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