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