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