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