xref: /illumos-gate/usr/src/lib/libidmap/common/idmap_api.c (revision d3a612ca42c17c3baa6c96ded00f98db349cc881)
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 2007 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 	free(ptr);
104 }
105 
106 
107 #define	MIN_STACK_NEEDS	16384
108 
109 /*
110  * Create and Initialize idmap client handle for rpc/doors
111  *
112  * Output:
113  * handle - idmap handle
114  */
115 idmap_stat
116 idmap_init(idmap_handle_t **handle) {
117 	CLIENT			*clnt = NULL;
118 	struct idmap_handle	*hptr;
119 	uint_t			sendsz = 0;
120 	stack_t			st;
121 
122 	*handle = NULL;
123 	hptr = (struct idmap_handle *)calloc(1, sizeof (*hptr));
124 	if (hptr == NULL)
125 		return (IDMAP_ERR_MEMORY);
126 
127 	/*
128 	 * clnt_door_call() alloca()s sendsz bytes (twice too, once for
129 	 * the call args buffer and once for the call result buffer), so
130 	 * we want to pick a sendsz that will be large enough, but not
131 	 * too large.
132 	 */
133 	if (stack_getbounds(&st) == 0) {
134 		/*
135 		 * Estimate how much stack space is left;
136 		 * st.ss_sp is the top of stack.
137 		 */
138 		if ((char *)&sendsz < (char *)st.ss_sp)
139 			/* stack grows up */
140 			sendsz = ((char *)st.ss_sp - (char *)&sendsz);
141 		else
142 			/* stack grows down */
143 			sendsz = ((char *)&sendsz - (char *)st.ss_sp);
144 
145 		/*
146 		 * Take much of the stack space left, divided by two,
147 		 * but leave enough for our needs (just a guess!), and
148 		 * if we can't, then roll the dice.
149 		 */
150 		sendsz = RNDUP(sendsz / 2);
151 		if (sendsz < MIN_STACK_NEEDS)
152 			sendsz = 0;	/* RPC call may fail */
153 		else if (sendsz > IDMAP_MAX_DOOR_RPC)
154 			sendsz = IDMAP_MAX_DOOR_RPC;
155 	}
156 
157 	clnt = clnt_door_create(IDMAP_PROG, IDMAP_V1, sendsz);
158 	if (clnt == NULL) {
159 		free(hptr);
160 		return (IDMAP_ERR_RPC);
161 	}
162 	hptr->type = _IDMAP_HANDLE_RPC_DOORS;
163 	hptr->privhandle = clnt;
164 	*handle = hptr;
165 	return (IDMAP_SUCCESS);
166 }
167 
168 
169 /*
170  * Finalize idmap handle
171  *
172  * Input:
173  * handle - idmap handle
174  */
175 idmap_stat
176 idmap_fini(idmap_handle_t *handle) {
177 	CLIENT			*clnt;
178 	struct idmap_handle	*hptr;
179 
180 	if (handle == NULL)
181 		return (IDMAP_SUCCESS);
182 
183 	hptr = (struct idmap_handle *)handle;
184 
185 	switch (hptr->type) {
186 	case _IDMAP_HANDLE_RPC_DOORS:
187 		clnt = (CLIENT *)hptr->privhandle;
188 		if (clnt) {
189 			if (clnt->cl_auth)
190 				auth_destroy(clnt->cl_auth);
191 			clnt_destroy(clnt);
192 		}
193 		break;
194 	default:
195 		break;
196 	}
197 	free(hptr);
198 	return (IDMAP_SUCCESS);
199 }
200 
201 
202 
203 /*
204  * Create/Initialize handle for updates
205  *
206  * Output:
207  * udthandle - update handle
208  */
209 idmap_stat
210 idmap_udt_create(idmap_handle_t *handle, idmap_udt_handle_t **udthandle) {
211 	idmap_udt_handle_t	*tmp;
212 
213 	if (handle == NULL || udthandle == NULL) {
214 		errno = EINVAL;
215 		return (IDMAP_ERR_ARG);
216 	}
217 	if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
218 		errno = ENOMEM;
219 		return (IDMAP_ERR_MEMORY);
220 	}
221 
222 	tmp->ih = handle;
223 	*udthandle = tmp;
224 	return (IDMAP_SUCCESS);
225 }
226 
227 
228 /*
229  * All the updates specified by the update handle are committed
230  * in a single transaction. i.e either all succeed or none.
231  *
232  * Input:
233  * udthandle - update handle with the update requests
234  *
235  * Return value:
236  * Status of the commit
237  */
238 idmap_stat
239 idmap_udt_commit(idmap_udt_handle_t *udthandle) {
240 	CLIENT			*clnt;
241 	enum clnt_stat		clntstat;
242 	idmap_update_res	res;
243 	idmap_stat		retcode;
244 
245 	if (udthandle == NULL) {
246 		errno = EINVAL;
247 		return (IDMAP_ERR_ARG);
248 	}
249 
250 	(void) memset(&res, 0, sizeof (res));
251 
252 	_IDMAP_GET_CLIENT_HANDLE(udthandle->ih, clnt);
253 	clntstat = clnt_call(clnt, IDMAP_UPDATE,
254 		(xdrproc_t)xdr_idmap_update_batch, (caddr_t)&udthandle->batch,
255 		(xdrproc_t)xdr_idmap_update_res, (caddr_t)&res,
256 		TIMEOUT);
257 
258 	if (clntstat != RPC_SUCCESS) {
259 		retcode = _idmap_rpc2stat(clnt);
260 		goto out;
261 	}
262 
263 	retcode = udthandle->commit_stat = res.retcode;
264 	udthandle->error_index = res.error_index;
265 
266 	if (retcode != IDMAP_SUCCESS) {
267 
268 		if (udthandle->error_index < 0)
269 			goto out;
270 
271 		retcode = idmap_namerule_cpy(&udthandle->error_rule,
272 		    &res.error_rule);
273 		if (retcode != IDMAP_SUCCESS) {
274 			udthandle->error_index = -2;
275 			goto out;
276 		}
277 
278 		retcode = idmap_namerule_cpy(&udthandle->conflict_rule,
279 		    &res.conflict_rule);
280 		if (retcode != IDMAP_SUCCESS) {
281 			udthandle->error_index = -2;
282 			goto out;
283 		}
284 	}
285 
286 	retcode = res.retcode;
287 
288 
289 out:
290 	/* reset handle so that it can be used again */
291 	if (retcode == IDMAP_SUCCESS) {
292 		_IDMAP_RESET_UDT_HANDLE(udthandle);
293 	}
294 
295 	(void) xdr_free(xdr_idmap_update_res, (caddr_t)&res);
296 	errno = idmap_stat2errno(retcode);
297 	return (retcode);
298 }
299 
300 
301 static void
302 idmap_namerule_parts_clear(char **windomain, char **winname,
303     char **unixname, boolean_t *is_user, boolean_t *is_nt4,
304     int *direction) {
305 	if (windomain)
306 		*windomain = NULL;
307 	if (winname)
308 		*winname = NULL;
309 	if (unixname)
310 		*unixname = NULL;
311 
312 	if (is_nt4)
313 		*is_nt4 = 0;
314 	if (is_user)
315 		*is_user = -1;
316 	if (direction)
317 		*direction = IDMAP_DIRECTION_UNDEF;
318 }
319 
320 static idmap_stat
321 idmap_namerule2parts(idmap_namerule	*rule,
322     char **windomain, char **winname,
323     char **unixname, boolean_t *is_user, boolean_t *is_nt4,
324     int *direction) {
325 	idmap_stat retcode;
326 
327 	if (EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
328 		return (IDMAP_ERR_NORESULT);
329 
330 
331 	retcode = idmap_strdupnull(windomain, rule->windomain);
332 	if (retcode != IDMAP_SUCCESS)
333 		goto errout;
334 
335 	retcode = idmap_strdupnull(winname, rule->winname);
336 	if (retcode != IDMAP_SUCCESS)
337 		goto errout;
338 
339 	retcode = idmap_strdupnull(unixname, rule->unixname);
340 	if (retcode != IDMAP_SUCCESS)
341 		goto errout;
342 
343 
344 	if (is_user)
345 		*is_user = rule->is_user;
346 	if (is_nt4)
347 		*is_nt4 = rule->is_nt4;
348 	if (direction)
349 		*direction = rule->direction;
350 
351 
352 	return (IDMAP_SUCCESS);
353 
354 errout:
355 	if (windomain && *windomain)
356 		free(*windomain);
357 	if (winname && *winname)
358 		free(*winname);
359 	if (unixname && *unixname)
360 		free(*unixname);
361 
362 	idmap_namerule_parts_clear(windomain, winname,
363 	    unixname, is_user, is_nt4, direction);
364 
365 	return (retcode);
366 
367 }
368 
369 /*
370  * Retrieve the index of the failed batch element. error_index == -1
371  * indicates failure at the beginning, -2 at the end.
372  *
373  * If idmap_udt_commit didn't return error, the returned value is undefined.
374  *
375  * Return value:
376  * IDMAP_SUCCESS
377  */
378 
379 idmap_stat
380 idmap_udt_get_error_index(idmap_udt_handle_t *udthandle,
381     int64_t *error_index) {
382 	if (error_index)
383 		*error_index = udthandle->error_index;
384 
385 	return (IDMAP_SUCCESS);
386 }
387 
388 
389 /*
390  * Retrieve the rule which caused the batch to fail. If
391  * idmap_udt_commit didn't return error or if error_index is < 0, the
392  * retrieved rule is undefined.
393  *
394  * Return value:
395  * IDMAP_ERR_NORESULT if there is no error rule.
396  * IDMAP_SUCCESS if the rule was obtained OK.
397  * other error code (IDMAP_ERR_NOMEMORY etc)
398  */
399 
400 idmap_stat
401 idmap_udt_get_error_rule(idmap_udt_handle_t *udthandle,
402     char **windomain, char **winname,
403     char **unixname, boolean_t *is_user, boolean_t *is_nt4,
404     int *direction) {
405 	idmap_namerule_parts_clear(windomain, winname,
406 	    unixname, is_user, is_nt4, direction);
407 
408 	if (udthandle->commit_stat == IDMAP_SUCCESS ||
409 	    udthandle->error_index < 0)
410 		return (IDMAP_ERR_NORESULT);
411 
412 	return (idmap_namerule2parts(
413 			&udthandle->error_rule,
414 			    windomain,
415 			    winname,
416 			    unixname,
417 			    is_user,
418 			    is_nt4,
419 			    direction));
420 }
421 
422 /*
423  * Retrieve the rule with which there was a conflict. TODO: retrieve
424  * the value.
425  *
426  * Return value:
427  * IDMAP_ERR_NORESULT if there is no error rule.
428  * IDMAP_SUCCESS if the rule was obtained OK.
429  * other error code (IDMAP_ERR_NOMEMORY etc)
430  */
431 
432 idmap_stat
433 idmap_udt_get_conflict_rule(idmap_udt_handle_t *udthandle,
434     char **windomain, char **winname,
435     char **unixname, boolean_t *is_user, boolean_t *is_nt4,
436     int *direction) {
437 	idmap_namerule_parts_clear(windomain, winname,
438 	    unixname, is_user, is_nt4, direction);
439 
440 	if (udthandle->commit_stat != IDMAP_ERR_W2U_NAMERULE_CONFLICT &&
441 	    udthandle->commit_stat != IDMAP_ERR_U2W_NAMERULE_CONFLICT) {
442 		    return (IDMAP_ERR_NORESULT);
443 	}
444 
445 	return (idmap_namerule2parts(
446 			&udthandle->conflict_rule,
447 			    windomain,
448 			    winname,
449 			    unixname,
450 			    is_user,
451 			    is_nt4,
452 			    direction));
453 }
454 
455 
456 /*
457  * Destroy the update handle
458  */
459 void
460 idmap_udt_destroy(idmap_udt_handle_t *udthandle) {
461 	if (udthandle == NULL)
462 		return;
463 	(void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
464 	(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->error_rule);
465 	(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->conflict_rule);
466 	free(udthandle);
467 }
468 
469 
470 idmap_stat
471 idmap_udt_add_namerule(idmap_udt_handle_t *udthandle, const char *windomain,
472 		boolean_t is_user, const char *winname, const char *unixname,
473 		boolean_t is_nt4, int direction) {
474 	idmap_retcode	retcode;
475 	idmap_namerule	*rule = NULL;
476 
477 	retcode = _udt_extend_batch(udthandle);
478 	if (retcode != IDMAP_SUCCESS)
479 		goto errout;
480 
481 	rule = &udthandle->batch.
482 		idmap_update_batch_val[udthandle->next].
483 		idmap_update_op_u.rule;
484 	rule->is_user = is_user;
485 	rule->direction = direction;
486 	rule->is_nt4 = is_nt4;
487 
488 	retcode = idmap_strdupnull(&rule->windomain, windomain);
489 	if (retcode != IDMAP_SUCCESS)
490 		goto errout;
491 
492 	retcode = idmap_strdupnull(&rule->winname, winname);
493 	if (retcode != IDMAP_SUCCESS)
494 		goto errout;
495 
496 	retcode = idmap_strdupnull(&rule->unixname, unixname);
497 	if (retcode != IDMAP_SUCCESS)
498 		goto errout;
499 
500 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
501 	    OP_ADD_NAMERULE;
502 	udthandle->next++;
503 	return (IDMAP_SUCCESS);
504 
505 errout:
506 	/* The batch should still be usable */
507 	if (rule)
508 		(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
509 	errno = idmap_stat2errno(retcode);
510 	return (retcode);
511 }
512 
513 
514 /* ARGSUSED */
515 idmap_stat
516 idmap_udt_rm_namerule(idmap_udt_handle_t *udthandle, boolean_t is_user,
517 		const char *windomain, const char *winname,
518 		const char *unixname, int direction) {
519 	idmap_retcode	retcode;
520 	idmap_namerule	*rule = NULL;
521 
522 	retcode = _udt_extend_batch(udthandle);
523 	if (retcode != IDMAP_SUCCESS)
524 		goto errout;
525 
526 	rule = &udthandle->batch.
527 		idmap_update_batch_val[udthandle->next].
528 		idmap_update_op_u.rule;
529 	rule->is_user = is_user;
530 	rule->direction = direction;
531 
532 	retcode = idmap_strdupnull(&rule->windomain, windomain);
533 	if (retcode != IDMAP_SUCCESS)
534 		goto errout;
535 
536 	retcode = idmap_strdupnull(&rule->winname, winname);
537 	if (retcode != IDMAP_SUCCESS)
538 		goto errout;
539 
540 	retcode = idmap_strdupnull(&rule->unixname, unixname);
541 	if (retcode != IDMAP_SUCCESS)
542 		goto errout;
543 
544 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
545 	    OP_RM_NAMERULE;
546 	udthandle->next++;
547 	return (IDMAP_SUCCESS);
548 
549 errout:
550 	if (rule)
551 		(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
552 	errno = idmap_stat2errno(retcode);
553 	return (retcode);
554 }
555 
556 
557 /* ARGSUSED */
558 idmap_stat
559 idmap_udt_flush_namerules(idmap_udt_handle_t *udthandle, boolean_t is_user) {
560 	idmap_retcode	retcode;
561 
562 	retcode = _udt_extend_batch(udthandle);
563 	if (retcode != IDMAP_SUCCESS)
564 		goto errout;
565 
566 	udthandle->batch.idmap_update_batch_val[udthandle->next].
567 		idmap_update_op_u.is_user = is_user;
568 
569 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
570 	    OP_FLUSH_NAMERULES;
571 	udthandle->next++;
572 	return (IDMAP_SUCCESS);
573 
574 errout:
575 	errno = idmap_stat2errno(retcode);
576 	return (retcode);
577 }
578 
579 
580 /*
581  * Set the number of entries requested per batch by the iterator
582  *
583  * Input:
584  * iter  - iterator
585  * limit - number of entries requested per batch
586  */
587 idmap_stat
588 idmap_iter_set_limit(idmap_iter_t *iter, uint64_t limit) {
589 	if (iter == NULL) {
590 		errno = EINVAL;
591 		return (IDMAP_ERR_ARG);
592 	}
593 	iter->limit = limit;
594 	return (IDMAP_SUCCESS);
595 }
596 
597 
598 /*
599  * Create iterator to get name-based mapping rules
600  *
601  * Input:
602  * windomain - Windows domain
603  * is_user   - user or group rules
604  * winname   - Windows user or group name
605  * unixname  - Unix user or group name
606  *
607  * Output:
608  * iter - iterator
609  */
610 idmap_stat
611 idmap_iter_namerules(idmap_handle_t *handle, const char *windomain,
612 		boolean_t is_user, const char *winname,
613 		const char *unixname, idmap_iter_t **iter) {
614 
615 	idmap_iter_t			*tmpiter;
616 	idmap_list_namerules_1_argument	*arg = NULL;
617 	idmap_namerule			*rule;
618 	idmap_retcode			retcode;
619 
620 	__ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_NAMERULES);
621 
622 	rule = &arg->rule;
623 	rule->is_user = is_user;
624 	rule->direction = IDMAP_DIRECTION_UNDEF;
625 
626 	retcode = idmap_strdupnull(&rule->windomain, windomain);
627 	if (retcode != IDMAP_SUCCESS)
628 		goto errout;
629 
630 	retcode = idmap_strdupnull(&rule->winname, winname);
631 	if (retcode != IDMAP_SUCCESS)
632 		goto errout;
633 
634 	retcode = idmap_strdupnull(&rule->unixname, unixname);
635 	if (retcode != IDMAP_SUCCESS)
636 		goto errout;
637 
638 	*iter = tmpiter;
639 	return (IDMAP_SUCCESS);
640 
641 errout:
642 	__ITER_ERR_RETURN(tmpiter, arg,
643 		xdr_idmap_list_namerules_1_argument, retcode);
644 }
645 
646 
647 /*
648  * Iterate through the name-based mapping rules
649  *
650  * Input:
651  * iter - iterator
652  *
653  * Output:
654  * windomain - Windows domain
655  * winname   - Windows user or group name
656  * unixname  - Unix user or group name
657  * is_nt4    - NT4 or AD
658  * direction - bi(0), win2unix(1), unix2win(2)
659  *
660  * Return value:
661  * 0   - done
662  * 1   - more results available
663  * < 0 - error
664  */
665 idmap_stat
666 idmap_iter_next_namerule(idmap_iter_t *iter, char **windomain,
667 		char **winname, char **unixname, boolean_t *is_nt4,
668 		int *direction) {
669 	idmap_namerules_res		*namerules;
670 	idmap_list_namerules_1_argument	*arg;
671 	idmap_retcode			retcode;
672 
673 	if (windomain)
674 		*windomain = NULL;
675 	if (winname)
676 		*winname = NULL;
677 	if (unixname)
678 		*unixname = NULL;
679 	if (is_nt4)
680 		*is_nt4 = 0;
681 	if (direction)
682 		*direction = IDMAP_DIRECTION_UNDEF;
683 
684 	__ITER_CHECK(iter, IDMAP_LIST_NAMERULES);
685 
686 	namerules = (idmap_namerules_res *)iter->retlist;
687 	if (iter->retcode == IDMAP_NEXT && (namerules == NULL ||
688 			iter->next >= namerules->rules.rules_len)) {
689 
690 		if ((arg = iter->arg) == NULL) {
691 			errno = EINVAL;
692 			return (IDMAP_ERR_ARG);
693 		}
694 		arg->limit = iter->limit;
695 
696 		retcode = _iter_get_next_list(IDMAP_LIST_NAMERULES,
697 			iter, arg,
698 			(uchar_t **)&namerules, sizeof (*namerules),
699 			(xdrproc_t)xdr_idmap_list_namerules_1_argument,
700 			(xdrproc_t)xdr_idmap_namerules_res);
701 		if (retcode != IDMAP_SUCCESS)
702 			return (retcode);
703 
704 		if (IDMAP_ERROR(namerules->retcode)) {
705 			retcode  = namerules->retcode;
706 			xdr_free(xdr_idmap_namerules_res, (caddr_t)namerules);
707 			free(namerules);
708 			iter->retlist = NULL;
709 			return (retcode);
710 		}
711 		iter->retcode = namerules->retcode;
712 		arg->lastrowid = namerules->lastrowid;
713 	}
714 
715 	if (namerules == NULL || namerules->rules.rules_len == 0)
716 		return (IDMAP_SUCCESS);
717 
718 	if (iter->next >= namerules->rules.rules_len) {
719 		return (IDMAP_ERR_ARG);
720 	}
721 
722 	retcode = idmap_strdupnull(windomain,
723 	    namerules->rules.rules_val[iter->next].windomain);
724 	if (retcode != IDMAP_SUCCESS)
725 		goto errout;
726 
727 	retcode = idmap_strdupnull(winname,
728 	    namerules->rules.rules_val[iter->next].winname);
729 	if (retcode != IDMAP_SUCCESS)
730 		goto errout;
731 
732 	retcode = idmap_strdupnull(unixname,
733 	    namerules->rules.rules_val[iter->next].unixname);
734 	if (retcode != IDMAP_SUCCESS)
735 		goto errout;
736 
737 	if (is_nt4)
738 		*is_nt4 = namerules->rules.rules_val[iter->next].is_nt4;
739 	if (direction)
740 		*direction = namerules->rules.rules_val[iter->next].direction;
741 	iter->next++;
742 
743 	if (iter->next == namerules->rules.rules_len)
744 		return (iter->retcode);
745 	else
746 		return (IDMAP_NEXT);
747 
748 errout:
749 	if (windomain && *windomain)
750 		free(*windomain);
751 	if (winname && *winname)
752 		free(*winname);
753 	if (unixname && *unixname)
754 		free(*unixname);
755 	return (retcode);
756 }
757 
758 
759 /*
760  * Create iterator to get SID to UID/GID mappings
761  *
762  * Input:
763  * is_user - user or group
764  *
765  * Output:
766  * iter - iterator
767  */
768 idmap_stat
769 idmap_iter_mappings(idmap_handle_t *handle, boolean_t is_user,
770 		idmap_iter_t **iter) {
771 	idmap_iter_t			*tmpiter;
772 	idmap_list_mappings_1_argument	*arg = NULL;
773 
774 	__ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_MAPPINGS);
775 
776 	arg->is_user = is_user;
777 	*iter = tmpiter;
778 	return (IDMAP_SUCCESS);
779 }
780 
781 
782 /*
783  * Iterate through the SID to UID/GID mappings
784  *
785  * Input:
786  * iter - iterator
787  *
788  * Output:
789  * sid - SID in canonical form
790  * pid - UID or GID
791  *
792  * Return value:
793  * 0   - done
794  * 1   - more results available
795  * < 0 - error
796  */
797 idmap_stat
798 idmap_iter_next_mapping(idmap_iter_t *iter, char **sidprefix,
799 		idmap_rid_t *rid, uid_t *pid, char **winname,
800 		char **windomain, char **unixname, int *direction) {
801 	idmap_mappings_res		*mappings;
802 	idmap_list_mappings_1_argument	*arg;
803 	idmap_retcode			retcode;
804 	char				*str;
805 
806 	if (sidprefix)
807 		*sidprefix = NULL;
808 	if (rid)
809 		*rid = UINT32_MAX;
810 	if (winname)
811 		*winname = NULL;
812 	if (windomain)
813 		*windomain = NULL;
814 	if (unixname)
815 		*unixname = NULL;
816 	if (pid)
817 		*pid = UINT32_MAX;
818 	if (direction)
819 		*direction = IDMAP_DIRECTION_UNDEF;
820 
821 	__ITER_CHECK(iter, IDMAP_LIST_MAPPINGS);
822 
823 	mappings = (idmap_mappings_res *)iter->retlist;
824 	if (iter->retcode == IDMAP_NEXT && (mappings == NULL ||
825 			iter->next >= mappings->mappings.mappings_len)) {
826 
827 		if ((arg = iter->arg) == NULL) {
828 			errno = EINVAL;
829 			return (IDMAP_ERR_ARG);
830 		}
831 		arg->limit = iter->limit;
832 
833 		retcode = _iter_get_next_list(IDMAP_LIST_MAPPINGS,
834 			iter, arg,
835 			(uchar_t **)&mappings, sizeof (*mappings),
836 			(xdrproc_t)xdr_idmap_list_mappings_1_argument,
837 			(xdrproc_t)xdr_idmap_mappings_res);
838 		if (retcode != IDMAP_SUCCESS)
839 			return (retcode);
840 
841 		if (IDMAP_ERROR(mappings->retcode)) {
842 			retcode  = mappings->retcode;
843 			xdr_free(xdr_idmap_mappings_res, (caddr_t)mappings);
844 			free(mappings);
845 			iter->retlist = NULL;
846 			return (retcode);
847 		}
848 		iter->retcode = mappings->retcode;
849 		arg->lastrowid = mappings->lastrowid;
850 	}
851 
852 	if (mappings == NULL || mappings->mappings.mappings_len == 0)
853 		return (IDMAP_SUCCESS);
854 
855 	if (iter->next >= mappings->mappings.mappings_len) {
856 		return (IDMAP_ERR_ARG);
857 	}
858 
859 	if (sidprefix) {
860 		str = mappings->mappings.mappings_val[iter->next].id1.
861 			idmap_id_u.sid.prefix;
862 		if (str && *str != '\0') {
863 			*sidprefix = strdup(str);
864 			if (*sidprefix == NULL) {
865 				retcode = IDMAP_ERR_MEMORY;
866 				goto errout;
867 			}
868 		}
869 	}
870 	if (rid)
871 		*rid = mappings->mappings.mappings_val[iter->next].id1.
872 			idmap_id_u.sid.rid;
873 
874 	retcode = idmap_strdupnull(windomain,
875 	    mappings->mappings.mappings_val[iter->next].id1domain);
876 	if (retcode != IDMAP_SUCCESS)
877 		goto errout;
878 
879 	retcode = idmap_strdupnull(winname,
880 	    mappings->mappings.mappings_val[iter->next].id1name);
881 	if (retcode != IDMAP_SUCCESS)
882 		goto errout;
883 
884 	retcode = idmap_strdupnull(unixname,
885 	    mappings->mappings.mappings_val[iter->next].id2name);
886 	if (retcode != IDMAP_SUCCESS)
887 		goto errout;
888 
889 
890 	if (pid)
891 		*pid = mappings->mappings.mappings_val[iter->next].id2.
892 			idmap_id_u.uid;
893 	if (direction)
894 		*direction = mappings->mappings.mappings_val[iter->next].
895 			direction;
896 	iter->next++;
897 
898 	if (iter->next == mappings->mappings.mappings_len)
899 		return (iter->retcode);
900 	else
901 		return (IDMAP_NEXT);
902 
903 errout:
904 	if (sidprefix && *sidprefix)
905 		free(*sidprefix);
906 	if (winname && *winname)
907 		free(*winname);
908 	if (windomain && *windomain)
909 		free(*windomain);
910 	if (unixname && *unixname)
911 		free(*unixname);
912 	return (retcode);
913 }
914 
915 
916 /*
917  * Destroy the iterator
918  */
919 void
920 idmap_iter_destroy(idmap_iter_t *iter) {
921 	xdrproc_t _xdr_argument, _xdr_result;
922 
923 	if (iter == NULL)
924 		return;
925 
926 	switch (iter->type) {
927 	case IDMAP_LIST_NAMERULES:
928 		_xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
929 		_xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
930 		break;
931 	case IDMAP_LIST_MAPPINGS:
932 		_xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
933 		_xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
934 		break;
935 	default:
936 		free(iter);
937 		return;
938 	};
939 
940 	if (iter->arg) {
941 		xdr_free(_xdr_argument, (caddr_t)iter->arg);
942 		free(iter->arg);
943 	}
944 	if (iter->retlist) {
945 		xdr_free(_xdr_result, (caddr_t)iter->retlist);
946 		free(iter->retlist);
947 	}
948 	free(iter);
949 }
950 
951 
952 /*
953  * Create handle to get SID to UID/GID mapping entries
954  *
955  * Input:
956  * gh - "get mapping" handle
957  */
958 idmap_stat
959 idmap_get_create(idmap_handle_t *handle, idmap_get_handle_t **gh) {
960 	idmap_get_handle_t	*tmp;
961 
962 	/* sanity checks */
963 	if (handle == NULL || gh == NULL) {
964 		errno = EINVAL;
965 		return (IDMAP_ERR_ARG);
966 	}
967 
968 	/* allocate the handle */
969 	if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
970 		errno = ENOMEM;
971 		return (IDMAP_ERR_MEMORY);
972 	}
973 
974 	tmp->ih = handle;
975 	*gh = tmp;
976 	return (IDMAP_SUCCESS);
977 }
978 
979 
980 /*
981  * Given SID, get UID
982  *
983  * Input:
984  * sidprefix  - SID prefix
985  * rid        - RID
986  * flag       - flag
987  *
988  * Output:
989  * stat - status of the get request
990  * uid  - POSIX UID if stat = 0
991  *
992  * Note: The output parameters will be set by idmap_get_mappings()
993  */
994 idmap_stat
995 idmap_get_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
996 		int flag, uid_t *uid, idmap_stat *stat) {
997 
998 	idmap_retcode	retcode;
999 	idmap_mapping	*mapping = NULL;
1000 
1001 	/* sanity checks */
1002 	if (gh == NULL)
1003 		return (IDMAP_ERR_ARG);
1004 	if (uid == NULL || sidprefix == NULL)
1005 		return (IDMAP_ERR_ARG);
1006 
1007 	/* Extend the request array and the return list */
1008 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1009 		goto errout;
1010 
1011 	/* Setup the request */
1012 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1013 	mapping->flag = flag;
1014 	mapping->id1.idtype = IDMAP_SID;
1015 	mapping->id1.idmap_id_u.sid.rid = rid;
1016 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1017 		retcode = IDMAP_ERR_MEMORY;
1018 		goto errout;
1019 	}
1020 	mapping->id2.idtype = IDMAP_UID;
1021 
1022 	/* Setup pointers for the result */
1023 	gh->retlist[gh->next].idtype = IDMAP_UID;
1024 	gh->retlist[gh->next].uid = uid;
1025 	gh->retlist[gh->next].stat = stat;
1026 
1027 	gh->next++;
1028 	return (IDMAP_SUCCESS);
1029 
1030 errout:
1031 	/* Batch created so far should still be usable */
1032 	if (mapping)
1033 		(void) memset(mapping, 0, sizeof (*mapping));
1034 	errno = idmap_stat2errno(retcode);
1035 	return (retcode);
1036 }
1037 
1038 
1039 /*
1040  * Given SID, get GID
1041  *
1042  * Input:
1043  * sidprefix  - SID prefix
1044  * rid        - rid
1045  * flag       - flag
1046  *
1047  * Output:
1048  * stat - status of the get request
1049  * gid  - POSIX GID if stat = 0
1050  *
1051  * Note: The output parameters will be set by idmap_get_mappings()
1052  */
1053 idmap_stat
1054 idmap_get_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1055 		int flag, gid_t *gid, idmap_stat *stat) {
1056 
1057 	idmap_retcode	retcode;
1058 	idmap_mapping	*mapping = NULL;
1059 
1060 	/* sanity checks */
1061 	if (gh == NULL)
1062 		return (IDMAP_ERR_ARG);
1063 	if (gid == NULL || sidprefix == NULL)
1064 		return (IDMAP_ERR_ARG);
1065 
1066 	/* Extend the request array and the return list */
1067 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1068 		goto errout;
1069 
1070 	/* Setup the request */
1071 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1072 	mapping->flag = flag;
1073 	mapping->id1.idtype = IDMAP_SID;
1074 	mapping->id1.idmap_id_u.sid.rid = rid;
1075 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1076 		retcode = IDMAP_ERR_MEMORY;
1077 		goto errout;
1078 	}
1079 	mapping->id2.idtype = IDMAP_GID;
1080 
1081 	/* Setup pointers for the result */
1082 	gh->retlist[gh->next].idtype = IDMAP_GID;
1083 	gh->retlist[gh->next].gid = gid;
1084 	gh->retlist[gh->next].stat = stat;
1085 
1086 	gh->next++;
1087 	return (IDMAP_SUCCESS);
1088 
1089 errout:
1090 	if (mapping)
1091 		(void) memset(mapping, 0, sizeof (*mapping));
1092 	errno = idmap_stat2errno(retcode);
1093 	return (retcode);
1094 }
1095 
1096 
1097 /*
1098  * Given SID, get POSIX ID i.e. UID/GID
1099  *
1100  * Input:
1101  * sidprefix  - SID prefix
1102  * rid        - rid
1103  * flag       - flag
1104  *
1105  * Output:
1106  * stat    - status of the get request
1107  * is_user - user or group
1108  * pid     - POSIX UID if stat = 0 and is_user = 1
1109  *           POSIX GID if stat = 0 and is_user = 0
1110  *
1111  * Note: The output parameters will be set by idmap_get_mappings()
1112  */
1113 idmap_stat
1114 idmap_get_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1115 		int flag, uid_t *pid, int *is_user, idmap_stat *stat) {
1116 	idmap_retcode	retcode;
1117 	idmap_mapping	*mapping = NULL;
1118 
1119 	/* sanity checks */
1120 	if (gh == NULL)
1121 		return (IDMAP_ERR_ARG);
1122 	if (pid == NULL || sidprefix == NULL || is_user == NULL)
1123 		return (IDMAP_ERR_ARG);
1124 
1125 	/* Extend the request array and the return list */
1126 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1127 		goto errout;
1128 
1129 	/* Setup the request */
1130 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1131 	mapping->flag = flag;
1132 	mapping->id1.idtype = IDMAP_SID;
1133 	mapping->id1.idmap_id_u.sid.rid = rid;
1134 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1135 		retcode = IDMAP_ERR_MEMORY;
1136 		goto errout;
1137 	}
1138 	mapping->id2.idtype = IDMAP_POSIXID;
1139 
1140 	/* Setup pointers for the result */
1141 	gh->retlist[gh->next].idtype = IDMAP_POSIXID;
1142 	gh->retlist[gh->next].uid = pid;
1143 	gh->retlist[gh->next].gid = pid;
1144 	gh->retlist[gh->next].is_user = is_user;
1145 	gh->retlist[gh->next].stat = stat;
1146 
1147 	gh->next++;
1148 	return (IDMAP_SUCCESS);
1149 
1150 errout:
1151 	if (mapping)
1152 		(void) memset(mapping, 0, sizeof (*mapping));
1153 	errno = idmap_stat2errno(retcode);
1154 	return (retcode);
1155 }
1156 
1157 
1158 /*
1159  * Given UID, get SID
1160  *
1161  * Input:
1162  * uid  - POSIX UID
1163  * flag - flag
1164  *
1165  * Output:
1166  * stat - status of the get request
1167  * sid  - SID prefix (if stat == 0)
1168  * rid  - rid
1169  *
1170  * Note: The output parameters will be set by idmap_get_mappings()
1171  */
1172 idmap_stat
1173 idmap_get_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
1174 		char **sidprefix, idmap_rid_t *rid, idmap_stat *stat) {
1175 
1176 	idmap_retcode	retcode;
1177 	idmap_mapping	*mapping = NULL;
1178 
1179 	/* sanity checks */
1180 	if (gh == NULL)
1181 		return (IDMAP_ERR_ARG);
1182 	if (sidprefix == NULL)
1183 		return (IDMAP_ERR_ARG);
1184 
1185 	/* Extend the request array and the return list */
1186 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1187 		goto errout;
1188 
1189 	/* Setup the request */
1190 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1191 	mapping->flag = flag;
1192 	mapping->id1.idtype = IDMAP_UID;
1193 	mapping->id1.idmap_id_u.uid = uid;
1194 	mapping->id2.idtype = IDMAP_SID;
1195 
1196 	/* Setup pointers for the result */
1197 	gh->retlist[gh->next].idtype = IDMAP_SID;
1198 	gh->retlist[gh->next].sidprefix = sidprefix;
1199 	gh->retlist[gh->next].rid = rid;
1200 	gh->retlist[gh->next].stat = stat;
1201 
1202 	gh->next++;
1203 	return (IDMAP_SUCCESS);
1204 
1205 errout:
1206 	if (mapping)
1207 		(void) memset(mapping, 0, sizeof (*mapping));
1208 	errno = idmap_stat2errno(retcode);
1209 	return (retcode);
1210 }
1211 
1212 
1213 /*
1214  * Given GID, get SID
1215  *
1216  * Input:
1217  * gid  - POSIX GID
1218  * flag - flag
1219  *
1220  * Output:
1221  * stat       - status of the get request
1222  * sidprefix  - SID prefix (if stat == 0)
1223  * rid        - rid
1224  *
1225  * Note: The output parameters will be set by idmap_get_mappings()
1226  */
1227 idmap_stat
1228 idmap_get_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
1229 		char **sidprefix, idmap_rid_t *rid, idmap_stat *stat) {
1230 
1231 	idmap_retcode	retcode;
1232 	idmap_mapping	*mapping = NULL;
1233 
1234 	/* sanity checks */
1235 	if (gh == NULL)
1236 		return (IDMAP_ERR_ARG);
1237 	if (sidprefix == NULL)
1238 		return (IDMAP_ERR_ARG);
1239 
1240 	/* Extend the request array and the return list */
1241 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1242 		goto errout;
1243 
1244 	/* Setup the request */
1245 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1246 	mapping->flag = flag;
1247 	mapping->id1.idtype = IDMAP_GID;
1248 	mapping->id1.idmap_id_u.gid = gid;
1249 	mapping->id2.idtype = IDMAP_SID;
1250 
1251 	/* Setup pointers for the result */
1252 	gh->retlist[gh->next].idtype = IDMAP_SID;
1253 	gh->retlist[gh->next].sidprefix = sidprefix;
1254 	gh->retlist[gh->next].rid = rid;
1255 	gh->retlist[gh->next].stat = stat;
1256 
1257 	gh->next++;
1258 	return (IDMAP_SUCCESS);
1259 
1260 errout:
1261 	if (mapping)
1262 		(void) memset(mapping, 0, sizeof (*mapping));
1263 	errno = idmap_stat2errno(retcode);
1264 	return (retcode);
1265 }
1266 
1267 
1268 /*
1269  * Process the batched "get mapping" requests. The results (i.e.
1270  * status and identity) will be available in the data areas
1271  * provided by individual requests.
1272  */
1273 idmap_stat
1274 idmap_get_mappings(idmap_get_handle_t *gh) {
1275 	CLIENT		*clnt;
1276 	enum clnt_stat	clntstat;
1277 	idmap_retcode	retcode;
1278 	idmap_ids_res	res;
1279 	idmap_id	*id;
1280 	int		i;
1281 
1282 	if (gh == NULL) {
1283 		errno = EINVAL;
1284 		return (IDMAP_ERR_ARG);
1285 	}
1286 	_IDMAP_GET_CLIENT_HANDLE(gh->ih, clnt);
1287 
1288 	(void) memset(&res, 0, sizeof (idmap_ids_res));
1289 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_IDS,
1290 		(xdrproc_t)xdr_idmap_mapping_batch,
1291 		(caddr_t)&gh->batch,
1292 		(xdrproc_t)xdr_idmap_ids_res,
1293 		(caddr_t)&res,
1294 		TIMEOUT);
1295 	if (clntstat != RPC_SUCCESS) {
1296 		retcode = _idmap_rpc2stat(clnt);
1297 		goto out;
1298 	}
1299 	if (res.retcode != IDMAP_SUCCESS) {
1300 		retcode = res.retcode;
1301 		goto out;
1302 	}
1303 	for (i = 0; i < gh->next; i++) {
1304 		if (i >= res.ids.ids_len) {
1305 			*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1306 			continue;
1307 		}
1308 		*gh->retlist[i].stat = res.ids.ids_val[i].retcode;
1309 		id = &res.ids.ids_val[i].id;
1310 		switch (id->idtype) {
1311 		case IDMAP_UID:
1312 			if (gh->retlist[i].uid)
1313 				*gh->retlist[i].uid = id->idmap_id_u.uid;
1314 			if (gh->retlist[i].is_user)
1315 				*gh->retlist[i].is_user = 1;
1316 			break;
1317 		case IDMAP_GID:
1318 			if (gh->retlist[i].gid)
1319 				*gh->retlist[i].gid = id->idmap_id_u.gid;
1320 			if (gh->retlist[i].is_user)
1321 				*gh->retlist[i].is_user = 0;
1322 			break;
1323 		case IDMAP_POSIXID:
1324 			if (gh->retlist[i].uid)
1325 				*gh->retlist[i].uid = 60001;
1326 			if (gh->retlist[i].is_user)
1327 				*gh->retlist[i].is_user = -1;
1328 			break;
1329 		case IDMAP_SID:
1330 			if (gh->retlist[i].rid)
1331 				*gh->retlist[i].rid = id->idmap_id_u.sid.rid;
1332 			if (gh->retlist[i].sidprefix) {
1333 				if (id->idmap_id_u.sid.prefix == NULL ||
1334 				    *id->idmap_id_u.sid.prefix == '\0') {
1335 					*gh->retlist[i].sidprefix = NULL;
1336 					break;
1337 				}
1338 				*gh->retlist[i].sidprefix =
1339 					strdup(id->idmap_id_u.sid.prefix);
1340 				if (*gh->retlist[i].sidprefix == NULL)
1341 					*gh->retlist[i].stat =
1342 						IDMAP_ERR_MEMORY;
1343 			}
1344 			break;
1345 		case IDMAP_NONE:
1346 			break;
1347 		default:
1348 			*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1349 			break;
1350 		}
1351 	}
1352 	retcode = IDMAP_SUCCESS;
1353 
1354 out:
1355 	_IDMAP_RESET_GET_HANDLE(gh);
1356 	(void) xdr_free(xdr_idmap_ids_res, (caddr_t)&res);
1357 	errno = idmap_stat2errno(retcode);
1358 	return (retcode);
1359 }
1360 
1361 
1362 /*
1363  * Destroy the "get mapping" handle
1364  */
1365 void
1366 idmap_get_destroy(idmap_get_handle_t *gh) {
1367 	if (gh == NULL)
1368 		return;
1369 	(void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
1370 	if (gh->retlist)
1371 		free(gh->retlist);
1372 	free(gh);
1373 }
1374 
1375 
1376 /*
1377  * Get windows to unix mapping
1378  */
1379 idmap_stat
1380 idmap_get_w2u_mapping(idmap_handle_t *handle,
1381 		const char *sidprefix, idmap_rid_t *rid,
1382 		const char *winname, const char *windomain,
1383 		int flag, int *is_user,
1384 		uid_t *pid, char **unixname, int *direction) {
1385 	CLIENT			*clnt;
1386 	enum clnt_stat		clntstat;
1387 	idmap_mapping		request, *mapping;
1388 	idmap_mappings_res	result;
1389 	idmap_retcode		retcode, rc;
1390 
1391 	if (handle == NULL) {
1392 		errno = EINVAL;
1393 		return (IDMAP_ERR_ARG);
1394 	}
1395 
1396 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1397 
1398 	(void) memset(&request, 0, sizeof (request));
1399 	(void) memset(&result, 0, sizeof (result));
1400 
1401 	if (is_user)
1402 		*is_user = -1;
1403 	if (pid)
1404 		*pid = UINT32_MAX;
1405 	if (unixname)
1406 		*unixname = NULL;
1407 	if (direction)
1408 		*direction = IDMAP_DIRECTION_UNDEF;
1409 
1410 	request.flag = flag;
1411 	request.id1.idtype = IDMAP_SID;
1412 	if (sidprefix && rid) {
1413 		request.id1.idmap_id_u.sid.prefix = (char *)sidprefix;
1414 		request.id1.idmap_id_u.sid.rid = *rid;
1415 	} else if (winname) {
1416 		retcode = idmap_strdupnull(&request.id1name, winname);
1417 		if (retcode != SUCCESS)
1418 			goto out;
1419 
1420 		retcode = idmap_strdupnull(&request.id1domain, windomain);
1421 		if (retcode != SUCCESS)
1422 			goto out;
1423 
1424 		request.id1.idmap_id_u.sid.prefix = NULL;
1425 	} else {
1426 		errno = EINVAL;
1427 		return (IDMAP_ERR_ARG);
1428 	}
1429 
1430 	if (is_user == NULL)
1431 		request.id2.idtype = IDMAP_POSIXID;
1432 	else if (*is_user == 1)
1433 		request.id2.idtype = IDMAP_UID;
1434 	else if (*is_user == 0)
1435 		request.id2.idtype = IDMAP_GID;
1436 	else
1437 		request.id2.idtype = IDMAP_POSIXID;
1438 
1439 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1440 		(xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1441 		(xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1442 		TIMEOUT);
1443 
1444 	if (clntstat != RPC_SUCCESS)
1445 		return (_idmap_rpc2stat(clnt));
1446 
1447 	retcode = result.retcode;
1448 
1449 	if ((mapping = result.mappings.mappings_val) == NULL) {
1450 		if (retcode == IDMAP_SUCCESS)
1451 			retcode = IDMAP_ERR_NORESULT;
1452 		goto out;
1453 	}
1454 
1455 	if (mapping->id2.idtype == IDMAP_UID) {
1456 		if (is_user) *is_user = 1;
1457 	} else if (mapping->id2.idtype == IDMAP_GID) {
1458 		if (is_user) *is_user = 0;
1459 	} else {
1460 		goto out;
1461 	}
1462 	if (direction)
1463 		*direction = mapping->direction;
1464 	if (pid)
1465 		*pid = mapping->id2.idmap_id_u.uid;
1466 
1467 	rc = idmap_strdupnull(unixname, mapping->id2name);
1468 	if (rc != IDMAP_SUCCESS)
1469 		retcode = rc;
1470 
1471 out:
1472 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1473 	if (retcode != IDMAP_SUCCESS)
1474 		errno = idmap_stat2errno(retcode);
1475 	return (retcode);
1476 }
1477 
1478 
1479 /*
1480  * Get unix to windows mapping
1481  */
1482 idmap_stat
1483 idmap_get_u2w_mapping(idmap_handle_t *handle,
1484 		uid_t *pid, const char *unixname,
1485 		int flag, int is_user,
1486 		char **sidprefix, idmap_rid_t *rid,
1487 		char **winname, char **windomain,
1488 		int *direction) {
1489 	CLIENT			*clnt;
1490 	enum clnt_stat		clntstat;
1491 	idmap_mapping		request, *mapping;
1492 	idmap_mappings_res	result;
1493 	idmap_retcode		retcode, rc;
1494 
1495 	if (handle == NULL) {
1496 		errno = EINVAL;
1497 		return (IDMAP_ERR_ARG);
1498 	}
1499 
1500 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1501 
1502 	if (sidprefix)
1503 		*sidprefix = NULL;
1504 	if (winname)
1505 		*winname = NULL;
1506 	if (windomain)
1507 		*windomain = NULL;
1508 	if (rid)
1509 		*rid = UINT32_MAX;
1510 	if (direction)
1511 		*direction = IDMAP_DIRECTION_UNDEF;
1512 
1513 	(void) memset(&request, 0, sizeof (request));
1514 	(void) memset(&result, 0, sizeof (result));
1515 
1516 	request.flag = flag;
1517 	request.id1.idtype = is_user?IDMAP_UID:IDMAP_GID;
1518 
1519 	if (pid && *pid != UINT32_MAX) {
1520 		request.id1.idmap_id_u.uid = *pid;
1521 	} else if (unixname) {
1522 		request.id1name = (char *)unixname;
1523 		request.id1.idmap_id_u.uid = UINT32_MAX;
1524 	} else {
1525 		errno = EINVAL;
1526 		return (IDMAP_ERR_ARG);
1527 	}
1528 
1529 	request.id2.idtype = IDMAP_SID;
1530 
1531 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1532 		(xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1533 		(xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1534 		TIMEOUT);
1535 
1536 	if (clntstat != RPC_SUCCESS)
1537 		return (_idmap_rpc2stat(clnt));
1538 
1539 	retcode = result.retcode;
1540 
1541 	if ((mapping = result.mappings.mappings_val) == NULL) {
1542 		if (retcode == IDMAP_SUCCESS)
1543 			retcode = IDMAP_ERR_NORESULT;
1544 		goto out;
1545 	}
1546 
1547 	if (direction)
1548 		*direction = mapping->direction;
1549 	if (sidprefix && mapping->id2.idmap_id_u.sid.prefix &&
1550 	    *mapping->id2.idmap_id_u.sid.prefix != '\0') {
1551 		*sidprefix = strdup(mapping->id2.idmap_id_u.sid.prefix);
1552 		if (*sidprefix == NULL) {
1553 			retcode = IDMAP_ERR_MEMORY;
1554 			goto errout;
1555 		}
1556 	}
1557 	if (rid)
1558 		*rid = mapping->id2.idmap_id_u.sid.rid;
1559 
1560 	rc = idmap_strdupnull(winname, mapping->id2name);
1561 	if (rc != IDMAP_SUCCESS)
1562 		retcode = rc;
1563 
1564 	rc = idmap_strdupnull(windomain, mapping->id2domain);
1565 	if (rc != IDMAP_SUCCESS)
1566 		retcode = rc;
1567 
1568 	goto out;
1569 
1570 errout:
1571 	if (sidprefix && *sidprefix) {
1572 		free(*sidprefix);
1573 		*sidprefix = NULL;
1574 	}
1575 	if (winname && *winname) {
1576 		free(*winname);
1577 		*winname = NULL;
1578 	}
1579 	if (windomain && *windomain) {
1580 		free(*windomain);
1581 		*windomain = NULL;
1582 	}
1583 
1584 out:
1585 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1586 	if (retcode != IDMAP_SUCCESS)
1587 		errno = idmap_stat2errno(retcode);
1588 	return (retcode);
1589 }
1590 
1591 
1592 
1593 #define	gettext(s)	s
1594 static stat_table_t stattable[] = {
1595 	{IDMAP_SUCCESS, gettext("Success"), 0},
1596 	{IDMAP_NEXT, gettext("More results available"), 0},
1597 	{IDMAP_ERR_OTHER, gettext("Undefined error"), EINVAL},
1598 	{IDMAP_ERR_INTERNAL, gettext("Internal error"), EINVAL},
1599 	{IDMAP_ERR_MEMORY, gettext("Out of memory"), ENOMEM},
1600 	{IDMAP_ERR_NORESULT, gettext("No results available"), EINVAL},
1601 	{IDMAP_ERR_NOTUSER, gettext("Not a user"), EINVAL},
1602 	{IDMAP_ERR_NOTGROUP, gettext("Not a group"), EINVAL},
1603 	{IDMAP_ERR_NOTSUPPORTED, gettext("Operation not supported"), ENOTSUP},
1604 	{IDMAP_ERR_W2U_NAMERULE,
1605 		gettext("Invalid Windows to UNIX name-based rule"), EINVAL},
1606 	{IDMAP_ERR_U2W_NAMERULE,
1607 		gettext("Invalid UNIX to Windows name-based rule"), EINVAL},
1608 	{IDMAP_ERR_CACHE, gettext("Invalid cache"), EINVAL},
1609 	{IDMAP_ERR_DB, gettext("Invalid database"), EINVAL},
1610 	{IDMAP_ERR_ARG, gettext("Invalid argument"), EINVAL},
1611 	{IDMAP_ERR_SID, gettext("Invalid SID"), EINVAL},
1612 	{IDMAP_ERR_IDTYPE, gettext("Invalid identity type"), EINVAL},
1613 	{IDMAP_ERR_RPC_HANDLE, gettext("Bad RPC handle"), EBADF},
1614 	{IDMAP_ERR_RPC, gettext("RPC error"), EINVAL},
1615 	{IDMAP_ERR_CLIENT_HANDLE, gettext("Bad client handle"), EINVAL},
1616 	{IDMAP_ERR_BUSY, gettext("Server is busy"), EBUSY},
1617 	{IDMAP_ERR_PERMISSION_DENIED, gettext("Permission denied"), EACCES},
1618 	{IDMAP_ERR_NOMAPPING,
1619 		gettext("Mapping not found or inhibited"), EINVAL},
1620 	{IDMAP_ERR_NEW_ID_ALLOC_REQD,
1621 		gettext("New mapping needs to be created"), EINVAL},
1622 	{IDMAP_ERR_DOMAIN, gettext("Invalid domain"), EINVAL},
1623 	{IDMAP_ERR_SECURITY, gettext("Security issue"), EINVAL},
1624 	{IDMAP_ERR_NOTFOUND, gettext("Not found"), EINVAL},
1625 	{IDMAP_ERR_DOMAIN_NOTFOUND, gettext("Domain not found"), EINVAL},
1626 	{IDMAP_ERR_UPDATE_NOTALLOWED, gettext("Update not allowed"), EINVAL},
1627 	{IDMAP_ERR_CFG, gettext("Configuration error"), EINVAL},
1628 	{IDMAP_ERR_CFG_CHANGE, gettext("Invalid configuration change"), EINVAL},
1629 	{IDMAP_ERR_NOTMAPPED_WELLKNOWN,
1630 		gettext("No mapping for well-known SID"), EINVAL},
1631 	{IDMAP_ERR_RETRIABLE_NET_ERR,
1632 		gettext("Windows lookup failed"), EINVAL},
1633 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
1634 		gettext("Duplicate rule or conflicts with an existing "
1635 		"Windows to UNIX name-based rule"), EINVAL},
1636 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
1637 		gettext("Duplicate rule or conflicts with an existing "
1638 		"Unix to Windows name-based rule"), EINVAL},
1639 	{-1, NULL, 0}
1640 };
1641 #undef	gettext
1642 
1643 
1644 /*
1645  * Get description of status code
1646  *
1647  * Input:
1648  * status - Status code returned by libidmap API call
1649  *
1650  * Return Value:
1651  * human-readable localized description of idmap_stat
1652  */
1653 /* ARGSUSED */
1654 const char *
1655 idmap_stat2string(idmap_handle_t *handle, idmap_stat status) {
1656 	int i;
1657 
1658 	for (i = 0; stattable[i].msg; i++) {
1659 		if (stattable[i].retcode == status)
1660 			return (gettext(stattable[i].msg));
1661 	}
1662 	return (gettext("Unknown error"));
1663 }
1664 
1665 
1666 static int
1667 idmap_stat2errno(idmap_stat stat) {
1668 	int i;
1669 	for (i = 0; stattable[i].msg; i++) {
1670 		if (stattable[i].retcode == stat)
1671 			return (stattable[i].errnum);
1672 	}
1673 	return (EINVAL);
1674 }
1675 
1676 
1677 /*
1678  * Get status code from string
1679  */
1680 idmap_stat
1681 idmap_string2stat(const char *str) {
1682 	if (str == NULL)
1683 		return (IDMAP_ERR_INTERNAL);
1684 
1685 #define	return_cmp(a) \
1686 	if (0 == strcmp(str, "IDMAP_ERR_" #a)) \
1687 		return (IDMAP_ERR_ ## a);
1688 
1689 	return_cmp(OTHER);
1690 	return_cmp(INTERNAL);
1691 	return_cmp(MEMORY);
1692 	return_cmp(NORESULT);
1693 	return_cmp(NOTUSER);
1694 	return_cmp(NOTGROUP);
1695 	return_cmp(NOTSUPPORTED);
1696 	return_cmp(W2U_NAMERULE);
1697 	return_cmp(U2W_NAMERULE);
1698 	return_cmp(CACHE);
1699 	return_cmp(DB);
1700 	return_cmp(ARG);
1701 	return_cmp(SID);
1702 	return_cmp(IDTYPE);
1703 	return_cmp(RPC_HANDLE);
1704 	return_cmp(RPC);
1705 	return_cmp(CLIENT_HANDLE);
1706 	return_cmp(BUSY);
1707 	return_cmp(PERMISSION_DENIED);
1708 	return_cmp(NOMAPPING);
1709 	return_cmp(NEW_ID_ALLOC_REQD);
1710 	return_cmp(DOMAIN);
1711 	return_cmp(SECURITY);
1712 	return_cmp(NOTFOUND);
1713 	return_cmp(DOMAIN_NOTFOUND);
1714 	return_cmp(MEMORY);
1715 	return_cmp(UPDATE_NOTALLOWED);
1716 	return_cmp(CFG);
1717 	return_cmp(CFG_CHANGE);
1718 	return_cmp(NOTMAPPED_WELLKNOWN);
1719 	return_cmp(RETRIABLE_NET_ERR);
1720 	return_cmp(W2U_NAMERULE_CONFLICT);
1721 	return_cmp(U2W_NAMERULE_CONFLICT);
1722 #undef return_cmp
1723 
1724 	return (IDMAP_ERR_OTHER);
1725 }
1726 
1727 
1728 /*
1729  * Map the given status to one that can be returned by the protocol
1730  */
1731 idmap_stat
1732 idmap_stat4prot(idmap_stat status) {
1733 	switch (status) {
1734 	case IDMAP_ERR_MEMORY:
1735 	case IDMAP_ERR_CACHE:
1736 		return (IDMAP_ERR_INTERNAL);
1737 	}
1738 	return (status);
1739 }
1740 
1741 
1742 /*
1743  * duplicate a string, possibly null
1744  */
1745 static idmap_stat
1746 idmap_strdupnull(char **to, const char *from) {
1747 	if (from == NULL || *from == '\0') {
1748 		*to = NULL;
1749 		return (IDMAP_SUCCESS);
1750 	}
1751 
1752 	*to = strdup(from);
1753 	if (*to == NULL)
1754 		return (IDMAP_ERR_MEMORY);
1755 	return (IDMAP_SUCCESS);
1756 }
1757 
1758 idmap_stat
1759 idmap_namerule_cpy(idmap_namerule *to, idmap_namerule *from) {
1760 	idmap_stat retval;
1761 
1762 	(void) memcpy(to, from, sizeof (idmap_namerule));
1763 
1764 	retval = idmap_strdupnull(&to->windomain, from->windomain);
1765 	if (retval != IDMAP_SUCCESS)
1766 		return (retval);
1767 
1768 	retval = idmap_strdupnull(&to->winname, from->winname);
1769 	if (retval != IDMAP_SUCCESS)
1770 		return (retval);
1771 
1772 	retval = idmap_strdupnull(&to->unixname, from->unixname);
1773 
1774 	return (retval);
1775 }
1776 
1777 
1778 /*
1779  * Get uid given Windows name
1780  */
1781 idmap_stat
1782 idmap_getuidbywinname(const char *name, const char *domain, uid_t *uid) {
1783 	idmap_handle_t	*ih;
1784 	idmap_retcode	rc;
1785 	int		is_user;
1786 
1787 	if (uid == NULL)
1788 		return (IDMAP_ERR_ARG);
1789 
1790 	/* Get mapping */
1791 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
1792 		return (rc);
1793 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, 0,
1794 	    &is_user, uid, NULL, NULL);
1795 	(void) idmap_fini(ih);
1796 
1797 	/*
1798 	 * XXX Until we have diagonal mapping support, check if
1799 	 * the given name belongs to a user
1800 	 */
1801 	if (rc == IDMAP_SUCCESS && !is_user)
1802 		return (IDMAP_ERR_NOTUSER);
1803 	return (rc);
1804 }
1805 
1806 
1807 /*
1808  * Get gid given Windows name
1809  */
1810 idmap_stat
1811 idmap_getgidbywinname(const char *name, const char *domain, gid_t *gid) {
1812 	idmap_handle_t	*ih;
1813 	idmap_retcode	rc;
1814 	int		is_user;
1815 
1816 	if (gid == NULL)
1817 		return (IDMAP_ERR_ARG);
1818 
1819 	/* Get mapping */
1820 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
1821 		return (rc);
1822 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, 0,
1823 	    &is_user, gid, NULL, NULL);
1824 	(void) idmap_fini(ih);
1825 
1826 	/*
1827 	 * XXX Until we have diagonal mapping support, check if
1828 	 * the given name belongs to a group
1829 	 */
1830 	if (rc == IDMAP_SUCCESS && is_user)
1831 		return (IDMAP_ERR_NOTGROUP);
1832 	return (rc);
1833 }
1834 
1835 
1836 /*
1837  * Get winname given pid
1838  */
1839 static idmap_retcode
1840 idmap_getwinnamebypid(uid_t pid, int is_user, char **name, char **domain) {
1841 	idmap_handle_t	*ih;
1842 	idmap_retcode	rc;
1843 	int		len;
1844 	char		*winname, *windomain;
1845 
1846 	if (name == NULL)
1847 		return (IDMAP_ERR_ARG);
1848 
1849 	/* Get mapping */
1850 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
1851 		return (rc);
1852 	rc = idmap_get_u2w_mapping(ih, &pid, NULL, 0, is_user, NULL,
1853 	    NULL, &winname, &windomain, NULL);
1854 	(void) idmap_fini(ih);
1855 
1856 	/* Return on error */
1857 	if (rc != IDMAP_SUCCESS)
1858 		return (rc);
1859 
1860 	/*
1861 	 * The given PID may have been mapped to a locally
1862 	 * generated SID in which case there isn't any
1863 	 * Windows name
1864 	 */
1865 	if (winname == NULL || windomain == NULL) {
1866 		idmap_free(winname);
1867 		idmap_free(windomain);
1868 		return (IDMAP_ERR_NORESULT);
1869 	}
1870 
1871 	if (domain != NULL) {
1872 		*name = winname;
1873 		*domain = windomain;
1874 	} else {
1875 		len = strlen(winname) + strlen(windomain) + 2;
1876 		if ((*name = malloc(len)) != NULL)
1877 			(void) snprintf(*name, len, "%s@%s", winname,
1878 			    windomain);
1879 		else
1880 			rc = IDMAP_ERR_MEMORY;
1881 		idmap_free(winname);
1882 		idmap_free(windomain);
1883 	}
1884 	return (rc);
1885 }
1886 
1887 
1888 /*
1889  * Get winname given uid
1890  */
1891 idmap_stat
1892 idmap_getwinnamebyuid(uid_t uid, char **name, char **domain) {
1893 	return (idmap_getwinnamebypid(uid, 1, name, domain));
1894 }
1895 
1896 
1897 /*
1898  * Get winname given gid
1899  */
1900 idmap_stat
1901 idmap_getwinnamebygid(gid_t gid, char **name, char **domain) {
1902 	return (idmap_getwinnamebypid(gid, 0, name, domain));
1903 }
1904