xref: /illumos-gate/usr/src/lib/libidmap/common/idmap_api.c (revision dd5829d1456ba00e6f704e6a88e7eaae608e3c1b)
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 && *str != '\0') {
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_POSIXID:
1124 			if (gh->retlist[i].uid)
1125 				*gh->retlist[i].uid = 60001;
1126 			if (gh->retlist[i].is_user)
1127 				*gh->retlist[i].is_user = -1;
1128 			break;
1129 		case IDMAP_SID:
1130 			if (gh->retlist[i].rid)
1131 				*gh->retlist[i].rid = id->idmap_id_u.sid.rid;
1132 			if (gh->retlist[i].sidprefix) {
1133 				if (id->idmap_id_u.sid.prefix == NULL ||
1134 				    *id->idmap_id_u.sid.prefix == '\0') {
1135 					*gh->retlist[i].sidprefix = NULL;
1136 					break;
1137 				}
1138 				*gh->retlist[i].sidprefix =
1139 					strdup(id->idmap_id_u.sid.prefix);
1140 				if (*gh->retlist[i].sidprefix == NULL)
1141 					*gh->retlist[i].stat =
1142 						IDMAP_ERR_MEMORY;
1143 			}
1144 			break;
1145 		case IDMAP_NONE:
1146 			break;
1147 		default:
1148 			*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1149 			break;
1150 		}
1151 	}
1152 	retcode = IDMAP_SUCCESS;
1153 
1154 out:
1155 	_IDMAP_RESET_GET_HANDLE(gh);
1156 	(void) xdr_free(xdr_idmap_ids_res, (caddr_t)&res);
1157 	errno = idmap_stat2errno(retcode);
1158 	return (retcode);
1159 }
1160 
1161 
1162 /*
1163  * Destroy the "get mapping" handle
1164  */
1165 void
1166 idmap_get_destroy(idmap_get_handle_t *gh) {
1167 	if (gh == NULL)
1168 		return;
1169 	(void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
1170 	if (gh->retlist)
1171 		free(gh->retlist);
1172 	free(gh);
1173 }
1174 
1175 
1176 /*
1177  * Get windows to unix mapping
1178  */
1179 idmap_stat
1180 idmap_get_w2u_mapping(idmap_handle_t *handle,
1181 		const char *sidprefix, idmap_rid_t *rid,
1182 		const char *winname, const char *windomain,
1183 		int flag, int *is_user,
1184 		uid_t *pid, char **unixname, int *direction) {
1185 	CLIENT			*clnt;
1186 	enum clnt_stat		clntstat;
1187 	idmap_mapping		request, *mapping;
1188 	idmap_mappings_res	result;
1189 	idmap_retcode		retcode, rc;
1190 	idmap_utf8str		*str;
1191 
1192 	if (handle == NULL) {
1193 		errno = EINVAL;
1194 		return (IDMAP_ERR_ARG);
1195 	}
1196 
1197 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1198 
1199 	(void) memset(&request, 0, sizeof (request));
1200 	(void) memset(&result, 0, sizeof (result));
1201 
1202 	if (is_user)
1203 		*is_user = -1;
1204 	if (pid)
1205 		*pid = UINT32_MAX;
1206 	if (unixname)
1207 		*unixname = NULL;
1208 	if (direction)
1209 		*direction = IDMAP_DIRECTION_UNDEF;
1210 
1211 	request.flag = flag;
1212 	request.id1.idtype = IDMAP_SID;
1213 	if (sidprefix && rid) {
1214 		request.id1.idmap_id_u.sid.prefix = (char *)sidprefix;
1215 		request.id1.idmap_id_u.sid.rid = *rid;
1216 	} else if (winname) {
1217 		str = &request.id1name;
1218 		retcode = idmap_str2utf8(&str, winname, 1);
1219 		if (retcode != IDMAP_SUCCESS)
1220 			goto out;
1221 		if (windomain) {
1222 			str = &request.id1domain;
1223 			retcode = idmap_str2utf8(&str, windomain, 1);
1224 			if (retcode != IDMAP_SUCCESS)
1225 				return (retcode);
1226 		}
1227 		request.id1.idmap_id_u.sid.prefix = NULL;
1228 	} else {
1229 		errno = EINVAL;
1230 		return (IDMAP_ERR_ARG);
1231 	}
1232 
1233 	if (is_user == NULL)
1234 		request.id2.idtype = IDMAP_POSIXID;
1235 	else if (*is_user == 1)
1236 		request.id2.idtype = IDMAP_UID;
1237 	else if (*is_user == 0)
1238 		request.id2.idtype = IDMAP_GID;
1239 	else
1240 		request.id2.idtype = IDMAP_POSIXID;
1241 
1242 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1243 		(xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1244 		(xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1245 		TIMEOUT);
1246 
1247 	if (clntstat != RPC_SUCCESS)
1248 		return (_idmap_rpc2stat(clnt));
1249 
1250 	retcode = result.retcode;
1251 
1252 	if ((mapping = result.mappings.mappings_val) == NULL) {
1253 		if (retcode == IDMAP_SUCCESS)
1254 			retcode = IDMAP_ERR_NORESULT;
1255 		goto out;
1256 	}
1257 
1258 	if (mapping->id2.idtype == IDMAP_UID) {
1259 		if (is_user) *is_user = 1;
1260 	} else if (mapping->id2.idtype == IDMAP_GID) {
1261 		if (is_user) *is_user = 0;
1262 	} else {
1263 		goto out;
1264 	}
1265 	if (direction)
1266 		*direction = mapping->direction;
1267 	if (pid)
1268 		*pid = mapping->id2.idmap_id_u.uid;
1269 	if (unixname) {
1270 		rc = idmap_utf82str(unixname, 0, &mapping->id2name);
1271 		if (rc != IDMAP_SUCCESS)
1272 			retcode = rc;
1273 	}
1274 
1275 out:
1276 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1277 	if (retcode != IDMAP_SUCCESS)
1278 		errno = idmap_stat2errno(retcode);
1279 	return (retcode);
1280 }
1281 
1282 
1283 /*
1284  * Get unix to windows mapping
1285  */
1286 idmap_stat
1287 idmap_get_u2w_mapping(idmap_handle_t *handle,
1288 		uid_t *pid, const char *unixname,
1289 		int flag, int is_user,
1290 		char **sidprefix, idmap_rid_t *rid,
1291 		char **winname, char **windomain,
1292 		int *direction) {
1293 	CLIENT			*clnt;
1294 	enum clnt_stat		clntstat;
1295 	idmap_mapping		request, *mapping;
1296 	idmap_mappings_res	result;
1297 	idmap_retcode		retcode, rc;
1298 	idmap_utf8str		*str;
1299 
1300 	if (handle == NULL) {
1301 		errno = EINVAL;
1302 		return (IDMAP_ERR_ARG);
1303 	}
1304 
1305 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1306 
1307 	if (sidprefix)
1308 		*sidprefix = NULL;
1309 	if (winname)
1310 		*winname = NULL;
1311 	if (windomain)
1312 		*windomain = NULL;
1313 	if (rid)
1314 		*rid = UINT32_MAX;
1315 	if (direction)
1316 		*direction = IDMAP_DIRECTION_UNDEF;
1317 
1318 	(void) memset(&request, 0, sizeof (request));
1319 	(void) memset(&result, 0, sizeof (result));
1320 
1321 	request.flag = flag;
1322 	request.id1.idtype = is_user?IDMAP_UID:IDMAP_GID;
1323 
1324 	if (pid && *pid != UINT32_MAX) {
1325 		request.id1.idmap_id_u.uid = *pid;
1326 	} else if (unixname) {
1327 		str = &request.id1name;
1328 		retcode = idmap_str2utf8(&str, unixname, 1);
1329 		if (retcode != IDMAP_SUCCESS)
1330 			goto out;
1331 		request.id1.idmap_id_u.uid = UINT32_MAX;
1332 	} else {
1333 		errno = EINVAL;
1334 		return (IDMAP_ERR_ARG);
1335 	}
1336 
1337 	request.id2.idtype = IDMAP_SID;
1338 
1339 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1340 		(xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1341 		(xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1342 		TIMEOUT);
1343 
1344 	if (clntstat != RPC_SUCCESS)
1345 		return (_idmap_rpc2stat(clnt));
1346 
1347 	retcode = result.retcode;
1348 
1349 	if ((mapping = result.mappings.mappings_val) == NULL) {
1350 		if (retcode == IDMAP_SUCCESS)
1351 			retcode = IDMAP_ERR_NORESULT;
1352 		goto out;
1353 	}
1354 
1355 	if (direction)
1356 		*direction = mapping->direction;
1357 	if (sidprefix && mapping->id2.idmap_id_u.sid.prefix &&
1358 	    *mapping->id2.idmap_id_u.sid.prefix != '\0') {
1359 		*sidprefix = strdup(mapping->id2.idmap_id_u.sid.prefix);
1360 		if (*sidprefix == NULL) {
1361 			retcode = IDMAP_ERR_MEMORY;
1362 			goto errout;
1363 		}
1364 	}
1365 	if (rid)
1366 		*rid = mapping->id2.idmap_id_u.sid.rid;
1367 	if (winname) {
1368 		rc = idmap_utf82str(winname, 0, &mapping->id2name);
1369 		if (rc != IDMAP_SUCCESS) {
1370 			retcode = rc;
1371 			goto errout;
1372 		}
1373 	}
1374 	if (windomain) {
1375 		rc = idmap_utf82str(windomain, 0, &mapping->id2domain);
1376 		if (rc != IDMAP_SUCCESS) {
1377 			retcode = rc;
1378 			goto errout;
1379 		}
1380 	}
1381 
1382 	goto out;
1383 
1384 errout:
1385 	if (sidprefix && *sidprefix) {
1386 		free(*sidprefix);
1387 		*sidprefix = NULL;
1388 	}
1389 	if (winname && *winname) {
1390 		free(*winname);
1391 		*winname = NULL;
1392 	}
1393 	if (windomain && *windomain) {
1394 		free(*windomain);
1395 		*windomain = NULL;
1396 	}
1397 
1398 out:
1399 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1400 	if (retcode != IDMAP_SUCCESS)
1401 		errno = idmap_stat2errno(retcode);
1402 	return (retcode);
1403 }
1404 
1405 
1406 /*
1407  * utf8str to string
1408  */
1409 idmap_stat
1410 idmap_utf82str(char **out, size_t outsize, idmap_utf8str *in) {
1411 	int len;
1412 
1413 	if (in == NULL || out == NULL)
1414 		return (IDMAP_ERR_ARG);
1415 
1416 	if (outsize == 0) {
1417 		*out = NULL;
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 		*out = calloc(1, len);
1425 		if (*out == NULL)
1426 			return (IDMAP_ERR_MEMORY);
1427 	} else {
1428 		if (*out == NULL)
1429 			return (IDMAP_ERR_ARG);
1430 		(void) memset(*out, 0, outsize);
1431 		if ((len = in->idmap_utf8str_len) == 0)
1432 			return (IDMAP_SUCCESS);
1433 		if (in->idmap_utf8str_val == NULL)
1434 			return (IDMAP_ERR_ARG);
1435 		if (in->idmap_utf8str_val[len - 1] != '\0')
1436 			len++;
1437 		if (outsize < len)
1438 			return (IDMAP_ERR_ARG);
1439 	}
1440 	(void) memcpy(*out, in->idmap_utf8str_val, in->idmap_utf8str_len);
1441 	return (IDMAP_SUCCESS);
1442 }
1443 
1444 
1445 /*
1446  * string to utf8str
1447  */
1448 idmap_stat
1449 idmap_str2utf8(idmap_utf8str **out, const char *in, int flag) {
1450 	idmap_utf8str	*tmp;
1451 
1452 	if (out == NULL)
1453 		return (IDMAP_ERR_ARG);
1454 	else if (*out == NULL) {
1455 		tmp = malloc(sizeof (idmap_utf8str));
1456 		if (tmp == NULL)
1457 			return (IDMAP_ERR_MEMORY);
1458 	} else {
1459 		tmp = *out;
1460 	}
1461 
1462 	if (in == NULL) {
1463 		tmp->idmap_utf8str_len = 0;
1464 		tmp->idmap_utf8str_val = NULL;
1465 		if (*out == NULL)
1466 			*out = tmp;
1467 		return (IDMAP_SUCCESS);
1468 	}
1469 
1470 	/* include the null terminator */
1471 	tmp->idmap_utf8str_len = strlen(in) + 1;
1472 
1473 	if (flag == 1) {
1474 		/* Don't malloc, simply assign */
1475 		tmp->idmap_utf8str_val = (char *)in;
1476 		if (*out == NULL)
1477 			*out = tmp;
1478 		return (IDMAP_SUCCESS);
1479 	}
1480 
1481 	tmp->idmap_utf8str_val = malloc(tmp->idmap_utf8str_len);
1482 	if (tmp->idmap_utf8str_val == NULL) {
1483 		tmp->idmap_utf8str_len = 0;
1484 		if (*out == NULL)
1485 			free(tmp);
1486 		return (IDMAP_ERR_MEMORY);
1487 	}
1488 	(void) memcpy(tmp->idmap_utf8str_val, in, tmp->idmap_utf8str_len);
1489 	if (*out == NULL)
1490 		*out = tmp;
1491 	return (IDMAP_SUCCESS);
1492 }
1493 
1494 
1495 #define	gettext(s)	s
1496 static stat_table_t stattable[] = {
1497 	{IDMAP_SUCCESS, gettext("Success"), 0},
1498 	{IDMAP_NEXT, gettext("More results available"), 0},
1499 	{IDMAP_ERR_OTHER, gettext("Undefined error"), EINVAL},
1500 	{IDMAP_ERR_INTERNAL, gettext("Internal error"), EINVAL},
1501 	{IDMAP_ERR_MEMORY, gettext("Out of memory"), ENOMEM},
1502 	{IDMAP_ERR_NORESULT, gettext("No results available"), EINVAL},
1503 	{IDMAP_ERR_NOTUSER, gettext("Not a user"), EINVAL},
1504 	{IDMAP_ERR_NOTGROUP, gettext("Not a group"), EINVAL},
1505 	{IDMAP_ERR_NOTSUPPORTED, gettext("Operation not supported"), ENOTSUP},
1506 	{IDMAP_ERR_W2U_NAMERULE,
1507 		gettext("Invalid Windows to UNIX name-based rule"), EINVAL},
1508 	{IDMAP_ERR_U2W_NAMERULE,
1509 		gettext("Invalid UNIX to Windows name-based rule"), EINVAL},
1510 	{IDMAP_ERR_CACHE, gettext("Invalid cache"), EINVAL},
1511 	{IDMAP_ERR_DB, gettext("Invalid database"), EINVAL},
1512 	{IDMAP_ERR_ARG, gettext("Invalid argument"), EINVAL},
1513 	{IDMAP_ERR_SID, gettext("Invalid SID"), EINVAL},
1514 	{IDMAP_ERR_IDTYPE, gettext("Invalid identity type"), EINVAL},
1515 	{IDMAP_ERR_RPC_HANDLE, gettext("Bad RPC handle"), EBADF},
1516 	{IDMAP_ERR_RPC, gettext("RPC error"), EINVAL},
1517 	{IDMAP_ERR_CLIENT_HANDLE, gettext("Bad client handle"), EINVAL},
1518 	{IDMAP_ERR_BUSY, gettext("Server is busy"), EBUSY},
1519 	{IDMAP_ERR_PERMISSION_DENIED, gettext("Permission denied"), EACCES},
1520 	{IDMAP_ERR_NOMAPPING,
1521 		gettext("Mapping not found or inhibited"), EINVAL},
1522 	{IDMAP_ERR_NEW_ID_ALLOC_REQD,
1523 		gettext("New mapping needs to be created"), EINVAL},
1524 	{IDMAP_ERR_DOMAIN, gettext("Invalid domain"), EINVAL},
1525 	{IDMAP_ERR_SECURITY, gettext("Security issue"), EINVAL},
1526 	{IDMAP_ERR_NOTFOUND, gettext("Not found"), EINVAL},
1527 	{IDMAP_ERR_DOMAIN_NOTFOUND, gettext("Domain not found"), EINVAL},
1528 	{IDMAP_ERR_UPDATE_NOTALLOWED, gettext("Update not allowed"), EINVAL},
1529 	{IDMAP_ERR_CFG, gettext("Configuration error"), EINVAL},
1530 	{IDMAP_ERR_CFG_CHANGE, gettext("Invalid configuration change"), EINVAL},
1531 	{IDMAP_ERR_NOTMAPPED_WELLKNOWN,
1532 		gettext("No mapping for well-known SID"), EINVAL},
1533 	{IDMAP_ERR_RETRIABLE_NET_ERR,
1534 		gettext("Windows lookup failed"), EINVAL},
1535 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
1536 		gettext("Duplicate rule or conflicts with an existing "
1537 		"Windows to UNIX name-based rule"), EINVAL},
1538 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
1539 		gettext("Duplicate rule or conflicts with an existing "
1540 		"Unix to Windows name-based rule"), EINVAL},
1541 	{-1, NULL, 0}
1542 };
1543 #undef	gettext
1544 
1545 
1546 /*
1547  * Get description of status code
1548  *
1549  * Input:
1550  * status - Status code returned by libidmap API call
1551  *
1552  * Return Value:
1553  * human-readable localized description of idmap_stat
1554  */
1555 /* ARGSUSED */
1556 const char *
1557 idmap_stat2string(idmap_handle_t *handle, idmap_stat status) {
1558 	int i;
1559 
1560 	for (i = 0; stattable[i].msg; i++) {
1561 		if (stattable[i].retcode == status)
1562 			return (gettext(stattable[i].msg));
1563 	}
1564 	return (gettext("Unknown error"));
1565 }
1566 
1567 
1568 static int
1569 idmap_stat2errno(idmap_stat stat) {
1570 	int i;
1571 	for (i = 0; stattable[i].msg; i++) {
1572 		if (stattable[i].retcode == stat)
1573 			return (stattable[i].errnum);
1574 	}
1575 	return (EINVAL);
1576 }
1577 
1578 
1579 /*
1580  * Get status code from string
1581  */
1582 idmap_stat
1583 idmap_string2stat(const char *str) {
1584 	if (str == NULL)
1585 		return (IDMAP_ERR_INTERNAL);
1586 
1587 #define	return_cmp(a) \
1588 	if (0 == strcmp(str, "IDMAP_ERR_" #a)) \
1589 		return (IDMAP_ERR_ ## a);
1590 
1591 	return_cmp(OTHER);
1592 	return_cmp(INTERNAL);
1593 	return_cmp(MEMORY);
1594 	return_cmp(NORESULT);
1595 	return_cmp(NOTUSER);
1596 	return_cmp(NOTGROUP);
1597 	return_cmp(NOTSUPPORTED);
1598 	return_cmp(W2U_NAMERULE);
1599 	return_cmp(U2W_NAMERULE);
1600 	return_cmp(CACHE);
1601 	return_cmp(DB);
1602 	return_cmp(ARG);
1603 	return_cmp(SID);
1604 	return_cmp(IDTYPE);
1605 	return_cmp(RPC_HANDLE);
1606 	return_cmp(RPC);
1607 	return_cmp(CLIENT_HANDLE);
1608 	return_cmp(BUSY);
1609 	return_cmp(PERMISSION_DENIED);
1610 	return_cmp(NOMAPPING);
1611 	return_cmp(NEW_ID_ALLOC_REQD);
1612 	return_cmp(DOMAIN);
1613 	return_cmp(SECURITY);
1614 	return_cmp(NOTFOUND);
1615 	return_cmp(DOMAIN_NOTFOUND);
1616 	return_cmp(MEMORY);
1617 	return_cmp(UPDATE_NOTALLOWED);
1618 	return_cmp(CFG);
1619 	return_cmp(CFG_CHANGE);
1620 	return_cmp(NOTMAPPED_WELLKNOWN);
1621 	return_cmp(RETRIABLE_NET_ERR);
1622 	return_cmp(W2U_NAMERULE_CONFLICT);
1623 	return_cmp(U2W_NAMERULE_CONFLICT);
1624 #undef return_cmp
1625 
1626 	return (IDMAP_ERR_OTHER);
1627 }
1628 
1629 
1630 /*
1631  * Map the given status to one that can be returned by the protocol
1632  */
1633 idmap_stat
1634 idmap_stat4prot(idmap_stat status) {
1635 	switch (status) {
1636 	case IDMAP_ERR_MEMORY:
1637 	case IDMAP_ERR_CACHE:
1638 		return (IDMAP_ERR_INTERNAL);
1639 	}
1640 	return (status);
1641 }
1642 
1643 
1644 /*
1645  * Get uid given Windows name
1646  */
1647 idmap_stat
1648 idmap_getuidbywinname(const char *name, const char *domain, uid_t *uid) {
1649 	idmap_handle_t	*ih;
1650 	idmap_retcode	rc;
1651 	int		is_user;
1652 
1653 	if (uid == NULL)
1654 		return (IDMAP_ERR_ARG);
1655 
1656 	/* Get mapping */
1657 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
1658 		return (rc);
1659 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, 0,
1660 	    &is_user, uid, NULL, NULL);
1661 	(void) idmap_fini(ih);
1662 
1663 	/*
1664 	 * XXX Until we have diagonal mapping support, check if
1665 	 * the given name belongs to a user
1666 	 */
1667 	if (rc == IDMAP_SUCCESS && !is_user)
1668 		return (IDMAP_ERR_NOTUSER);
1669 	return (rc);
1670 }
1671 
1672 
1673 /*
1674  * Get gid given Windows name
1675  */
1676 idmap_stat
1677 idmap_getgidbywinname(const char *name, const char *domain, gid_t *gid) {
1678 	idmap_handle_t	*ih;
1679 	idmap_retcode	rc;
1680 	int		is_user;
1681 
1682 	if (gid == NULL)
1683 		return (IDMAP_ERR_ARG);
1684 
1685 	/* Get mapping */
1686 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
1687 		return (rc);
1688 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, 0,
1689 	    &is_user, gid, NULL, NULL);
1690 	(void) idmap_fini(ih);
1691 
1692 	/*
1693 	 * XXX Until we have diagonal mapping support, check if
1694 	 * the given name belongs to a group
1695 	 */
1696 	if (rc == IDMAP_SUCCESS && is_user)
1697 		return (IDMAP_ERR_NOTGROUP);
1698 	return (rc);
1699 }
1700 
1701 
1702 /*
1703  * Get winname given pid
1704  */
1705 static idmap_retcode
1706 idmap_getwinnamebypid(uid_t pid, int is_user, char **name, char **domain) {
1707 	idmap_handle_t	*ih;
1708 	idmap_retcode	rc;
1709 	int		len;
1710 	char		*winname, *windomain;
1711 
1712 	if (name == NULL)
1713 		return (IDMAP_ERR_ARG);
1714 
1715 	/* Get mapping */
1716 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
1717 		return (rc);
1718 	rc = idmap_get_u2w_mapping(ih, &pid, NULL, 0, is_user, NULL,
1719 	    NULL, &winname, &windomain, NULL);
1720 	(void) idmap_fini(ih);
1721 
1722 	/* Return on error */
1723 	if (rc != IDMAP_SUCCESS)
1724 		return (rc);
1725 
1726 	/*
1727 	 * The given PID may have been mapped to a locally
1728 	 * generated SID in which case there isn't any
1729 	 * Windows name
1730 	 */
1731 	if (winname == NULL || windomain == NULL) {
1732 		idmap_free(winname);
1733 		idmap_free(windomain);
1734 		return (IDMAP_ERR_NORESULT);
1735 	}
1736 
1737 	if (domain != NULL) {
1738 		*name = winname;
1739 		*domain = windomain;
1740 	} else {
1741 		len = strlen(winname) + strlen(windomain) + 2;
1742 		if ((*name = malloc(len)) != NULL)
1743 			(void) snprintf(*name, len, "%s@%s", winname,
1744 			    windomain);
1745 		else
1746 			rc = IDMAP_ERR_MEMORY;
1747 		idmap_free(winname);
1748 		idmap_free(windomain);
1749 	}
1750 	return (rc);
1751 }
1752 
1753 
1754 /*
1755  * Get winname given uid
1756  */
1757 idmap_stat
1758 idmap_getwinnamebyuid(uid_t uid, char **name, char **domain) {
1759 	return (idmap_getwinnamebypid(uid, 1, name, domain));
1760 }
1761 
1762 
1763 /*
1764  * Get winname given gid
1765  */
1766 idmap_stat
1767 idmap_getwinnamebygid(gid_t gid, char **name, char **domain) {
1768 	return (idmap_getwinnamebypid(gid, 0, name, domain));
1769 }
1770