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