xref: /illumos-gate/usr/src/lib/libidmap/common/idmap_api.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * libidmap API
29  */
30 
31 #include <stdlib.h>
32 #include <sys/varargs.h>
33 #include <inttypes.h>
34 #include <errno.h>
35 #include <strings.h>
36 #include <ctype.h>
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <dlfcn.h>
41 #include <libintl.h>
42 #include <ucontext.h>
43 #include "idmap_impl.h"
44 #include "idmap_cache.h"
45 
46 /*LINTLIBRARY*/
47 
48 /*
49  * The following structure determines where the log messages from idmapdlog()
50  * go to. It can be stderr (idmap, idmapd -d) and/or syslog (idmapd).
51  *
52  * logstate.max_pri is integer cutoff necessary to silence low-priority
53  * messages to stderr. Syslog has its own means so there a boolean
54  * logstate.write_syslog is enough.
55  *
56  * logstate.degraded is a mode used by idmapd in its degraded state.
57  */
58 
59 static struct {
60 	bool_t write_syslog;
61 	int max_pri; /* Max priority written to stderr */
62 	bool_t degraded;
63 } logstate = {FALSE, LOG_DEBUG, FALSE};
64 
65 
66 static struct timeval TIMEOUT = { 25, 0 };
67 
68 static int idmap_stat2errno(idmap_stat);
69 static idmap_stat	idmap_strdupnull(char **, const char *);
70 
71 #define	__ITER_CREATE(itera, argu, handl, ityp)\
72 	if (handl == NULL) {\
73 		errno = EINVAL;\
74 		return (IDMAP_ERR_ARG);\
75 	}\
76 	itera = calloc(1, sizeof (*itera));\
77 	if (itera == NULL) {\
78 		errno = ENOMEM;\
79 		return (IDMAP_ERR_MEMORY);\
80 	}\
81 	argu = calloc(1, sizeof (*argu));\
82 	if (argu == NULL) {\
83 		free(itera);\
84 		errno = ENOMEM;\
85 		return (IDMAP_ERR_MEMORY);\
86 	}\
87 	itera->ih = handl;\
88 	itera->type = ityp;\
89 	itera->retcode = IDMAP_NEXT;\
90 	itera->limit = 1024;\
91 	itera->arg = argu;
92 
93 
94 #define	__ITER_ERR_RETURN(itera, argu, xdr_argu, iretcod)\
95 	if (argu) {\
96 		xdr_free(xdr_argu, (caddr_t)argu);\
97 		free(argu);\
98 	}\
99 	if (itera)\
100 		free(itera);\
101 	return (iretcod);
102 
103 
104 #define	__ITER_CHECK(itera, ityp)\
105 	if (itera == NULL) {\
106 		errno = EINVAL;\
107 		return (IDMAP_ERR_ARG);\
108 	}\
109 	if (itera->type != ityp) {\
110 		errno = EINVAL;\
111 		return (IDMAP_ERR_ARG);\
112 	}
113 
114 /*
115  * Free memory allocated by libidmap API
116  *
117  * Input:
118  * ptr - memory to be freed
119  */
120 void
121 idmap_free(void *ptr)
122 {
123 	free(ptr);
124 }
125 
126 
127 #define	MIN_STACK_NEEDS	65536
128 
129 /*
130  * Create and Initialize idmap client handle for rpc/doors
131  *
132  * Output:
133  * handle - idmap handle
134  */
135 idmap_stat
136 idmap_init(idmap_handle_t **handle)
137 {
138 	CLIENT			*clnt = NULL;
139 	struct idmap_handle	*hptr;
140 	uint_t			sendsz = 0;
141 	stack_t			st;
142 
143 	*handle = NULL;
144 	hptr = (struct idmap_handle *)calloc(1, sizeof (*hptr));
145 	if (hptr == NULL)
146 		return (IDMAP_ERR_MEMORY);
147 
148 	/*
149 	 * clnt_door_call() alloca()s sendsz bytes (twice too, once for
150 	 * the call args buffer and once for the call result buffer), so
151 	 * we want to pick a sendsz that will be large enough, but not
152 	 * too large.
153 	 */
154 	if (stack_getbounds(&st) == 0) {
155 		/*
156 		 * Estimate how much stack space is left;
157 		 * st.ss_sp is the top of stack.
158 		 */
159 		if ((char *)&sendsz < (char *)st.ss_sp)
160 			/* stack grows up */
161 			sendsz = ((char *)st.ss_sp - (char *)&sendsz);
162 		else
163 			/* stack grows down */
164 			sendsz = ((char *)&sendsz - (char *)st.ss_sp);
165 
166 		if (sendsz <= MIN_STACK_NEEDS) {
167 			sendsz = 0;	/* RPC call may fail */
168 		} else {
169 			/* Leave 64Kb (just a guess) for our needs */
170 			sendsz -= MIN_STACK_NEEDS;
171 
172 			/* Divide the stack space left by two */
173 			sendsz = RNDUP(sendsz / 2);
174 
175 			/* Limit sendsz to 256KB */
176 			if (sendsz > IDMAP_MAX_DOOR_RPC)
177 				sendsz = IDMAP_MAX_DOOR_RPC;
178 		}
179 	}
180 
181 	clnt = clnt_door_create(IDMAP_PROG, IDMAP_V1, sendsz);
182 	if (clnt == NULL) {
183 		free(hptr);
184 		return (IDMAP_ERR_RPC);
185 	}
186 	hptr->type = _IDMAP_HANDLE_RPC_DOORS;
187 	hptr->privhandle = clnt;
188 	*handle = hptr;
189 	return (IDMAP_SUCCESS);
190 }
191 
192 
193 /*
194  * Finalize idmap handle
195  *
196  * Input:
197  * handle - idmap handle
198  */
199 idmap_stat
200 idmap_fini(idmap_handle_t *handle)
201 {
202 	CLIENT			*clnt;
203 	struct idmap_handle	*hptr;
204 
205 	if (handle == NULL)
206 		return (IDMAP_SUCCESS);
207 
208 	hptr = (struct idmap_handle *)handle;
209 
210 	switch (hptr->type) {
211 	case _IDMAP_HANDLE_RPC_DOORS:
212 		clnt = (CLIENT *)hptr->privhandle;
213 		if (clnt) {
214 			if (clnt->cl_auth)
215 				auth_destroy(clnt->cl_auth);
216 			clnt_destroy(clnt);
217 		}
218 		break;
219 	default:
220 		break;
221 	}
222 	free(hptr);
223 	return (IDMAP_SUCCESS);
224 }
225 
226 
227 idmap_stat
228 idmap_get_prop(idmap_handle_t *handle, idmap_prop_type pr, idmap_prop_res *res)
229 {
230 	CLIENT			*clnt;
231 	enum clnt_stat		clntstat;
232 
233 
234 	(void) memset(res, 0, sizeof (*res));
235 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
236 
237 	clntstat = clnt_call(clnt, IDMAP_GET_PROP,
238 	    (xdrproc_t)xdr_idmap_prop_type, (caddr_t)&pr,
239 	    (xdrproc_t)xdr_idmap_prop_res, (caddr_t)res, TIMEOUT);
240 
241 	if (clntstat != RPC_SUCCESS) {
242 		return (_idmap_rpc2stat(clnt));
243 	}
244 
245 	return (res->retcode); /* This might not be IDMAP_SUCCESS! */
246 
247 #if 0
248 	(void) memset(&res, 0, sizeof (res));
249 	pr = PROP_DOMAIN_CONTROLLER;
250 
251 	clntstat = clnt_call(clnt, IDMAP_GET_PROP,
252 	    (xdrproc_t)xdr_idmap_prop_type, (caddr_t)&pr,
253 	    (xdrproc_t)xdr_idmap_prop_res, (caddr_t)&res, TIMEOUT);
254 
255 	if (clntstat != RPC_SUCCESS) {
256 		fprintf(stderr, "clntstat != RPC_SUCCESS\n");
257 		rc = _idmap_rpc2stat(clnt);
258 		goto cleanup;
259 	}
260 #endif
261 
262 }
263 
264 idmap_stat
265 idmap_get_prop_ds(idmap_handle_t *handle, idmap_prop_type pr,
266     idmap_ad_disc_ds_t *dc)
267 {
268 	idmap_prop_res res;
269 	idmap_stat rc = IDMAP_SUCCESS;
270 
271 	rc = idmap_get_prop(handle, pr, &res);
272 	if (rc < 0)
273 		return (rc);
274 
275 	dc->port = res.value.idmap_prop_val_u.dsval.port;
276 	(void) strlcpy(dc->host, res.value.idmap_prop_val_u.dsval.host,
277 	    AD_DISC_MAXHOSTNAME);
278 
279 	/* xdr doesn't guarantee 0-termination of char[]: */
280 	dc->host[AD_DISC_MAXHOSTNAME - 1] = '\0';
281 
282 	return (rc);
283 }
284 
285 
286 /*
287  * Sometimes the property is not set. In that case, str is set to NULL but
288  * otherwise IDMAP_SUCCESS is returned.
289  */
290 idmap_stat
291 idmap_get_prop_str(idmap_handle_t *handle, idmap_prop_type pr, char **str)
292 {
293 	idmap_prop_res res;
294 	idmap_stat rc = IDMAP_SUCCESS;
295 
296 	rc = idmap_get_prop(handle, pr, &res);
297 	if (rc < 0)
298 		return (rc);
299 
300 	rc = idmap_strdupnull(str, res.value.idmap_prop_val_u.utf8val);
301 	return (rc);
302 }
303 
304 /*
305  * Create/Initialize handle for updates
306  *
307  * Output:
308  * udthandle - update handle
309  */
310 idmap_stat
311 idmap_udt_create(idmap_handle_t *handle, idmap_udt_handle_t **udthandle)
312 {
313 	idmap_udt_handle_t	*tmp;
314 
315 	if (handle == NULL || udthandle == NULL) {
316 		errno = EINVAL;
317 		return (IDMAP_ERR_ARG);
318 	}
319 	if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
320 		errno = ENOMEM;
321 		return (IDMAP_ERR_MEMORY);
322 	}
323 
324 	tmp->ih = handle;
325 	*udthandle = tmp;
326 	return (IDMAP_SUCCESS);
327 }
328 
329 
330 /*
331  * All the updates specified by the update handle are committed
332  * in a single transaction. i.e either all succeed or none.
333  *
334  * Input:
335  * udthandle - update handle with the update requests
336  *
337  * Return value:
338  * Status of the commit
339  */
340 idmap_stat
341 idmap_udt_commit(idmap_udt_handle_t *udthandle)
342 {
343 	CLIENT			*clnt;
344 	enum clnt_stat		clntstat;
345 	idmap_update_res	res;
346 	idmap_stat		retcode;
347 
348 	if (udthandle == NULL) {
349 		errno = EINVAL;
350 		return (IDMAP_ERR_ARG);
351 	}
352 
353 	(void) memset(&res, 0, sizeof (res));
354 
355 	_IDMAP_GET_CLIENT_HANDLE(udthandle->ih, clnt);
356 	clntstat = clnt_call(clnt, IDMAP_UPDATE,
357 	    (xdrproc_t)xdr_idmap_update_batch, (caddr_t)&udthandle->batch,
358 	    (xdrproc_t)xdr_idmap_update_res, (caddr_t)&res,
359 	    TIMEOUT);
360 
361 	if (clntstat != RPC_SUCCESS) {
362 		retcode = _idmap_rpc2stat(clnt);
363 		goto out;
364 	}
365 
366 	retcode = udthandle->commit_stat = res.retcode;
367 	udthandle->error_index = res.error_index;
368 
369 	if (retcode != IDMAP_SUCCESS) {
370 
371 		if (udthandle->error_index < 0)
372 			goto out;
373 
374 		retcode = idmap_namerule_cpy(&udthandle->error_rule,
375 		    &res.error_rule);
376 		if (retcode != IDMAP_SUCCESS) {
377 			udthandle->error_index = -2;
378 			goto out;
379 		}
380 
381 		retcode = idmap_namerule_cpy(&udthandle->conflict_rule,
382 		    &res.conflict_rule);
383 		if (retcode != IDMAP_SUCCESS) {
384 			udthandle->error_index = -2;
385 			goto out;
386 		}
387 	}
388 
389 	retcode = res.retcode;
390 
391 
392 out:
393 	/* reset handle so that it can be used again */
394 	if (retcode == IDMAP_SUCCESS) {
395 		_IDMAP_RESET_UDT_HANDLE(udthandle);
396 	}
397 
398 	(void) xdr_free(xdr_idmap_update_res, (caddr_t)&res);
399 	errno = idmap_stat2errno(retcode);
400 	return (retcode);
401 }
402 
403 
404 static void
405 idmap_namerule_parts_clear(char **windomain, char **winname,
406     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
407     boolean_t *is_nt4, int *direction)
408 {
409 	if (windomain)
410 		*windomain = NULL;
411 	if (winname)
412 		*winname = NULL;
413 	if (unixname)
414 		*unixname = NULL;
415 
416 	if (is_nt4)
417 		*is_nt4 = 0;
418 	if (is_user)
419 		*is_user = -1;
420 	if (is_wuser)
421 		*is_wuser = -1;
422 	if (direction)
423 		*direction = IDMAP_DIRECTION_UNDEF;
424 }
425 
426 static idmap_stat
427 idmap_namerule2parts(idmap_namerule *rule,
428     char **windomain, char **winname,
429     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
430     boolean_t *is_nt4, int *direction)
431 {
432 	idmap_stat retcode;
433 
434 	if (EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
435 		return (IDMAP_ERR_NORESULT);
436 
437 
438 	retcode = idmap_strdupnull(windomain, rule->windomain);
439 	if (retcode != IDMAP_SUCCESS)
440 		goto errout;
441 
442 	retcode = idmap_strdupnull(winname, rule->winname);
443 	if (retcode != IDMAP_SUCCESS)
444 		goto errout;
445 
446 	retcode = idmap_strdupnull(unixname, rule->unixname);
447 	if (retcode != IDMAP_SUCCESS)
448 		goto errout;
449 
450 
451 	if (is_user)
452 		*is_user = rule->is_user;
453 	if (is_wuser)
454 		*is_wuser = rule->is_wuser;
455 	if (is_nt4)
456 		*is_nt4 = rule->is_nt4;
457 	if (direction)
458 		*direction = rule->direction;
459 
460 
461 	return (IDMAP_SUCCESS);
462 
463 errout:
464 	if (windomain && *windomain)
465 		free(*windomain);
466 	if (winname && *winname)
467 		free(*winname);
468 	if (unixname && *unixname)
469 		free(*unixname);
470 
471 	idmap_namerule_parts_clear(windomain, winname,
472 	    unixname, is_user, is_wuser, is_nt4, direction);
473 
474 	return (retcode);
475 
476 }
477 
478 /*
479  * Retrieve the index of the failed batch element. error_index == -1
480  * indicates failure at the beginning, -2 at the end.
481  *
482  * If idmap_udt_commit didn't return error, the returned value is undefined.
483  *
484  * Return value:
485  * IDMAP_SUCCESS
486  */
487 
488 idmap_stat
489 idmap_udt_get_error_index(idmap_udt_handle_t *udthandle,
490     int64_t *error_index)
491 {
492 	if (error_index)
493 		*error_index = udthandle->error_index;
494 
495 	return (IDMAP_SUCCESS);
496 }
497 
498 
499 /*
500  * Retrieve the rule which caused the batch to fail. If
501  * idmap_udt_commit didn't return error or if error_index is < 0, the
502  * retrieved rule is undefined.
503  *
504  * Return value:
505  * IDMAP_ERR_NORESULT if there is no error rule.
506  * IDMAP_SUCCESS if the rule was obtained OK.
507  * other error code (IDMAP_ERR_NOMEMORY etc)
508  */
509 
510 idmap_stat
511 idmap_udt_get_error_rule(idmap_udt_handle_t *udthandle,
512     char **windomain, char **winname,
513     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
514     boolean_t *is_nt4, int *direction)
515 {
516 	idmap_namerule_parts_clear(windomain, winname,
517 	    unixname, is_user, is_wuser, is_nt4, direction);
518 
519 	if (udthandle->commit_stat == IDMAP_SUCCESS ||
520 	    udthandle->error_index < 0)
521 		return (IDMAP_ERR_NORESULT);
522 
523 	return (idmap_namerule2parts(
524 	    &udthandle->error_rule,
525 	    windomain,
526 	    winname,
527 	    unixname,
528 	    is_user,
529 	    is_wuser,
530 	    is_nt4,
531 	    direction));
532 }
533 
534 /*
535  * Retrieve the rule with which there was a conflict. TODO: retrieve
536  * the value.
537  *
538  * Return value:
539  * IDMAP_ERR_NORESULT if there is no error rule.
540  * IDMAP_SUCCESS if the rule was obtained OK.
541  * other error code (IDMAP_ERR_NOMEMORY etc)
542  */
543 
544 idmap_stat
545 idmap_udt_get_conflict_rule(idmap_udt_handle_t *udthandle,
546     char **windomain, char **winname,
547     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
548     boolean_t *is_nt4, int *direction)
549 {
550 	idmap_namerule_parts_clear(windomain, winname,
551 	    unixname, is_user, is_wuser, is_nt4, direction);
552 
553 	if (udthandle->commit_stat != IDMAP_ERR_W2U_NAMERULE_CONFLICT &&
554 	    udthandle->commit_stat != IDMAP_ERR_U2W_NAMERULE_CONFLICT) {
555 		return (IDMAP_ERR_NORESULT);
556 	}
557 
558 	return (idmap_namerule2parts(
559 	    &udthandle->conflict_rule,
560 	    windomain,
561 	    winname,
562 	    unixname,
563 	    is_user,
564 	    is_wuser,
565 	    is_nt4,
566 	    direction));
567 }
568 
569 
570 /*
571  * Destroy the update handle
572  */
573 void
574 idmap_udt_destroy(idmap_udt_handle_t *udthandle)
575 {
576 	if (udthandle == NULL)
577 		return;
578 	(void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
579 	(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->error_rule);
580 	(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->conflict_rule);
581 	free(udthandle);
582 }
583 
584 
585 idmap_stat
586 idmap_udt_add_namerule(idmap_udt_handle_t *udthandle, const char *windomain,
587     boolean_t is_user, boolean_t is_wuser, const char *winname,
588     const char *unixname, boolean_t is_nt4, int direction)
589 {
590 	idmap_retcode	retcode;
591 	idmap_namerule	*rule = NULL;
592 
593 	retcode = _udt_extend_batch(udthandle);
594 	if (retcode != IDMAP_SUCCESS)
595 		goto errout;
596 
597 	rule = &udthandle->batch.
598 	    idmap_update_batch_val[udthandle->next].
599 	    idmap_update_op_u.rule;
600 	rule->is_user = is_user;
601 	rule->is_wuser = is_wuser;
602 	rule->direction = direction;
603 	rule->is_nt4 = is_nt4;
604 
605 	retcode = idmap_strdupnull(&rule->windomain, windomain);
606 	if (retcode != IDMAP_SUCCESS)
607 		goto errout;
608 
609 	retcode = idmap_strdupnull(&rule->winname, winname);
610 	if (retcode != IDMAP_SUCCESS)
611 		goto errout;
612 
613 	retcode = idmap_strdupnull(&rule->unixname, unixname);
614 	if (retcode != IDMAP_SUCCESS)
615 		goto errout;
616 
617 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
618 	    OP_ADD_NAMERULE;
619 	udthandle->next++;
620 	return (IDMAP_SUCCESS);
621 
622 errout:
623 	/* The batch should still be usable */
624 	if (rule)
625 		(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
626 	errno = idmap_stat2errno(retcode);
627 	return (retcode);
628 }
629 
630 
631 /* ARGSUSED */
632 idmap_stat
633 idmap_udt_rm_namerule(idmap_udt_handle_t *udthandle, boolean_t is_user,
634     boolean_t is_wuser,	const char *windomain, const char *winname,
635     const char *unixname, int direction)
636 {
637 	idmap_retcode	retcode;
638 	idmap_namerule	*rule = NULL;
639 
640 	retcode = _udt_extend_batch(udthandle);
641 	if (retcode != IDMAP_SUCCESS)
642 		goto errout;
643 
644 	rule = &udthandle->batch.
645 	    idmap_update_batch_val[udthandle->next].
646 	    idmap_update_op_u.rule;
647 	rule->is_user = is_user;
648 	rule->is_wuser = is_wuser;
649 	rule->direction = direction;
650 
651 	retcode = idmap_strdupnull(&rule->windomain, windomain);
652 	if (retcode != IDMAP_SUCCESS)
653 		goto errout;
654 
655 	retcode = idmap_strdupnull(&rule->winname, winname);
656 	if (retcode != IDMAP_SUCCESS)
657 		goto errout;
658 
659 	retcode = idmap_strdupnull(&rule->unixname, unixname);
660 	if (retcode != IDMAP_SUCCESS)
661 		goto errout;
662 
663 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
664 	    OP_RM_NAMERULE;
665 	udthandle->next++;
666 	return (IDMAP_SUCCESS);
667 
668 errout:
669 	if (rule)
670 		(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
671 	errno = idmap_stat2errno(retcode);
672 	return (retcode);
673 }
674 
675 
676 /* ARGSUSED */
677 idmap_stat
678 idmap_udt_flush_namerules(idmap_udt_handle_t *udthandle)
679 {
680 	idmap_retcode	retcode;
681 
682 	retcode = _udt_extend_batch(udthandle);
683 	if (retcode != IDMAP_SUCCESS)
684 		goto errout;
685 
686 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
687 	    OP_FLUSH_NAMERULES;
688 	udthandle->next++;
689 	return (IDMAP_SUCCESS);
690 
691 errout:
692 	errno = idmap_stat2errno(retcode);
693 	return (retcode);
694 }
695 
696 
697 /*
698  * Set the number of entries requested per batch by the iterator
699  *
700  * Input:
701  * iter  - iterator
702  * limit - number of entries requested per batch
703  */
704 idmap_stat
705 idmap_iter_set_limit(idmap_iter_t *iter, uint64_t limit)
706 {
707 	if (iter == NULL) {
708 		errno = EINVAL;
709 		return (IDMAP_ERR_ARG);
710 	}
711 	iter->limit = limit;
712 	return (IDMAP_SUCCESS);
713 }
714 
715 
716 /*
717  * Create iterator to get name-based mapping rules
718  *
719  * Input:
720  * windomain - Windows domain
721  * is_user   - user or group rules
722  * winname   - Windows user or group name
723  * unixname  - Unix user or group name
724  *
725  * Output:
726  * iter - iterator
727  */
728 idmap_stat
729 idmap_iter_namerules(idmap_handle_t *handle, const char *windomain,
730 		boolean_t is_user, boolean_t is_wuser, const char *winname,
731 		const char *unixname, idmap_iter_t **iter)
732 {
733 
734 	idmap_iter_t			*tmpiter;
735 	idmap_list_namerules_1_argument	*arg = NULL;
736 	idmap_namerule			*rule;
737 	idmap_retcode			retcode;
738 
739 	__ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_NAMERULES);
740 
741 	rule = &arg->rule;
742 	rule->is_user = is_user;
743 	rule->is_wuser = is_wuser;
744 	rule->direction = IDMAP_DIRECTION_UNDEF;
745 
746 	retcode = idmap_strdupnull(&rule->windomain, windomain);
747 	if (retcode != IDMAP_SUCCESS)
748 		goto errout;
749 
750 	retcode = idmap_strdupnull(&rule->winname, winname);
751 	if (retcode != IDMAP_SUCCESS)
752 		goto errout;
753 
754 	retcode = idmap_strdupnull(&rule->unixname, unixname);
755 	if (retcode != IDMAP_SUCCESS)
756 		goto errout;
757 
758 	*iter = tmpiter;
759 	return (IDMAP_SUCCESS);
760 
761 errout:
762 	__ITER_ERR_RETURN(tmpiter, arg,
763 	    xdr_idmap_list_namerules_1_argument, retcode);
764 }
765 
766 
767 /*
768  * Iterate through the name-based mapping rules
769  *
770  * Input:
771  * iter - iterator
772  *
773  * Output:
774  * windomain - Windows domain
775  * winname   - Windows user or group name
776  * unixname  - Unix user or group name
777  * is_nt4    - NT4 or AD
778  * direction - bi(0), win2unix(1), unix2win(2)
779  *
780  * Return value:
781  * 0   - done
782  * 1   - more results available
783  * < 0 - error
784  */
785 idmap_stat
786 idmap_iter_next_namerule(idmap_iter_t *iter, char **windomain,
787     char **winname, char **unixname,  boolean_t *is_user,
788     boolean_t *is_wuser, boolean_t *is_nt4, int *direction)
789 {
790 	idmap_namerules_res		*namerules;
791 	idmap_list_namerules_1_argument	*arg;
792 	idmap_retcode			retcode;
793 
794 	idmap_namerule_parts_clear(windomain, winname,
795 	    unixname, is_user, is_wuser, is_nt4, direction);
796 
797 
798 	__ITER_CHECK(iter, IDMAP_LIST_NAMERULES);
799 
800 	namerules = (idmap_namerules_res *)iter->retlist;
801 	if (iter->retcode == IDMAP_NEXT && (namerules == NULL ||
802 	    iter->next >= namerules->rules.rules_len)) {
803 
804 		if ((arg = iter->arg) == NULL) {
805 			errno = EINVAL;
806 			return (IDMAP_ERR_ARG);
807 		}
808 		arg->limit = iter->limit;
809 
810 		retcode = _iter_get_next_list(IDMAP_LIST_NAMERULES,
811 		    iter, arg,
812 		    (uchar_t **)&namerules, sizeof (*namerules),
813 		    (xdrproc_t)xdr_idmap_list_namerules_1_argument,
814 		    (xdrproc_t)xdr_idmap_namerules_res);
815 		if (retcode != IDMAP_SUCCESS)
816 			return (retcode);
817 
818 		if (IDMAP_ERROR(namerules->retcode)) {
819 			retcode  = namerules->retcode;
820 			xdr_free(xdr_idmap_namerules_res, (caddr_t)namerules);
821 			free(namerules);
822 			iter->retlist = NULL;
823 			return (retcode);
824 		}
825 		iter->retcode = namerules->retcode;
826 		arg->lastrowid = namerules->lastrowid;
827 	}
828 
829 	if (namerules == NULL || namerules->rules.rules_len == 0)
830 		return (IDMAP_SUCCESS);
831 
832 	if (iter->next >= namerules->rules.rules_len) {
833 		return (IDMAP_ERR_ARG);
834 	}
835 
836 	retcode = idmap_strdupnull(windomain,
837 	    namerules->rules.rules_val[iter->next].windomain);
838 	if (retcode != IDMAP_SUCCESS)
839 		goto errout;
840 
841 	retcode = idmap_strdupnull(winname,
842 	    namerules->rules.rules_val[iter->next].winname);
843 	if (retcode != IDMAP_SUCCESS)
844 		goto errout;
845 
846 	retcode = idmap_strdupnull(unixname,
847 	    namerules->rules.rules_val[iter->next].unixname);
848 	if (retcode != IDMAP_SUCCESS)
849 		goto errout;
850 
851 	if (is_nt4)
852 		*is_nt4 = namerules->rules.rules_val[iter->next].is_nt4;
853 	if (is_user)
854 		*is_user = namerules->rules.rules_val[iter->next].is_user;
855 	if (is_wuser)
856 		*is_wuser = namerules->rules.rules_val[iter->next].is_wuser;
857 	if (direction)
858 		*direction = namerules->rules.rules_val[iter->next].direction;
859 	iter->next++;
860 
861 	if (iter->next == namerules->rules.rules_len)
862 		return (iter->retcode);
863 	else
864 		return (IDMAP_NEXT);
865 
866 errout:
867 	if (windomain && *windomain)
868 		free(*windomain);
869 	if (winname && *winname)
870 		free(*winname);
871 	if (unixname && *unixname)
872 		free(*unixname);
873 	return (retcode);
874 }
875 
876 
877 /*
878  * Create iterator to get SID to UID/GID mappings
879  *
880  * Output:
881  * iter - iterator
882  */
883 idmap_stat
884 idmap_iter_mappings(idmap_handle_t *handle, idmap_iter_t **iter, int flag)
885 {
886 	idmap_iter_t			*tmpiter;
887 	idmap_list_mappings_1_argument	*arg = NULL;
888 
889 	__ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_MAPPINGS);
890 
891 	arg->flag = flag;
892 	*iter = tmpiter;
893 	return (IDMAP_SUCCESS);
894 }
895 
896 
897 /*
898  * Iterate through the SID to UID/GID mappings
899  *
900  * Input:
901  * iter - iterator
902  *
903  * Output:
904  * sid - SID in canonical form
905  * pid - UID or GID
906  *
907  * Return value:
908  * 0   - done
909  * 1   - more results available
910  * < 0 - error
911  */
912 idmap_stat
913 idmap_iter_next_mapping(idmap_iter_t *iter, char **sidprefix,
914     idmap_rid_t *rid, uid_t *pid, char **winname,
915     char **windomain, char **unixname, boolean_t *is_user,
916     boolean_t *is_wuser, int *direction, idmap_info *info)
917 {
918 	idmap_mappings_res		*mappings;
919 	idmap_list_mappings_1_argument	*arg;
920 	idmap_retcode			retcode;
921 	char				*str;
922 
923 	if (sidprefix)
924 		*sidprefix = NULL;
925 	if (rid)
926 		*rid = UINT32_MAX;
927 	if (winname)
928 		*winname = NULL;
929 	if (windomain)
930 		*windomain = NULL;
931 	if (unixname)
932 		*unixname = NULL;
933 	if (pid)
934 		*pid = UINT32_MAX;
935 	if (is_user)
936 		*is_user = -1;
937 	if (is_wuser)
938 		*is_wuser = -1;
939 	if (direction)
940 		*direction = IDMAP_DIRECTION_UNDEF;
941 
942 	__ITER_CHECK(iter, IDMAP_LIST_MAPPINGS);
943 
944 	mappings = (idmap_mappings_res *)iter->retlist;
945 	if (iter->retcode == IDMAP_NEXT && (mappings == NULL ||
946 	    iter->next >= mappings->mappings.mappings_len)) {
947 
948 		if ((arg = iter->arg) == NULL) {
949 			errno = EINVAL;
950 			return (IDMAP_ERR_ARG);
951 		}
952 		arg->limit = iter->limit;
953 
954 		retcode = _iter_get_next_list(IDMAP_LIST_MAPPINGS,
955 		    iter, arg,
956 		    (uchar_t **)&mappings, sizeof (*mappings),
957 		    (xdrproc_t)xdr_idmap_list_mappings_1_argument,
958 		    (xdrproc_t)xdr_idmap_mappings_res);
959 		if (retcode != IDMAP_SUCCESS)
960 			return (retcode);
961 
962 		if (IDMAP_ERROR(mappings->retcode)) {
963 			retcode  = mappings->retcode;
964 			xdr_free(xdr_idmap_mappings_res, (caddr_t)mappings);
965 			free(mappings);
966 			iter->retlist = NULL;
967 			return (retcode);
968 		}
969 		iter->retcode = mappings->retcode;
970 		arg->lastrowid = mappings->lastrowid;
971 	}
972 
973 	if (mappings == NULL || mappings->mappings.mappings_len == 0)
974 		return (IDMAP_SUCCESS);
975 
976 	if (iter->next >= mappings->mappings.mappings_len) {
977 		return (IDMAP_ERR_ARG);
978 	}
979 
980 	if (sidprefix) {
981 		str = mappings->mappings.mappings_val[iter->next].id1.
982 		    idmap_id_u.sid.prefix;
983 		if (str && *str != '\0') {
984 			*sidprefix = strdup(str);
985 			if (*sidprefix == NULL) {
986 				retcode = IDMAP_ERR_MEMORY;
987 				goto errout;
988 			}
989 		}
990 	}
991 	if (rid)
992 		*rid = mappings->mappings.mappings_val[iter->next].id1.
993 		    idmap_id_u.sid.rid;
994 
995 	retcode = idmap_strdupnull(windomain,
996 	    mappings->mappings.mappings_val[iter->next].id1domain);
997 	if (retcode != IDMAP_SUCCESS)
998 		goto errout;
999 
1000 	retcode = idmap_strdupnull(winname,
1001 	    mappings->mappings.mappings_val[iter->next].id1name);
1002 	if (retcode != IDMAP_SUCCESS)
1003 		goto errout;
1004 
1005 	retcode = idmap_strdupnull(unixname,
1006 	    mappings->mappings.mappings_val[iter->next].id2name);
1007 	if (retcode != IDMAP_SUCCESS)
1008 		goto errout;
1009 
1010 
1011 	if (pid)
1012 		*pid = mappings->mappings.mappings_val[iter->next].id2.
1013 		    idmap_id_u.uid;
1014 	if (direction)
1015 		*direction = mappings->mappings.mappings_val[iter->next].
1016 		    direction;
1017 	if (is_user)
1018 		*is_user = (mappings->mappings.mappings_val[iter->next].id2
1019 		    .idtype == IDMAP_UID)?1:0;
1020 	if (is_wuser)
1021 		*is_wuser = (mappings->mappings.mappings_val[iter->next].id1
1022 		    .idtype == IDMAP_USID)?1:0;
1023 
1024 	if (info) {
1025 		retcode = idmap_info_cpy(info,
1026 		    &mappings->mappings.mappings_val[iter->next].info);
1027 		if (retcode != IDMAP_SUCCESS)
1028 			goto errout;
1029 	}
1030 	iter->next++;
1031 
1032 	if (iter->next == mappings->mappings.mappings_len)
1033 		return (iter->retcode);
1034 	else
1035 		return (IDMAP_NEXT);
1036 
1037 errout:
1038 	if (sidprefix && *sidprefix)
1039 		free(*sidprefix);
1040 	if (winname && *winname)
1041 		free(*winname);
1042 	if (windomain && *windomain)
1043 		free(*windomain);
1044 	if (unixname && *unixname)
1045 		free(*unixname);
1046 	return (retcode);
1047 }
1048 
1049 
1050 /*
1051  * Destroy the iterator
1052  */
1053 void
1054 idmap_iter_destroy(idmap_iter_t *iter)
1055 {
1056 	xdrproc_t _xdr_argument, _xdr_result;
1057 
1058 	if (iter == NULL)
1059 		return;
1060 
1061 	switch (iter->type) {
1062 	case IDMAP_LIST_NAMERULES:
1063 		_xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
1064 		_xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
1065 		break;
1066 	case IDMAP_LIST_MAPPINGS:
1067 		_xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
1068 		_xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
1069 		break;
1070 	default:
1071 		free(iter);
1072 		return;
1073 	};
1074 
1075 	if (iter->arg) {
1076 		xdr_free(_xdr_argument, (caddr_t)iter->arg);
1077 		free(iter->arg);
1078 	}
1079 	if (iter->retlist) {
1080 		xdr_free(_xdr_result, (caddr_t)iter->retlist);
1081 		free(iter->retlist);
1082 	}
1083 	free(iter);
1084 }
1085 
1086 
1087 /*
1088  * Create handle to get SID to UID/GID mapping entries
1089  *
1090  * Input:
1091  * gh - "get mapping" handle
1092  */
1093 idmap_stat
1094 idmap_get_create(idmap_handle_t *handle, idmap_get_handle_t **gh)
1095 {
1096 	idmap_get_handle_t	*tmp;
1097 
1098 	/* sanity checks */
1099 	if (handle == NULL || gh == NULL) {
1100 		errno = EINVAL;
1101 		return (IDMAP_ERR_ARG);
1102 	}
1103 
1104 	/* allocate the handle */
1105 	if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
1106 		errno = ENOMEM;
1107 		return (IDMAP_ERR_MEMORY);
1108 	}
1109 
1110 	tmp->ih = handle;
1111 	*gh = tmp;
1112 	return (IDMAP_SUCCESS);
1113 }
1114 
1115 
1116 /*
1117  * Given SID, get UID
1118  *
1119  * Input:
1120  * sidprefix  - SID prefix
1121  * rid        - RID
1122  * flag       - flag
1123  *
1124  * Output:
1125  * stat - status of the get request
1126  * uid  - POSIX UID if stat = 0
1127  *
1128  * Note: The output parameters will be set by idmap_get_mappings()
1129  */
1130 idmap_stat
1131 idmap_get_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1132 		int flag, uid_t *uid, idmap_stat *stat)
1133 {
1134 	return (idmap_getext_uidbysid(gh, sidprefix, rid, flag, uid,
1135 	    NULL, stat));
1136 }
1137 
1138 /*
1139  * Given SID, get UID
1140  *
1141  * Input:
1142  * sidprefix  - SID prefix
1143  * rid        - RID
1144  * flag       - flag
1145  *
1146  * Output:
1147  * stat - status of the get request
1148  * uid  - POSIX UID if stat = 0
1149  * how  - mapping type if stat = 0
1150  *
1151  * Note: The output parameters will be set by idmap_get_mappings()
1152  */
1153 
1154 idmap_stat
1155 idmap_getext_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1156 		int flag, uid_t *uid, idmap_info *info, idmap_stat *stat)
1157 {
1158 	idmap_retcode	retcode;
1159 	idmap_mapping	*mapping = NULL;
1160 
1161 	/* sanity checks */
1162 	if (gh == NULL)
1163 		return (IDMAP_ERR_ARG);
1164 	if (uid == NULL || sidprefix == NULL)
1165 		return (IDMAP_ERR_ARG);
1166 
1167 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1168 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1169 		retcode = idmap_cache_lookup_uidbysid(sidprefix, rid, uid);
1170 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1171 			*stat = retcode;
1172 			return (retcode);
1173 		}
1174 	}
1175 
1176 	/* Extend the request array and the return list */
1177 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1178 		goto errout;
1179 
1180 	/* Setup the request */
1181 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1182 	mapping->flag = flag;
1183 	mapping->id1.idtype = IDMAP_SID;
1184 	mapping->id1.idmap_id_u.sid.rid = rid;
1185 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1186 		retcode = IDMAP_ERR_MEMORY;
1187 		goto errout;
1188 	}
1189 	mapping->id2.idtype = IDMAP_UID;
1190 
1191 	/* Setup pointers for the result */
1192 	gh->retlist[gh->next].idtype = IDMAP_UID;
1193 	gh->retlist[gh->next].uid = uid;
1194 	gh->retlist[gh->next].stat = stat;
1195 	gh->retlist[gh->next].info = info;
1196 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1197 
1198 	gh->next++;
1199 	return (IDMAP_SUCCESS);
1200 
1201 errout:
1202 	/* Batch created so far should still be usable */
1203 	if (mapping)
1204 		(void) memset(mapping, 0, sizeof (*mapping));
1205 	errno = idmap_stat2errno(retcode);
1206 	return (retcode);
1207 }
1208 
1209 
1210 /*
1211  * Given SID, get GID
1212  *
1213  * Input:
1214  * sidprefix  - SID prefix
1215  * rid        - rid
1216  * flag       - flag
1217  *
1218  * Output:
1219  * stat - status of the get request
1220  * gid  - POSIX GID if stat = 0
1221  *
1222  * Note: The output parameters will be set by idmap_get_mappings()
1223  */
1224 idmap_stat
1225 idmap_get_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1226 		int flag, gid_t *gid, idmap_stat *stat)
1227 {
1228 	return (idmap_getext_gidbysid(gh, sidprefix, rid, flag, gid,
1229 	    NULL, stat));
1230 }
1231 
1232 
1233 /*
1234  * Given SID, get GID
1235  *
1236  * Input:
1237  * sidprefix  - SID prefix
1238  * rid        - rid
1239  * flag       - flag
1240  *
1241  * Output:
1242  * stat - status of the get request
1243  * gid  - POSIX GID if stat = 0
1244  * how  - mapping type if stat = 0
1245  *
1246  * Note: The output parameters will be set by idmap_get_mappings()
1247  */
1248 idmap_stat
1249 idmap_getext_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1250 		int flag, gid_t *gid, idmap_info *info, idmap_stat *stat)
1251 {
1252 
1253 	idmap_retcode	retcode;
1254 	idmap_mapping	*mapping = NULL;
1255 
1256 	/* sanity checks */
1257 	if (gh == NULL)
1258 		return (IDMAP_ERR_ARG);
1259 	if (gid == NULL || sidprefix == NULL)
1260 		return (IDMAP_ERR_ARG);
1261 
1262 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1263 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1264 		retcode = idmap_cache_lookup_gidbysid(sidprefix, rid, gid);
1265 		if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1266 			*stat = retcode;
1267 			return (retcode);
1268 		}
1269 	}
1270 
1271 	/* Extend the request array and the return list */
1272 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1273 		goto errout;
1274 
1275 	/* Setup the request */
1276 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1277 	mapping->flag = flag;
1278 	mapping->id1.idtype = IDMAP_SID;
1279 	mapping->id1.idmap_id_u.sid.rid = rid;
1280 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1281 		retcode = IDMAP_ERR_MEMORY;
1282 		goto errout;
1283 	}
1284 	mapping->id2.idtype = IDMAP_GID;
1285 
1286 	/* Setup pointers for the result */
1287 	gh->retlist[gh->next].idtype = IDMAP_GID;
1288 	gh->retlist[gh->next].gid = gid;
1289 	gh->retlist[gh->next].stat = stat;
1290 	gh->retlist[gh->next].info = info;
1291 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1292 
1293 	gh->next++;
1294 	return (IDMAP_SUCCESS);
1295 
1296 errout:
1297 	if (mapping)
1298 		(void) memset(mapping, 0, sizeof (*mapping));
1299 	errno = idmap_stat2errno(retcode);
1300 	return (retcode);
1301 }
1302 
1303 
1304 
1305 /*
1306  * Given SID, get POSIX ID i.e. UID/GID
1307  *
1308  * Input:
1309  * sidprefix  - SID prefix
1310  * rid        - rid
1311  * flag       - flag
1312  *
1313  * Output:
1314  * stat    - status of the get request
1315  * is_user - user or group
1316  * pid     - POSIX UID if stat = 0 and is_user = 1
1317  *           POSIX GID if stat = 0 and is_user = 0
1318  *
1319  * Note: The output parameters will be set by idmap_get_mappings()
1320  */
1321 idmap_stat
1322 idmap_get_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1323 		int flag, uid_t *pid, int *is_user, idmap_stat *stat)
1324 {
1325 	return (idmap_getext_pidbysid(gh, sidprefix, rid, flag, pid, is_user,
1326 	    NULL, stat));
1327 }
1328 
1329 
1330 
1331 /*
1332  * Given SID, get POSIX ID i.e. UID/GID
1333  *
1334  * Input:
1335  * sidprefix  - SID prefix
1336  * rid        - rid
1337  * flag       - flag
1338  *
1339  * Output:
1340  * stat    - status of the get request
1341  * is_user - user or group
1342  * pid     - POSIX UID if stat = 0 and is_user = 1
1343  *           POSIX GID if stat = 0 and is_user = 0
1344  * how     - mapping type if stat = 0
1345  *
1346  * Note: The output parameters will be set by idmap_get_mappings()
1347  */
1348 idmap_stat
1349 idmap_getext_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1350 	int flag, uid_t *pid, int *is_user, idmap_info *info, idmap_stat *stat)
1351 {
1352 	idmap_retcode	retcode;
1353 	idmap_mapping	*mapping = NULL;
1354 
1355 	/* sanity checks */
1356 	if (gh == NULL)
1357 		return (IDMAP_ERR_ARG);
1358 	if (pid == NULL || sidprefix == NULL || is_user == NULL)
1359 		return (IDMAP_ERR_ARG);
1360 
1361 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1362 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1363 		retcode = idmap_cache_lookup_pidbysid(sidprefix, rid, pid,
1364 		    is_user);
1365 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1366 			*stat = retcode;
1367 			return (retcode);
1368 		}
1369 	}
1370 
1371 	/* Extend the request array and the return list */
1372 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1373 		goto errout;
1374 
1375 	/* Setup the request */
1376 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1377 	mapping->flag = flag;
1378 	mapping->id1.idtype = IDMAP_SID;
1379 	mapping->id1.idmap_id_u.sid.rid = rid;
1380 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1381 		retcode = IDMAP_ERR_MEMORY;
1382 		goto errout;
1383 	}
1384 	mapping->id2.idtype = IDMAP_POSIXID;
1385 
1386 	/* Setup pointers for the result */
1387 	gh->retlist[gh->next].idtype = IDMAP_POSIXID;
1388 	gh->retlist[gh->next].uid = pid;
1389 	gh->retlist[gh->next].gid = pid;
1390 	gh->retlist[gh->next].is_user = is_user;
1391 	gh->retlist[gh->next].stat = stat;
1392 	gh->retlist[gh->next].info = info;
1393 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1394 
1395 	gh->next++;
1396 	return (IDMAP_SUCCESS);
1397 
1398 errout:
1399 	if (mapping)
1400 		(void) memset(mapping, 0, sizeof (*mapping));
1401 	errno = idmap_stat2errno(retcode);
1402 	return (retcode);
1403 }
1404 
1405 
1406 /*
1407  * Given UID, get SID
1408  *
1409  * Input:
1410  * uid  - POSIX UID
1411  * flag - flag
1412  *
1413  * Output:
1414  * stat - status of the get request
1415  * sid  - SID prefix (if stat == 0)
1416  * rid  - rid
1417  *
1418  * Note: The output parameters will be set by idmap_get_mappings()
1419  */
1420 idmap_stat
1421 idmap_get_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
1422 		char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
1423 {
1424 	return (idmap_getext_sidbyuid(gh, uid, flag, sidprefix, rid,
1425 	    NULL, stat));
1426 }
1427 
1428 
1429 /*
1430  * Given UID, get SID
1431  *
1432  * Input:
1433  * uid  - POSIX UID
1434  * flag - flag
1435  *
1436  * Output:
1437  * stat - status of the get request
1438  * sid  - SID prefix (if stat == 0)
1439  * rid  - rid
1440  * how  - mapping type if stat = 0
1441  *
1442  * Note: The output parameters will be set by idmap_get_mappings()
1443  */
1444 idmap_stat
1445 idmap_getext_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
1446 	char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
1447 {
1448 
1449 	idmap_retcode	retcode;
1450 	idmap_mapping	*mapping = NULL;
1451 
1452 	/* sanity checks */
1453 	if (gh == NULL)
1454 		return (IDMAP_ERR_ARG);
1455 	if (sidprefix == NULL)
1456 		return (IDMAP_ERR_ARG);
1457 
1458 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1459 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1460 		retcode = idmap_cache_lookup_sidbyuid(sidprefix, rid, uid);
1461 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1462 			*stat = retcode;
1463 			return (retcode);
1464 		}
1465 	}
1466 
1467 	/* Extend the request array and the return list */
1468 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1469 		goto errout;
1470 
1471 	/* Setup the request */
1472 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1473 	mapping->flag = flag;
1474 	mapping->id1.idtype = IDMAP_UID;
1475 	mapping->id1.idmap_id_u.uid = uid;
1476 	mapping->id2.idtype = IDMAP_SID;
1477 
1478 	/* Setup pointers for the result */
1479 	gh->retlist[gh->next].idtype = IDMAP_SID;
1480 	gh->retlist[gh->next].sidprefix = sidprefix;
1481 	gh->retlist[gh->next].rid = rid;
1482 	gh->retlist[gh->next].stat = stat;
1483 	gh->retlist[gh->next].info = info;
1484 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1485 
1486 	gh->next++;
1487 	return (IDMAP_SUCCESS);
1488 
1489 errout:
1490 	if (mapping)
1491 		(void) memset(mapping, 0, sizeof (*mapping));
1492 	errno = idmap_stat2errno(retcode);
1493 	return (retcode);
1494 }
1495 
1496 
1497 /*
1498  * Given GID, get SID
1499  *
1500  * Input:
1501  * gid  - POSIX GID
1502  * flag - flag
1503  *
1504  * Output:
1505  * stat       - status of the get request
1506  * sidprefix  - SID prefix (if stat == 0)
1507  * rid        - rid
1508  *
1509  * Note: The output parameters will be set by idmap_get_mappings()
1510  */
1511 idmap_stat
1512 idmap_get_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
1513 		char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
1514 {
1515 	return (idmap_getext_sidbygid(gh, gid, flag, sidprefix, rid,
1516 	    NULL, stat));
1517 }
1518 
1519 
1520 /*
1521  * Given GID, get SID
1522  *
1523  * Input:
1524  * gid  - POSIX GID
1525  * flag - flag
1526  *
1527  * Output:
1528  * stat       - status of the get request
1529  * sidprefix  - SID prefix (if stat == 0)
1530  * rid        - rid
1531  * how        - mapping type if stat = 0
1532  *
1533  * Note: The output parameters will be set by idmap_get_mappings()
1534  */
1535 idmap_stat
1536 idmap_getext_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
1537 	char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
1538 {
1539 
1540 	idmap_retcode	retcode;
1541 	idmap_mapping	*mapping = NULL;
1542 
1543 	/* sanity checks */
1544 	if (gh == NULL)
1545 		return (IDMAP_ERR_ARG);
1546 	if (sidprefix == NULL)
1547 		return (IDMAP_ERR_ARG);
1548 
1549 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1550 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1551 		retcode = idmap_cache_lookup_sidbygid(sidprefix, rid, gid);
1552 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1553 			*stat = retcode;
1554 			return (retcode);
1555 		}
1556 	}
1557 
1558 	/* Extend the request array and the return list */
1559 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1560 		goto errout;
1561 
1562 	/* Setup the request */
1563 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1564 	mapping->flag = flag;
1565 	mapping->id1.idtype = IDMAP_GID;
1566 	mapping->id1.idmap_id_u.gid = gid;
1567 	mapping->id2.idtype = IDMAP_SID;
1568 
1569 	/* Setup pointers for the result */
1570 	gh->retlist[gh->next].idtype = IDMAP_SID;
1571 	gh->retlist[gh->next].sidprefix = sidprefix;
1572 	gh->retlist[gh->next].rid = rid;
1573 	gh->retlist[gh->next].stat = stat;
1574 	gh->retlist[gh->next].info = info;
1575 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1576 
1577 	gh->next++;
1578 	return (IDMAP_SUCCESS);
1579 
1580 errout:
1581 	if (mapping)
1582 		(void) memset(mapping, 0, sizeof (*mapping));
1583 	errno = idmap_stat2errno(retcode);
1584 	return (retcode);
1585 }
1586 
1587 
1588 /*
1589  * Process the batched "get mapping" requests. The results (i.e.
1590  * status and identity) will be available in the data areas
1591  * provided by individual requests.
1592  */
1593 idmap_stat
1594 idmap_get_mappings(idmap_get_handle_t *gh)
1595 {
1596 	CLIENT		*clnt;
1597 	enum clnt_stat	clntstat;
1598 	idmap_retcode	retcode;
1599 	idmap_ids_res	res;
1600 	idmap_id	*res_id;
1601 	int		i;
1602 	idmap_id	*req_id;
1603 	int		direction;
1604 
1605 	if (gh == NULL) {
1606 		errno = EINVAL;
1607 		return (IDMAP_ERR_ARG);
1608 	}
1609 	_IDMAP_GET_CLIENT_HANDLE(gh->ih, clnt);
1610 
1611 	(void) memset(&res, 0, sizeof (idmap_ids_res));
1612 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_IDS,
1613 	    (xdrproc_t)xdr_idmap_mapping_batch,
1614 	    (caddr_t)&gh->batch,
1615 	    (xdrproc_t)xdr_idmap_ids_res,
1616 	    (caddr_t)&res,
1617 	    TIMEOUT);
1618 	if (clntstat != RPC_SUCCESS) {
1619 		retcode = _idmap_rpc2stat(clnt);
1620 		goto out;
1621 	}
1622 	if (res.retcode != IDMAP_SUCCESS) {
1623 		retcode = res.retcode;
1624 		goto out;
1625 	}
1626 	for (i = 0; i < gh->next; i++) {
1627 		if (i >= res.ids.ids_len) {
1628 			*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1629 			continue;
1630 		}
1631 		*gh->retlist[i].stat = res.ids.ids_val[i].retcode;
1632 		res_id = &res.ids.ids_val[i].id;
1633 		direction = res.ids.ids_val[i].direction;
1634 		req_id = &gh->batch.idmap_mapping_batch_val[i].id1;
1635 		switch (res_id->idtype) {
1636 		case IDMAP_UID:
1637 			if (gh->retlist[i].uid)
1638 				*gh->retlist[i].uid = res_id->idmap_id_u.uid;
1639 			if (gh->retlist[i].is_user)
1640 				*gh->retlist[i].is_user = 1;
1641 
1642 			if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1643 			    gh->retlist[i].cache_res) {
1644 				if (gh->retlist[i].is_user != NULL)
1645 					idmap_cache_add_sid2pid(
1646 					    req_id->idmap_id_u.sid.prefix,
1647 					    req_id->idmap_id_u.sid.rid,
1648 					    res_id->idmap_id_u.uid, 1,
1649 					    direction);
1650 				else
1651 					idmap_cache_add_sid2uid(
1652 					    req_id->idmap_id_u.sid.prefix,
1653 					    req_id->idmap_id_u.sid.rid,
1654 					    res_id->idmap_id_u.uid,
1655 					    direction);
1656 			}
1657 			break;
1658 
1659 		case IDMAP_GID:
1660 			if (gh->retlist[i].gid)
1661 				*gh->retlist[i].gid = res_id->idmap_id_u.gid;
1662 			if (gh->retlist[i].is_user)
1663 				*gh->retlist[i].is_user = 0;
1664 
1665 			if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1666 			    gh->retlist[i].cache_res) {
1667 				if (gh->retlist[i].is_user != NULL)
1668 					idmap_cache_add_sid2pid(
1669 					    req_id->idmap_id_u.sid.prefix,
1670 					    req_id->idmap_id_u.sid.rid,
1671 					    res_id->idmap_id_u.gid, 0,
1672 					    direction);
1673 				else
1674 					idmap_cache_add_sid2gid(
1675 					    req_id->idmap_id_u.sid.prefix,
1676 					    req_id->idmap_id_u.sid.rid,
1677 					    res_id->idmap_id_u.gid,
1678 					    direction);
1679 			}
1680 			break;
1681 
1682 		case IDMAP_POSIXID:
1683 			if (gh->retlist[i].uid)
1684 				*gh->retlist[i].uid = 60001;
1685 			if (gh->retlist[i].is_user)
1686 				*gh->retlist[i].is_user = -1;
1687 			break;
1688 
1689 		case IDMAP_SID:
1690 		case IDMAP_USID:
1691 		case IDMAP_GSID:
1692 			if (gh->retlist[i].rid)
1693 				*gh->retlist[i].rid =
1694 				    res_id->idmap_id_u.sid.rid;
1695 			if (gh->retlist[i].sidprefix) {
1696 				if (res_id->idmap_id_u.sid.prefix == NULL ||
1697 				    *res_id->idmap_id_u.sid.prefix == '\0') {
1698 					*gh->retlist[i].sidprefix = NULL;
1699 					break;
1700 				}
1701 				*gh->retlist[i].sidprefix =
1702 				    strdup(res_id->idmap_id_u.sid.prefix);
1703 				if (*gh->retlist[i].sidprefix == NULL)
1704 					*gh->retlist[i].stat =
1705 					    IDMAP_ERR_MEMORY;
1706 			}
1707 			if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1708 			    gh->retlist[i].cache_res) {
1709 				if (req_id->idtype == IDMAP_UID)
1710 					idmap_cache_add_sid2uid(
1711 					    res_id->idmap_id_u.sid.prefix,
1712 					    res_id->idmap_id_u.sid.rid,
1713 					    req_id->idmap_id_u.uid,
1714 					    direction);
1715 				else /* req_id->idtype == IDMAP_GID */
1716 					idmap_cache_add_sid2gid(
1717 					    res_id->idmap_id_u.sid.prefix,
1718 					    res_id->idmap_id_u.sid.rid,
1719 					    req_id->idmap_id_u.gid,
1720 					    direction);
1721 			}
1722 			break;
1723 
1724 		case IDMAP_NONE:
1725 			break;
1726 
1727 		default:
1728 			*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1729 			break;
1730 		}
1731 		if (gh->retlist[i].info != NULL)
1732 			(void) idmap_info_cpy(gh->retlist[i].info,
1733 			    &res.ids.ids_val[i].info);
1734 	}
1735 	retcode = IDMAP_SUCCESS;
1736 
1737 out:
1738 	_IDMAP_RESET_GET_HANDLE(gh);
1739 	(void) xdr_free(xdr_idmap_ids_res, (caddr_t)&res);
1740 	errno = idmap_stat2errno(retcode);
1741 	return (retcode);
1742 }
1743 
1744 
1745 /*
1746  * Destroy the "get mapping" handle
1747  */
1748 void
1749 idmap_get_destroy(idmap_get_handle_t *gh)
1750 {
1751 	if (gh == NULL)
1752 		return;
1753 	(void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
1754 	if (gh->retlist)
1755 		free(gh->retlist);
1756 	free(gh);
1757 }
1758 
1759 
1760 /*
1761  * Get windows to unix mapping
1762  */
1763 idmap_stat
1764 idmap_get_w2u_mapping(idmap_handle_t *handle,
1765 		const char *sidprefix, idmap_rid_t *rid,
1766 		const char *winname, const char *windomain,
1767 		int flag, int *is_user, int *is_wuser,
1768 		uid_t *pid, char **unixname, int *direction, idmap_info *info)
1769 {
1770 	CLIENT			*clnt;
1771 	enum clnt_stat		clntstat;
1772 	idmap_mapping		request, *mapping;
1773 	idmap_mappings_res	result;
1774 	idmap_retcode		retcode, rc;
1775 
1776 	if (handle == NULL) {
1777 		errno = EINVAL;
1778 		return (IDMAP_ERR_ARG);
1779 	}
1780 
1781 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1782 
1783 	(void) memset(&request, 0, sizeof (request));
1784 	(void) memset(&result, 0, sizeof (result));
1785 
1786 	if (pid)
1787 		*pid = UINT32_MAX;
1788 	if (unixname)
1789 		*unixname = NULL;
1790 	if (direction)
1791 		*direction = IDMAP_DIRECTION_UNDEF;
1792 
1793 	request.flag = flag;
1794 	request.id1.idtype = IDMAP_SID;
1795 	if (sidprefix && rid) {
1796 		request.id1.idmap_id_u.sid.prefix = (char *)sidprefix;
1797 		request.id1.idmap_id_u.sid.rid = *rid;
1798 	} else if (winname) {
1799 		retcode = idmap_strdupnull(&request.id1name, winname);
1800 		if (retcode != IDMAP_SUCCESS)
1801 			goto out;
1802 
1803 		retcode = idmap_strdupnull(&request.id1domain, windomain);
1804 		if (retcode != IDMAP_SUCCESS)
1805 			goto out;
1806 
1807 		request.id1.idmap_id_u.sid.prefix = NULL;
1808 	} else {
1809 		errno = EINVAL;
1810 		return (IDMAP_ERR_ARG);
1811 	}
1812 
1813 	if (*is_user == 1)
1814 		request.id2.idtype = IDMAP_UID;
1815 	else if (*is_user == 0)
1816 		request.id2.idtype = IDMAP_GID;
1817 	else
1818 		request.id2.idtype = IDMAP_POSIXID;
1819 
1820 	if (*is_wuser == 1)
1821 		request.id1.idtype = IDMAP_USID;
1822 	else if (*is_wuser == 0)
1823 		request.id1.idtype = IDMAP_GSID;
1824 	else
1825 		request.id1.idtype = IDMAP_SID;
1826 
1827 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1828 	    (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1829 	    (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1830 	    TIMEOUT);
1831 
1832 	if (clntstat != RPC_SUCCESS)
1833 		return (_idmap_rpc2stat(clnt));
1834 
1835 	retcode = result.retcode;
1836 
1837 	if ((mapping = result.mappings.mappings_val) == NULL) {
1838 		if (retcode == IDMAP_SUCCESS)
1839 			retcode = IDMAP_ERR_NORESULT;
1840 		goto out;
1841 	}
1842 
1843 	if (mapping->id2.idtype == IDMAP_UID) {
1844 		*is_user = 1;
1845 	} else if (mapping->id2.idtype == IDMAP_GID) {
1846 		*is_user = 0;
1847 	} else {
1848 		goto out;
1849 	}
1850 
1851 	if (mapping->id1.idtype == IDMAP_USID) {
1852 		*is_wuser = 1;
1853 	} else if (mapping->id1.idtype == IDMAP_GSID) {
1854 		*is_wuser = 0;
1855 	} else {
1856 		goto out;
1857 	}
1858 
1859 	if (direction)
1860 		*direction = mapping->direction;
1861 	if (pid)
1862 		*pid = mapping->id2.idmap_id_u.uid;
1863 
1864 	rc = idmap_strdupnull(unixname, mapping->id2name);
1865 	if (rc != IDMAP_SUCCESS)
1866 		retcode = rc;
1867 
1868 	rc = idmap_info_cpy(info, &mapping->info);
1869 	if (rc != IDMAP_SUCCESS)
1870 		retcode = rc;
1871 
1872 out:
1873 	if (request.id1name != NULL)
1874 		free(request.id1name);
1875 	if (request.id1domain != NULL)
1876 		free(request.id1domain);
1877 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1878 	if (retcode != IDMAP_SUCCESS)
1879 		errno = idmap_stat2errno(retcode);
1880 	return (retcode);
1881 }
1882 
1883 
1884 /*
1885  * Get unix to windows mapping
1886  */
1887 idmap_stat
1888 idmap_get_u2w_mapping(idmap_handle_t *handle,
1889 		uid_t *pid, const char *unixname,
1890 		int flag, int is_user, int *is_wuser,
1891 		char **sidprefix, idmap_rid_t *rid,
1892 		char **winname, char **windomain,
1893 		int *direction, idmap_info *info)
1894 {
1895 	CLIENT			*clnt;
1896 	enum clnt_stat		clntstat;
1897 	idmap_mapping		request, *mapping;
1898 	idmap_mappings_res	result;
1899 	idmap_retcode		retcode, rc;
1900 
1901 	if (handle == NULL) {
1902 		errno = EINVAL;
1903 		return (IDMAP_ERR_ARG);
1904 	}
1905 
1906 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1907 
1908 	if (sidprefix)
1909 		*sidprefix = NULL;
1910 	if (winname)
1911 		*winname = NULL;
1912 	if (windomain)
1913 		*windomain = NULL;
1914 	if (rid)
1915 		*rid = UINT32_MAX;
1916 	if (direction)
1917 		*direction = IDMAP_DIRECTION_UNDEF;
1918 
1919 	(void) memset(&request, 0, sizeof (request));
1920 	(void) memset(&result, 0, sizeof (result));
1921 
1922 	request.flag = flag;
1923 	request.id1.idtype = is_user?IDMAP_UID:IDMAP_GID;
1924 
1925 	if (pid && *pid != UINT32_MAX) {
1926 		request.id1.idmap_id_u.uid = *pid;
1927 	} else if (unixname) {
1928 		request.id1name = (char *)unixname;
1929 		request.id1.idmap_id_u.uid = UINT32_MAX;
1930 	} else {
1931 		errno = EINVAL;
1932 		return (IDMAP_ERR_ARG);
1933 	}
1934 
1935 	if (is_wuser == NULL)
1936 		request.id2.idtype = IDMAP_SID;
1937 	else if (*is_wuser == -1)
1938 		request.id2.idtype = IDMAP_SID;
1939 	else if (*is_wuser == 0)
1940 		request.id2.idtype = IDMAP_GSID;
1941 	else if (*is_wuser == 1)
1942 		request.id2.idtype = IDMAP_USID;
1943 
1944 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1945 	    (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1946 	    (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1947 	    TIMEOUT);
1948 
1949 	if (clntstat != RPC_SUCCESS)
1950 		return (_idmap_rpc2stat(clnt));
1951 
1952 	retcode = result.retcode;
1953 
1954 	if ((mapping = result.mappings.mappings_val) == NULL) {
1955 		if (retcode == IDMAP_SUCCESS)
1956 			retcode = IDMAP_ERR_NORESULT;
1957 		goto out;
1958 	}
1959 
1960 	if (direction != NULL)
1961 		*direction = mapping->direction;
1962 
1963 	if (is_wuser != NULL) {
1964 		if (mapping->id2.idtype == IDMAP_USID)
1965 			*is_wuser = 1;
1966 		else if (mapping->id2.idtype == IDMAP_GSID)
1967 			*is_wuser = 0;
1968 		else
1969 			*is_wuser = -1;
1970 	}
1971 
1972 	if (sidprefix && mapping->id2.idmap_id_u.sid.prefix &&
1973 	    *mapping->id2.idmap_id_u.sid.prefix != '\0') {
1974 		*sidprefix = strdup(mapping->id2.idmap_id_u.sid.prefix);
1975 		if (*sidprefix == NULL) {
1976 			retcode = IDMAP_ERR_MEMORY;
1977 			goto errout;
1978 		}
1979 	}
1980 	if (rid)
1981 		*rid = mapping->id2.idmap_id_u.sid.rid;
1982 
1983 	rc = idmap_strdupnull(winname, mapping->id2name);
1984 	if (rc != IDMAP_SUCCESS)
1985 		retcode = rc;
1986 
1987 	rc = idmap_strdupnull(windomain, mapping->id2domain);
1988 	if (rc != IDMAP_SUCCESS)
1989 		retcode = rc;
1990 
1991 	rc = idmap_info_cpy(info, &mapping->info);
1992 	if (rc != IDMAP_SUCCESS)
1993 		retcode = rc;
1994 
1995 	goto out;
1996 
1997 errout:
1998 	if (sidprefix && *sidprefix) {
1999 		free(*sidprefix);
2000 		*sidprefix = NULL;
2001 	}
2002 	if (winname && *winname) {
2003 		free(*winname);
2004 		*winname = NULL;
2005 	}
2006 	if (windomain && *windomain) {
2007 		free(*windomain);
2008 		*windomain = NULL;
2009 	}
2010 
2011 out:
2012 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
2013 	if (retcode != IDMAP_SUCCESS)
2014 		errno = idmap_stat2errno(retcode);
2015 	return (retcode);
2016 }
2017 
2018 
2019 
2020 #define	gettext(s)	s
2021 static stat_table_t stattable[] = {
2022 	{IDMAP_SUCCESS, gettext("Success"), 0},
2023 	{IDMAP_NEXT, gettext("More results available"), 0},
2024 	{IDMAP_ERR_OTHER, gettext("Undefined error"), EINVAL},
2025 	{IDMAP_ERR_INTERNAL, gettext("Internal error"), EINVAL},
2026 	{IDMAP_ERR_MEMORY, gettext("Out of memory"), ENOMEM},
2027 	{IDMAP_ERR_NORESULT, gettext("No results available"), EINVAL},
2028 	{IDMAP_ERR_NOTUSER, gettext("Not a user"), EINVAL},
2029 	{IDMAP_ERR_NOTGROUP, gettext("Not a group"), EINVAL},
2030 	{IDMAP_ERR_NOTSUPPORTED, gettext("Operation not supported"), ENOTSUP},
2031 	{IDMAP_ERR_W2U_NAMERULE,
2032 		gettext("Invalid Windows to UNIX name-based rule"), EINVAL},
2033 	{IDMAP_ERR_U2W_NAMERULE,
2034 		gettext("Invalid UNIX to Windows name-based rule"), EINVAL},
2035 	{IDMAP_ERR_CACHE, gettext("Invalid cache"), EINVAL},
2036 	{IDMAP_ERR_DB, gettext("Invalid database"), EINVAL},
2037 	{IDMAP_ERR_ARG, gettext("Invalid argument"), EINVAL},
2038 	{IDMAP_ERR_SID, gettext("Invalid SID"), EINVAL},
2039 	{IDMAP_ERR_IDTYPE, gettext("Invalid identity type"), EINVAL},
2040 	{IDMAP_ERR_RPC_HANDLE, gettext("Bad RPC handle"), EBADF},
2041 	{IDMAP_ERR_RPC, gettext("RPC error"), EINVAL},
2042 	{IDMAP_ERR_CLIENT_HANDLE, gettext("Bad client handle"), EINVAL},
2043 	{IDMAP_ERR_BUSY, gettext("Server is busy"), EBUSY},
2044 	{IDMAP_ERR_PERMISSION_DENIED, gettext("Permission denied"), EACCES},
2045 	{IDMAP_ERR_NOMAPPING,
2046 		gettext("Mapping not found or inhibited"), EINVAL},
2047 	{IDMAP_ERR_NEW_ID_ALLOC_REQD,
2048 		gettext("New mapping needs to be created"), EINVAL},
2049 	{IDMAP_ERR_DOMAIN, gettext("Invalid domain"), EINVAL},
2050 	{IDMAP_ERR_SECURITY, gettext("Security issue"), EINVAL},
2051 	{IDMAP_ERR_NOTFOUND, gettext("Not found"), EINVAL},
2052 	{IDMAP_ERR_DOMAIN_NOTFOUND, gettext("Domain not found"), EINVAL},
2053 	{IDMAP_ERR_UPDATE_NOTALLOWED, gettext("Update not allowed"), EINVAL},
2054 	{IDMAP_ERR_CFG, gettext("Configuration error"), EINVAL},
2055 	{IDMAP_ERR_CFG_CHANGE, gettext("Invalid configuration change"), EINVAL},
2056 	{IDMAP_ERR_NOTMAPPED_WELLKNOWN,
2057 		gettext("No mapping for well-known SID"), EINVAL},
2058 	{IDMAP_ERR_RETRIABLE_NET_ERR,
2059 		gettext("Windows lookup failed"), EINVAL},
2060 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
2061 		gettext("Duplicate rule or conflicts with an existing "
2062 		"Windows to UNIX name-based rule"), EINVAL},
2063 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
2064 		gettext("Duplicate rule or conflicts with an existing "
2065 		"Unix to Windows name-based rule"), EINVAL},
2066 	{IDMAP_ERR_BAD_UTF8,
2067 		gettext("Invalid or illegal UTF-8 sequence found in "
2068 		"a given Windows entity name or domain name"), EINVAL},
2069 	{IDMAP_ERR_NONEGENERATED,
2070 		gettext("Mapping not found and none created (see -c option)"),
2071 		EINVAL},
2072 	{IDMAP_ERR_PROP_UNKNOWN,
2073 		gettext("Undefined property"),
2074 		EINVAL},
2075 	{IDMAP_ERR_NS_LDAP_CFG,
2076 		gettext("Native LDAP configuration error"), EINVAL},
2077 	{IDMAP_ERR_NS_LDAP_PARTIAL,
2078 		gettext("Partial result from Native LDAP"), EINVAL},
2079 	{IDMAP_ERR_NS_LDAP_OP_FAILED,
2080 		gettext("Native LDAP operation failed"), EINVAL},
2081 	{IDMAP_ERR_NS_LDAP_BAD_WINNAME,
2082 		gettext("Improper winname form found in Native LDAP"), EINVAL},
2083 	{-1, NULL, 0}
2084 };
2085 #undef	gettext
2086 
2087 
2088 /*
2089  * Get description of status code
2090  *
2091  * Input:
2092  * status - Status code returned by libidmap API call
2093  *
2094  * Return Value:
2095  * human-readable localized description of idmap_stat
2096  */
2097 /* ARGSUSED */
2098 const char *
2099 idmap_stat2string(idmap_handle_t *handle, idmap_stat status)
2100 {
2101 	int i;
2102 
2103 	for (i = 0; stattable[i].msg; i++) {
2104 		if (stattable[i].retcode == status)
2105 			return (gettext(stattable[i].msg));
2106 	}
2107 	return (gettext("Unknown error"));
2108 }
2109 
2110 
2111 static int
2112 idmap_stat2errno(idmap_stat stat)
2113 {
2114 	int i;
2115 	for (i = 0; stattable[i].msg; i++) {
2116 		if (stattable[i].retcode == stat)
2117 			return (stattable[i].errnum);
2118 	}
2119 	return (EINVAL);
2120 }
2121 
2122 
2123 /*
2124  * Get status code from string
2125  */
2126 idmap_stat
2127 idmap_string2stat(const char *str)
2128 {
2129 	if (str == NULL)
2130 		return (IDMAP_ERR_INTERNAL);
2131 
2132 #define	return_cmp(a) \
2133 	if (0 == strcmp(str, "IDMAP_ERR_" #a)) \
2134 		return (IDMAP_ERR_ ## a);
2135 
2136 	return_cmp(OTHER);
2137 	return_cmp(INTERNAL);
2138 	return_cmp(MEMORY);
2139 	return_cmp(NORESULT);
2140 	return_cmp(NOTUSER);
2141 	return_cmp(NOTGROUP);
2142 	return_cmp(NOTSUPPORTED);
2143 	return_cmp(W2U_NAMERULE);
2144 	return_cmp(U2W_NAMERULE);
2145 	return_cmp(CACHE);
2146 	return_cmp(DB);
2147 	return_cmp(ARG);
2148 	return_cmp(SID);
2149 	return_cmp(IDTYPE);
2150 	return_cmp(RPC_HANDLE);
2151 	return_cmp(RPC);
2152 	return_cmp(CLIENT_HANDLE);
2153 	return_cmp(BUSY);
2154 	return_cmp(PERMISSION_DENIED);
2155 	return_cmp(NOMAPPING);
2156 	return_cmp(NEW_ID_ALLOC_REQD);
2157 	return_cmp(DOMAIN);
2158 	return_cmp(SECURITY);
2159 	return_cmp(NOTFOUND);
2160 	return_cmp(DOMAIN_NOTFOUND);
2161 	return_cmp(MEMORY);
2162 	return_cmp(UPDATE_NOTALLOWED);
2163 	return_cmp(CFG);
2164 	return_cmp(CFG_CHANGE);
2165 	return_cmp(NOTMAPPED_WELLKNOWN);
2166 	return_cmp(RETRIABLE_NET_ERR);
2167 	return_cmp(W2U_NAMERULE_CONFLICT);
2168 	return_cmp(U2W_NAMERULE_CONFLICT);
2169 	return_cmp(BAD_UTF8);
2170 	return_cmp(NONEGENERATED);
2171 	return_cmp(PROP_UNKNOWN);
2172 	return_cmp(NS_LDAP_CFG);
2173 	return_cmp(NS_LDAP_PARTIAL);
2174 	return_cmp(NS_LDAP_OP_FAILED);
2175 	return_cmp(NS_LDAP_BAD_WINNAME);
2176 #undef return_cmp
2177 
2178 	return (IDMAP_ERR_OTHER);
2179 }
2180 
2181 
2182 /*
2183  * Map the given status to one that can be returned by the protocol
2184  */
2185 idmap_stat
2186 idmap_stat4prot(idmap_stat status)
2187 {
2188 	switch (status) {
2189 	case IDMAP_ERR_MEMORY:
2190 	case IDMAP_ERR_CACHE:
2191 		return (IDMAP_ERR_INTERNAL);
2192 	}
2193 	return (status);
2194 }
2195 
2196 
2197 /*
2198  * This is a convenience routine which duplicates a string after
2199  * checking for NULL pointers. This function will return success if
2200  * either the 'to' OR 'from' pointers are NULL.
2201  */
2202 static idmap_stat
2203 idmap_strdupnull(char **to, const char *from)
2204 {
2205 	if (to == NULL)
2206 		return (IDMAP_SUCCESS);
2207 
2208 	if (from == NULL || *from == '\0') {
2209 		*to = NULL;
2210 		return (IDMAP_SUCCESS);
2211 	}
2212 
2213 	*to = strdup(from);
2214 	if (*to == NULL)
2215 		return (IDMAP_ERR_MEMORY);
2216 	return (IDMAP_SUCCESS);
2217 }
2218 
2219 
2220 idmap_stat
2221 idmap_namerule_cpy(idmap_namerule *to, idmap_namerule *from)
2222 {
2223 	idmap_stat retval;
2224 
2225 	if (to == NULL)
2226 		return (IDMAP_SUCCESS);
2227 
2228 	(void) memcpy(to, from, sizeof (idmap_namerule));
2229 	to->windomain = NULL;
2230 	to->winname = NULL;
2231 	to->unixname = NULL;
2232 
2233 	retval = idmap_strdupnull(&to->windomain, from->windomain);
2234 	if (retval != IDMAP_SUCCESS)
2235 		return (retval);
2236 
2237 	retval = idmap_strdupnull(&to->winname, from->winname);
2238 	if (retval != IDMAP_SUCCESS) {
2239 		free(to->windomain);
2240 		to->windomain = NULL;
2241 		return (retval);
2242 	}
2243 
2244 	retval = idmap_strdupnull(&to->unixname, from->unixname);
2245 	if (retval != IDMAP_SUCCESS) {
2246 		free(to->windomain);
2247 		to->windomain = NULL;
2248 		free(to->winname);
2249 		to->winname = NULL;
2250 		return (retval);
2251 	}
2252 
2253 	return (retval);
2254 }
2255 
2256 
2257 static
2258 idmap_stat
2259 idmap_how_ds_based_cpy(idmap_how_ds_based *to, idmap_how_ds_based *from)
2260 {
2261 	idmap_stat retval;
2262 
2263 	if (to == NULL)
2264 		return (IDMAP_SUCCESS);
2265 
2266 	retval = idmap_strdupnull(&to->dn, from->dn);
2267 	if (retval != IDMAP_SUCCESS)
2268 		return (retval);
2269 
2270 	retval = idmap_strdupnull(&to->attr, from->attr);
2271 	if (retval != IDMAP_SUCCESS) {
2272 		free(to->dn);
2273 		to->dn = NULL;
2274 		return (retval);
2275 	}
2276 
2277 	retval = idmap_strdupnull(&to->value, from->value);
2278 	if (retval != IDMAP_SUCCESS) {
2279 		free(to->dn);
2280 		to->dn = NULL;
2281 		free(to->attr);
2282 		to->attr = NULL;
2283 		return (retval);
2284 	}
2285 
2286 	return (retval);
2287 }
2288 
2289 
2290 idmap_stat
2291 idmap_info_cpy(idmap_info *to, idmap_info *from)
2292 {
2293 	idmap_stat retval = IDMAP_SUCCESS;
2294 
2295 	if (to == NULL)
2296 		return (IDMAP_SUCCESS);
2297 
2298 	(void) memset(to, 0, sizeof (idmap_info));
2299 
2300 	to->src = from->src;
2301 	to->how.map_type = from->how.map_type;
2302 	switch (to->how.map_type) {
2303 	case IDMAP_MAP_TYPE_DS_AD:
2304 		retval = idmap_how_ds_based_cpy(&to->how.idmap_how_u.ad,
2305 		    &from->how.idmap_how_u.ad);
2306 		break;
2307 
2308 	case IDMAP_MAP_TYPE_DS_NLDAP:
2309 		retval = idmap_how_ds_based_cpy(&to->how.idmap_how_u.nldap,
2310 		    &from->how.idmap_how_u.nldap);
2311 		break;
2312 
2313 	case IDMAP_MAP_TYPE_RULE_BASED:
2314 		retval = idmap_namerule_cpy(&to->how.idmap_how_u.rule,
2315 		    &from->how.idmap_how_u.rule);
2316 		break;
2317 
2318 	case IDMAP_MAP_TYPE_EPHEMERAL:
2319 		break;
2320 
2321 	case IDMAP_MAP_TYPE_LOCAL_SID:
2322 		break;
2323 
2324 	case IDMAP_MAP_TYPE_KNOWN_SID:
2325 		break;
2326 	}
2327 	return (retval);
2328 }
2329 
2330 
2331 /*
2332  * This routine is similar to idmap_info_cpy, but the strings
2333  * are moved from the "from" info to the "to" info.
2334  * This routine is equivelent of:
2335  *
2336  *	idmap_info_cpy(to,from);
2337  *	idmap_info_free(from);
2338  */
2339 idmap_stat
2340 idmap_info_mov(idmap_info *to, idmap_info *from)
2341 {
2342 	idmap_stat retval = IDMAP_SUCCESS;
2343 
2344 	if (to == NULL) {
2345 		idmap_info_free(from);
2346 		return (IDMAP_SUCCESS);
2347 	}
2348 	(void) memcpy(to, from, sizeof (idmap_info));
2349 
2350 	(void) memset(from, 0, sizeof (idmap_info));
2351 
2352 	return (retval);
2353 }
2354 
2355 
2356 void
2357 idmap_info_free(idmap_info *info)
2358 {
2359 	idmap_how *how;
2360 
2361 	if (info == NULL)
2362 		return;
2363 
2364 	how = &info->how;
2365 	switch (how->map_type) {
2366 	case IDMAP_MAP_TYPE_DS_AD:
2367 		free(how->idmap_how_u.ad.dn);
2368 		how->idmap_how_u.ad.dn = NULL;
2369 		free(how->idmap_how_u.ad.attr);
2370 		how->idmap_how_u.ad.attr = NULL;
2371 		free(how->idmap_how_u.ad.value);
2372 		how->idmap_how_u.ad.value = NULL;
2373 		break;
2374 
2375 	case IDMAP_MAP_TYPE_DS_NLDAP:
2376 		free(how->idmap_how_u.nldap.dn);
2377 		how->idmap_how_u.nldap.dn = NULL;
2378 		free(how->idmap_how_u.nldap.attr);
2379 		how->idmap_how_u.nldap.attr = NULL;
2380 		free(how->idmap_how_u.nldap.value);
2381 		how->idmap_how_u.nldap.value = NULL;
2382 		break;
2383 
2384 	case IDMAP_MAP_TYPE_RULE_BASED:
2385 		free(how->idmap_how_u.rule.windomain);
2386 		how->idmap_how_u.rule.windomain = NULL;
2387 		free(how->idmap_how_u.rule.winname);
2388 		how->idmap_how_u.rule.winname = NULL;
2389 		free(how->idmap_how_u.rule.unixname);
2390 		how->idmap_how_u.rule.unixname = NULL;
2391 		break;
2392 
2393 	case IDMAP_MAP_TYPE_EPHEMERAL:
2394 		break;
2395 
2396 	case IDMAP_MAP_TYPE_LOCAL_SID:
2397 		break;
2398 	}
2399 	how->map_type = IDMAP_MAP_TYPE_UNKNOWN;
2400 	info->src = IDMAP_MAP_SRC_UNKNOWN;
2401 }
2402 
2403 
2404 /*
2405  * Get uid given Windows name
2406  */
2407 idmap_stat
2408 idmap_getuidbywinname(const char *name, const char *domain, int flag,
2409 	uid_t *uid)
2410 {
2411 	idmap_handle_t	*ih;
2412 	idmap_retcode	rc;
2413 	int		is_user = 1;
2414 	int		is_wuser = -1;
2415 	int 		direction;
2416 
2417 	if (uid == NULL)
2418 		return (IDMAP_ERR_ARG);
2419 
2420 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2421 		rc = idmap_cache_lookup_uidbywinname(name, domain, uid);
2422 		if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
2423 			return (rc);
2424 	}
2425 	/* Get mapping */
2426 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
2427 		return (rc);
2428 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, flag,
2429 	    &is_user, &is_wuser, uid, NULL, &direction, NULL);
2430 	(void) idmap_fini(ih);
2431 
2432 	if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
2433 		/* If we have not got the domain don't store UID to winname */
2434 		if (domain == NULL)
2435 			direction = IDMAP_DIRECTION_W2U;
2436 		idmap_cache_add_winname2uid(name, domain, *uid, direction);
2437 	}
2438 
2439 	return (rc);
2440 }
2441 
2442 
2443 /*
2444  * Get gid given Windows name
2445  */
2446 idmap_stat
2447 idmap_getgidbywinname(const char *name, const char *domain, int flag,
2448 	gid_t *gid)
2449 {
2450 	idmap_handle_t	*ih;
2451 	idmap_retcode	rc;
2452 	int		is_user = 0;
2453 	int		is_wuser = -1;
2454 	int		direction;
2455 
2456 	if (gid == NULL)
2457 		return (IDMAP_ERR_ARG);
2458 
2459 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2460 		rc = idmap_cache_lookup_gidbywinname(name, domain, gid);
2461 		if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
2462 			return (rc);
2463 	}
2464 
2465 	/* Get mapping */
2466 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
2467 		return (rc);
2468 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, flag,
2469 	    &is_user, &is_wuser, gid, NULL, &direction, NULL);
2470 	(void) idmap_fini(ih);
2471 
2472 	if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
2473 		/* If we have not got the domain don't store GID to winname */
2474 		if (domain == NULL)
2475 			direction = IDMAP_DIRECTION_W2U;
2476 		idmap_cache_add_winname2gid(name, domain, *gid, direction);
2477 	}
2478 
2479 	return (rc);
2480 }
2481 
2482 
2483 /*
2484  * Get winname given pid
2485  */
2486 static idmap_retcode
2487 idmap_getwinnamebypid(uid_t pid, int is_user, int flag, char **name,
2488 	char **domain)
2489 {
2490 	idmap_handle_t	*ih;
2491 	idmap_retcode	rc;
2492 	int		len;
2493 	char		*winname, *windomain;
2494 	int		direction;
2495 
2496 	if (name == NULL)
2497 		return (IDMAP_ERR_ARG);
2498 
2499 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2500 		if (is_user)
2501 			rc = idmap_cache_lookup_winnamebyuid(&winname,
2502 			    &windomain, pid);
2503 		else
2504 			rc = idmap_cache_lookup_winnamebygid(&winname,
2505 			    &windomain, pid);
2506 		if (rc == IDMAP_SUCCESS)
2507 			goto out;
2508 		if (rc == IDMAP_ERR_MEMORY)
2509 			return (rc);
2510 	}
2511 
2512 	/* Get mapping */
2513 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
2514 		return (rc);
2515 	rc = idmap_get_u2w_mapping(ih, &pid, NULL, flag, is_user, NULL,
2516 	    NULL, NULL, &winname, &windomain, &direction, NULL);
2517 	(void) idmap_fini(ih);
2518 
2519 	/* Return on error */
2520 	if (rc != IDMAP_SUCCESS)
2521 		return (rc);
2522 
2523 	/*
2524 	 * The given PID may have been mapped to a locally
2525 	 * generated SID in which case there isn't any
2526 	 * Windows name
2527 	 */
2528 	if (winname == NULL || windomain == NULL) {
2529 		idmap_free(winname);
2530 		idmap_free(windomain);
2531 		return (IDMAP_ERR_NORESULT);
2532 	}
2533 
2534 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2535 		if (is_user)
2536 			idmap_cache_add_winname2uid(winname, windomain,
2537 			    pid, direction);
2538 		else
2539 			idmap_cache_add_winname2gid(winname, windomain,
2540 			    pid, direction);
2541 	}
2542 
2543 out:
2544 	if (domain != NULL) {
2545 		*name = winname;
2546 		*domain = windomain;
2547 	} else {
2548 		len = strlen(winname) + strlen(windomain) + 2;
2549 		if ((*name = malloc(len)) != NULL)
2550 			(void) snprintf(*name, len, "%s@%s", winname,
2551 			    windomain);
2552 		else
2553 			rc = IDMAP_ERR_MEMORY;
2554 		idmap_free(winname);
2555 		idmap_free(windomain);
2556 	}
2557 
2558 	return (rc);
2559 }
2560 
2561 
2562 /*
2563  * Get winname given uid
2564  */
2565 idmap_stat
2566 idmap_getwinnamebyuid(uid_t uid, int flag, char **name, char **domain)
2567 {
2568 	return (idmap_getwinnamebypid(uid, 1, flag, name, domain));
2569 }
2570 
2571 
2572 /*
2573  * Get winname given gid
2574  */
2575 idmap_stat
2576 idmap_getwinnamebygid(gid_t gid, int flag, char **name, char **domain)
2577 {
2578 	return (idmap_getwinnamebypid(gid, 0, flag, name, domain));
2579 }
2580 
2581 
2582 /* printflike */
2583 void
2584 idmapdlog(int pri, const char *format, ...) {
2585 	va_list args;
2586 
2587 	va_start(args, format);
2588 	if (pri <= logstate.max_pri) {
2589 		(void) vfprintf(stderr, format, args);
2590 		(void) fprintf(stderr, "\n");
2591 	}
2592 
2593 	/*
2594 	 * We don't want to fill up the logs with useless messages when
2595 	 * we're degraded, but we still want to log.
2596 	 */
2597 	if (logstate.degraded)
2598 		pri = LOG_DEBUG;
2599 
2600 	if (logstate.write_syslog)
2601 		(void) vsyslog(pri, format, args);
2602 	va_end(args);
2603 }
2604 
2605 void
2606 idmap_log_stderr(int pri)
2607 {
2608 	logstate.max_pri = pri;
2609 }
2610 
2611 void
2612 idmap_log_syslog(bool_t what)
2613 {
2614 	logstate.write_syslog = what;
2615 }
2616 
2617 void
2618 idmap_log_degraded(bool_t what)
2619 {
2620 	logstate.degraded = what;
2621 }
2622