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