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