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