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