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