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