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