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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * libidmap API
29  */
30 
31 #include <stdlib.h>
32 #include <sys/varargs.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 <ucontext.h>
43 #include "idmap_impl.h"
44 #include "idmap_cache.h"
45 
46 /*LINTLIBRARY*/
47 
48 /*
49  * The following structure determines where the log messages from idmapdlog()
50  * go to. It can be stderr (idmap, idmapd -d) and/or syslog (idmapd).
51  *
52  * logstate.max_pri is integer cutoff necessary to silence low-priority
53  * messages to stderr. Syslog has its own means so there a boolean
54  * logstate.write_syslog is enough.
55  *
56  * logstate.degraded is a mode used by idmapd in its degraded state.
57  */
58 
59 static struct {
60 	bool_t write_syslog;
61 	int max_pri; /* Max priority written to stderr */
62 	bool_t degraded;
63 } logstate = {FALSE, LOG_DEBUG, FALSE};
64 
65 
66 static struct timeval TIMEOUT = { 25, 0 };
67 
68 static int idmap_stat2errno(idmap_stat);
69 static idmap_stat	idmap_strdupnull(char **, const char *);
70 
71 #define	__ITER_CREATE(itera, argu, handl, ityp)\
72 	if (handl == NULL) {\
73 		errno = EINVAL;\
74 		return (IDMAP_ERR_ARG);\
75 	}\
76 	itera = calloc(1, sizeof (*itera));\
77 	if (itera == NULL) {\
78 		errno = ENOMEM;\
79 		return (IDMAP_ERR_MEMORY);\
80 	}\
81 	argu = calloc(1, sizeof (*argu));\
82 	if (argu == NULL) {\
83 		free(itera);\
84 		errno = ENOMEM;\
85 		return (IDMAP_ERR_MEMORY);\
86 	}\
87 	itera->ih = handl;\
88 	itera->type = ityp;\
89 	itera->retcode = IDMAP_NEXT;\
90 	itera->limit = 1024;\
91 	itera->arg = argu;
92 
93 
94 #define	__ITER_ERR_RETURN(itera, argu, xdr_argu, iretcod)\
95 	if (argu) {\
96 		xdr_free(xdr_argu, (caddr_t)argu);\
97 		free(argu);\
98 	}\
99 	if (itera)\
100 		free(itera);\
101 	return (iretcod);
102 
103 
104 #define	__ITER_CHECK(itera, ityp)\
105 	if (itera == NULL) {\
106 		errno = EINVAL;\
107 		return (IDMAP_ERR_ARG);\
108 	}\
109 	if (itera->type != ityp) {\
110 		errno = EINVAL;\
111 		return (IDMAP_ERR_ARG);\
112 	}
113 
114 /*
115  * Free memory allocated by libidmap API
116  *
117  * Input:
118  * ptr - memory to be freed
119  */
120 void
121 idmap_free(void *ptr)
122 {
123 	free(ptr);
124 }
125 
126 
127 #define	MIN_STACK_NEEDS	16384
128 
129 /*
130  * Create and Initialize idmap client handle for rpc/doors
131  *
132  * Output:
133  * handle - idmap handle
134  */
135 idmap_stat
136 idmap_init(idmap_handle_t **handle)
137 {
138 	CLIENT			*clnt = NULL;
139 	struct idmap_handle	*hptr;
140 	uint_t			sendsz = 0;
141 	stack_t			st;
142 
143 	*handle = NULL;
144 	hptr = (struct idmap_handle *)calloc(1, sizeof (*hptr));
145 	if (hptr == NULL)
146 		return (IDMAP_ERR_MEMORY);
147 
148 	/*
149 	 * clnt_door_call() alloca()s sendsz bytes (twice too, once for
150 	 * the call args buffer and once for the call result buffer), so
151 	 * we want to pick a sendsz that will be large enough, but not
152 	 * too large.
153 	 */
154 	if (stack_getbounds(&st) == 0) {
155 		/*
156 		 * Estimate how much stack space is left;
157 		 * st.ss_sp is the top of stack.
158 		 */
159 		if ((char *)&sendsz < (char *)st.ss_sp)
160 			/* stack grows up */
161 			sendsz = ((char *)st.ss_sp - (char *)&sendsz);
162 		else
163 			/* stack grows down */
164 			sendsz = ((char *)&sendsz - (char *)st.ss_sp);
165 
166 		/*
167 		 * Take much of the stack space left, divided by two,
168 		 * but leave enough for our needs (just a guess!), and
169 		 * if we can't, then roll the dice.
170 		 */
171 		sendsz = RNDUP(sendsz / 2);
172 		if (sendsz < MIN_STACK_NEEDS)
173 			sendsz = 0;	/* RPC call may fail */
174 		else if (sendsz > IDMAP_MAX_DOOR_RPC)
175 			sendsz = IDMAP_MAX_DOOR_RPC;
176 	}
177 
178 	clnt = clnt_door_create(IDMAP_PROG, IDMAP_V1, sendsz);
179 	if (clnt == NULL) {
180 		free(hptr);
181 		return (IDMAP_ERR_RPC);
182 	}
183 	hptr->type = _IDMAP_HANDLE_RPC_DOORS;
184 	hptr->privhandle = clnt;
185 	*handle = hptr;
186 	return (IDMAP_SUCCESS);
187 }
188 
189 
190 /*
191  * Finalize idmap handle
192  *
193  * Input:
194  * handle - idmap handle
195  */
196 idmap_stat
197 idmap_fini(idmap_handle_t *handle)
198 {
199 	CLIENT			*clnt;
200 	struct idmap_handle	*hptr;
201 
202 	if (handle == NULL)
203 		return (IDMAP_SUCCESS);
204 
205 	hptr = (struct idmap_handle *)handle;
206 
207 	switch (hptr->type) {
208 	case _IDMAP_HANDLE_RPC_DOORS:
209 		clnt = (CLIENT *)hptr->privhandle;
210 		if (clnt) {
211 			if (clnt->cl_auth)
212 				auth_destroy(clnt->cl_auth);
213 			clnt_destroy(clnt);
214 		}
215 		break;
216 	default:
217 		break;
218 	}
219 	free(hptr);
220 	return (IDMAP_SUCCESS);
221 }
222 
223 
224 idmap_stat
225 idmap_get_prop(idmap_handle_t *handle, idmap_prop_type pr, idmap_prop_res *res)
226 {
227 	CLIENT			*clnt;
228 	enum clnt_stat		clntstat;
229 
230 
231 	(void) memset(res, 0, sizeof (*res));
232 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
233 
234 	clntstat = clnt_call(clnt, IDMAP_GET_PROP,
235 	    (xdrproc_t)xdr_idmap_prop_type, (caddr_t)&pr,
236 	    (xdrproc_t)xdr_idmap_prop_res, (caddr_t)res, TIMEOUT);
237 
238 	if (clntstat != RPC_SUCCESS) {
239 		return (_idmap_rpc2stat(clnt));
240 	}
241 
242 	return (res->retcode); /* This might not be IDMAP_SUCCESS! */
243 
244 #if 0
245 	(void) memset(&res, 0, sizeof (res));
246 	pr = PROP_DOMAIN_CONTROLLER;
247 
248 	clntstat = clnt_call(clnt, IDMAP_GET_PROP,
249 	    (xdrproc_t)xdr_idmap_prop_type, (caddr_t)&pr,
250 	    (xdrproc_t)xdr_idmap_prop_res, (caddr_t)&res, TIMEOUT);
251 
252 	if (clntstat != RPC_SUCCESS) {
253 		fprintf(stderr, "clntstat != RPC_SUCCESS\n");
254 		rc = _idmap_rpc2stat(clnt);
255 		goto cleanup;
256 	}
257 #endif
258 
259 }
260 
261 idmap_stat
262 idmap_get_prop_ds(idmap_handle_t *handle, idmap_prop_type pr,
263     idmap_ad_disc_ds_t *dc)
264 {
265 	idmap_prop_res res;
266 	idmap_stat rc = IDMAP_SUCCESS;
267 
268 	rc = idmap_get_prop(handle, pr, &res);
269 	if (rc < 0)
270 		return (rc);
271 
272 	dc->port = res.value.idmap_prop_val_u.dsval.port;
273 	(void) strlcpy(dc->host, res.value.idmap_prop_val_u.dsval.host,
274 	    AD_DISC_MAXHOSTNAME);
275 
276 	/* xdr doesn't guarantee 0-termination of char[]: */
277 	dc->host[AD_DISC_MAXHOSTNAME - 1] = '\0';
278 
279 	return (rc);
280 }
281 
282 
283 /*
284  * Sometimes the property is not set. In that case, str is set to NULL but
285  * otherwise IDMAP_SUCCESS is returned.
286  */
287 idmap_stat
288 idmap_get_prop_str(idmap_handle_t *handle, idmap_prop_type pr, char **str)
289 {
290 	idmap_prop_res res;
291 	idmap_stat rc = IDMAP_SUCCESS;
292 
293 	rc = idmap_get_prop(handle, pr, &res);
294 	if (rc < 0)
295 		return (rc);
296 
297 	rc = idmap_strdupnull(str, res.value.idmap_prop_val_u.utf8val);
298 	return (rc);
299 }
300 
301 /*
302  * Create/Initialize handle for updates
303  *
304  * Output:
305  * udthandle - update handle
306  */
307 idmap_stat
308 idmap_udt_create(idmap_handle_t *handle, idmap_udt_handle_t **udthandle)
309 {
310 	idmap_udt_handle_t	*tmp;
311 
312 	if (handle == NULL || udthandle == NULL) {
313 		errno = EINVAL;
314 		return (IDMAP_ERR_ARG);
315 	}
316 	if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
317 		errno = ENOMEM;
318 		return (IDMAP_ERR_MEMORY);
319 	}
320 
321 	tmp->ih = handle;
322 	*udthandle = tmp;
323 	return (IDMAP_SUCCESS);
324 }
325 
326 
327 /*
328  * All the updates specified by the update handle are committed
329  * in a single transaction. i.e either all succeed or none.
330  *
331  * Input:
332  * udthandle - update handle with the update requests
333  *
334  * Return value:
335  * Status of the commit
336  */
337 idmap_stat
338 idmap_udt_commit(idmap_udt_handle_t *udthandle)
339 {
340 	CLIENT			*clnt;
341 	enum clnt_stat		clntstat;
342 	idmap_update_res	res;
343 	idmap_stat		retcode;
344 
345 	if (udthandle == NULL) {
346 		errno = EINVAL;
347 		return (IDMAP_ERR_ARG);
348 	}
349 
350 	(void) memset(&res, 0, sizeof (res));
351 
352 	_IDMAP_GET_CLIENT_HANDLE(udthandle->ih, clnt);
353 	clntstat = clnt_call(clnt, IDMAP_UPDATE,
354 	    (xdrproc_t)xdr_idmap_update_batch, (caddr_t)&udthandle->batch,
355 	    (xdrproc_t)xdr_idmap_update_res, (caddr_t)&res,
356 	    TIMEOUT);
357 
358 	if (clntstat != RPC_SUCCESS) {
359 		retcode = _idmap_rpc2stat(clnt);
360 		goto out;
361 	}
362 
363 	retcode = udthandle->commit_stat = res.retcode;
364 	udthandle->error_index = res.error_index;
365 
366 	if (retcode != IDMAP_SUCCESS) {
367 
368 		if (udthandle->error_index < 0)
369 			goto out;
370 
371 		retcode = idmap_namerule_cpy(&udthandle->error_rule,
372 		    &res.error_rule);
373 		if (retcode != IDMAP_SUCCESS) {
374 			udthandle->error_index = -2;
375 			goto out;
376 		}
377 
378 		retcode = idmap_namerule_cpy(&udthandle->conflict_rule,
379 		    &res.conflict_rule);
380 		if (retcode != IDMAP_SUCCESS) {
381 			udthandle->error_index = -2;
382 			goto out;
383 		}
384 	}
385 
386 	retcode = res.retcode;
387 
388 
389 out:
390 	/* reset handle so that it can be used again */
391 	if (retcode == IDMAP_SUCCESS) {
392 		_IDMAP_RESET_UDT_HANDLE(udthandle);
393 	}
394 
395 	(void) xdr_free(xdr_idmap_update_res, (caddr_t)&res);
396 	errno = idmap_stat2errno(retcode);
397 	return (retcode);
398 }
399 
400 
401 static void
402 idmap_namerule_parts_clear(char **windomain, char **winname,
403     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
404     boolean_t *is_nt4, int *direction)
405 {
406 	if (windomain)
407 		*windomain = NULL;
408 	if (winname)
409 		*winname = NULL;
410 	if (unixname)
411 		*unixname = NULL;
412 
413 	if (is_nt4)
414 		*is_nt4 = 0;
415 	if (is_user)
416 		*is_user = -1;
417 	if (is_wuser)
418 		*is_wuser = -1;
419 	if (direction)
420 		*direction = IDMAP_DIRECTION_UNDEF;
421 }
422 
423 static idmap_stat
424 idmap_namerule2parts(idmap_namerule *rule,
425     char **windomain, char **winname,
426     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
427     boolean_t *is_nt4, int *direction)
428 {
429 	idmap_stat retcode;
430 
431 	if (EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
432 		return (IDMAP_ERR_NORESULT);
433 
434 
435 	retcode = idmap_strdupnull(windomain, rule->windomain);
436 	if (retcode != IDMAP_SUCCESS)
437 		goto errout;
438 
439 	retcode = idmap_strdupnull(winname, rule->winname);
440 	if (retcode != IDMAP_SUCCESS)
441 		goto errout;
442 
443 	retcode = idmap_strdupnull(unixname, rule->unixname);
444 	if (retcode != IDMAP_SUCCESS)
445 		goto errout;
446 
447 
448 	if (is_user)
449 		*is_user = rule->is_user;
450 	if (is_wuser)
451 		*is_wuser = rule->is_wuser;
452 	if (is_nt4)
453 		*is_nt4 = rule->is_nt4;
454 	if (direction)
455 		*direction = rule->direction;
456 
457 
458 	return (IDMAP_SUCCESS);
459 
460 errout:
461 	if (windomain && *windomain)
462 		free(*windomain);
463 	if (winname && *winname)
464 		free(*winname);
465 	if (unixname && *unixname)
466 		free(*unixname);
467 
468 	idmap_namerule_parts_clear(windomain, winname,
469 	    unixname, is_user, is_wuser, is_nt4, direction);
470 
471 	return (retcode);
472 
473 }
474 
475 /*
476  * Retrieve the index of the failed batch element. error_index == -1
477  * indicates failure at the beginning, -2 at the end.
478  *
479  * If idmap_udt_commit didn't return error, the returned value is undefined.
480  *
481  * Return value:
482  * IDMAP_SUCCESS
483  */
484 
485 idmap_stat
486 idmap_udt_get_error_index(idmap_udt_handle_t *udthandle,
487     int64_t *error_index)
488 {
489 	if (error_index)
490 		*error_index = udthandle->error_index;
491 
492 	return (IDMAP_SUCCESS);
493 }
494 
495 
496 /*
497  * Retrieve the rule which caused the batch to fail. If
498  * idmap_udt_commit didn't return error or if error_index is < 0, the
499  * retrieved rule is undefined.
500  *
501  * Return value:
502  * IDMAP_ERR_NORESULT if there is no error rule.
503  * IDMAP_SUCCESS if the rule was obtained OK.
504  * other error code (IDMAP_ERR_NOMEMORY etc)
505  */
506 
507 idmap_stat
508 idmap_udt_get_error_rule(idmap_udt_handle_t *udthandle,
509     char **windomain, char **winname,
510     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
511     boolean_t *is_nt4, int *direction)
512 {
513 	idmap_namerule_parts_clear(windomain, winname,
514 	    unixname, is_user, is_wuser, is_nt4, direction);
515 
516 	if (udthandle->commit_stat == IDMAP_SUCCESS ||
517 	    udthandle->error_index < 0)
518 		return (IDMAP_ERR_NORESULT);
519 
520 	return (idmap_namerule2parts(
521 	    &udthandle->error_rule,
522 	    windomain,
523 	    winname,
524 	    unixname,
525 	    is_user,
526 	    is_wuser,
527 	    is_nt4,
528 	    direction));
529 }
530 
531 /*
532  * Retrieve the rule with which there was a conflict. TODO: retrieve
533  * the value.
534  *
535  * Return value:
536  * IDMAP_ERR_NORESULT if there is no error rule.
537  * IDMAP_SUCCESS if the rule was obtained OK.
538  * other error code (IDMAP_ERR_NOMEMORY etc)
539  */
540 
541 idmap_stat
542 idmap_udt_get_conflict_rule(idmap_udt_handle_t *udthandle,
543     char **windomain, char **winname,
544     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
545     boolean_t *is_nt4, int *direction)
546 {
547 	idmap_namerule_parts_clear(windomain, winname,
548 	    unixname, is_user, is_wuser, is_nt4, direction);
549 
550 	if (udthandle->commit_stat != IDMAP_ERR_W2U_NAMERULE_CONFLICT &&
551 	    udthandle->commit_stat != IDMAP_ERR_U2W_NAMERULE_CONFLICT) {
552 		return (IDMAP_ERR_NORESULT);
553 	}
554 
555 	return (idmap_namerule2parts(
556 	    &udthandle->conflict_rule,
557 	    windomain,
558 	    winname,
559 	    unixname,
560 	    is_user,
561 	    is_wuser,
562 	    is_nt4,
563 	    direction));
564 }
565 
566 
567 /*
568  * Destroy the update handle
569  */
570 void
571 idmap_udt_destroy(idmap_udt_handle_t *udthandle)
572 {
573 	if (udthandle == NULL)
574 		return;
575 	(void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
576 	(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->error_rule);
577 	(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->conflict_rule);
578 	free(udthandle);
579 }
580 
581 
582 idmap_stat
583 idmap_udt_add_namerule(idmap_udt_handle_t *udthandle, const char *windomain,
584     boolean_t is_user, boolean_t is_wuser, const char *winname,
585     const char *unixname, boolean_t is_nt4, int direction)
586 {
587 	idmap_retcode	retcode;
588 	idmap_namerule	*rule = NULL;
589 
590 	retcode = _udt_extend_batch(udthandle);
591 	if (retcode != IDMAP_SUCCESS)
592 		goto errout;
593 
594 	rule = &udthandle->batch.
595 	    idmap_update_batch_val[udthandle->next].
596 	    idmap_update_op_u.rule;
597 	rule->is_user = is_user;
598 	rule->is_wuser = is_wuser;
599 	rule->direction = direction;
600 	rule->is_nt4 = is_nt4;
601 
602 	retcode = idmap_strdupnull(&rule->windomain, windomain);
603 	if (retcode != IDMAP_SUCCESS)
604 		goto errout;
605 
606 	retcode = idmap_strdupnull(&rule->winname, winname);
607 	if (retcode != IDMAP_SUCCESS)
608 		goto errout;
609 
610 	retcode = idmap_strdupnull(&rule->unixname, unixname);
611 	if (retcode != IDMAP_SUCCESS)
612 		goto errout;
613 
614 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
615 	    OP_ADD_NAMERULE;
616 	udthandle->next++;
617 	return (IDMAP_SUCCESS);
618 
619 errout:
620 	/* The batch should still be usable */
621 	if (rule)
622 		(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
623 	errno = idmap_stat2errno(retcode);
624 	return (retcode);
625 }
626 
627 
628 /* ARGSUSED */
629 idmap_stat
630 idmap_udt_rm_namerule(idmap_udt_handle_t *udthandle, boolean_t is_user,
631     boolean_t is_wuser,	const char *windomain, const char *winname,
632     const char *unixname, int direction)
633 {
634 	idmap_retcode	retcode;
635 	idmap_namerule	*rule = NULL;
636 
637 	retcode = _udt_extend_batch(udthandle);
638 	if (retcode != IDMAP_SUCCESS)
639 		goto errout;
640 
641 	rule = &udthandle->batch.
642 	    idmap_update_batch_val[udthandle->next].
643 	    idmap_update_op_u.rule;
644 	rule->is_user = is_user;
645 	rule->is_wuser = is_wuser;
646 	rule->direction = direction;
647 
648 	retcode = idmap_strdupnull(&rule->windomain, windomain);
649 	if (retcode != IDMAP_SUCCESS)
650 		goto errout;
651 
652 	retcode = idmap_strdupnull(&rule->winname, winname);
653 	if (retcode != IDMAP_SUCCESS)
654 		goto errout;
655 
656 	retcode = idmap_strdupnull(&rule->unixname, unixname);
657 	if (retcode != IDMAP_SUCCESS)
658 		goto errout;
659 
660 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
661 	    OP_RM_NAMERULE;
662 	udthandle->next++;
663 	return (IDMAP_SUCCESS);
664 
665 errout:
666 	if (rule)
667 		(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
668 	errno = idmap_stat2errno(retcode);
669 	return (retcode);
670 }
671 
672 
673 /* ARGSUSED */
674 idmap_stat
675 idmap_udt_flush_namerules(idmap_udt_handle_t *udthandle)
676 {
677 	idmap_retcode	retcode;
678 
679 	retcode = _udt_extend_batch(udthandle);
680 	if (retcode != IDMAP_SUCCESS)
681 		goto errout;
682 
683 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
684 	    OP_FLUSH_NAMERULES;
685 	udthandle->next++;
686 	return (IDMAP_SUCCESS);
687 
688 errout:
689 	errno = idmap_stat2errno(retcode);
690 	return (retcode);
691 }
692 
693 
694 /*
695  * Set the number of entries requested per batch by the iterator
696  *
697  * Input:
698  * iter  - iterator
699  * limit - number of entries requested per batch
700  */
701 idmap_stat
702 idmap_iter_set_limit(idmap_iter_t *iter, uint64_t limit)
703 {
704 	if (iter == NULL) {
705 		errno = EINVAL;
706 		return (IDMAP_ERR_ARG);
707 	}
708 	iter->limit = limit;
709 	return (IDMAP_SUCCESS);
710 }
711 
712 
713 /*
714  * Create iterator to get name-based mapping rules
715  *
716  * Input:
717  * windomain - Windows domain
718  * is_user   - user or group rules
719  * winname   - Windows user or group name
720  * unixname  - Unix user or group name
721  *
722  * Output:
723  * iter - iterator
724  */
725 idmap_stat
726 idmap_iter_namerules(idmap_handle_t *handle, const char *windomain,
727 		boolean_t is_user, boolean_t is_wuser, const char *winname,
728 		const char *unixname, idmap_iter_t **iter)
729 {
730 
731 	idmap_iter_t			*tmpiter;
732 	idmap_list_namerules_1_argument	*arg = NULL;
733 	idmap_namerule			*rule;
734 	idmap_retcode			retcode;
735 
736 	__ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_NAMERULES);
737 
738 	rule = &arg->rule;
739 	rule->is_user = is_user;
740 	rule->is_wuser = is_wuser;
741 	rule->direction = IDMAP_DIRECTION_UNDEF;
742 
743 	retcode = idmap_strdupnull(&rule->windomain, windomain);
744 	if (retcode != IDMAP_SUCCESS)
745 		goto errout;
746 
747 	retcode = idmap_strdupnull(&rule->winname, winname);
748 	if (retcode != IDMAP_SUCCESS)
749 		goto errout;
750 
751 	retcode = idmap_strdupnull(&rule->unixname, unixname);
752 	if (retcode != IDMAP_SUCCESS)
753 		goto errout;
754 
755 	*iter = tmpiter;
756 	return (IDMAP_SUCCESS);
757 
758 errout:
759 	__ITER_ERR_RETURN(tmpiter, arg,
760 	    xdr_idmap_list_namerules_1_argument, retcode);
761 }
762 
763 
764 /*
765  * Iterate through the name-based mapping rules
766  *
767  * Input:
768  * iter - iterator
769  *
770  * Output:
771  * windomain - Windows domain
772  * winname   - Windows user or group name
773  * unixname  - Unix user or group name
774  * is_nt4    - NT4 or AD
775  * direction - bi(0), win2unix(1), unix2win(2)
776  *
777  * Return value:
778  * 0   - done
779  * 1   - more results available
780  * < 0 - error
781  */
782 idmap_stat
783 idmap_iter_next_namerule(idmap_iter_t *iter, char **windomain,
784     char **winname, char **unixname,  boolean_t *is_user,
785     boolean_t *is_wuser, boolean_t *is_nt4, int *direction)
786 {
787 	idmap_namerules_res		*namerules;
788 	idmap_list_namerules_1_argument	*arg;
789 	idmap_retcode			retcode;
790 
791 	idmap_namerule_parts_clear(windomain, winname,
792 	    unixname, is_user, is_wuser, is_nt4, direction);
793 
794 
795 	__ITER_CHECK(iter, IDMAP_LIST_NAMERULES);
796 
797 	namerules = (idmap_namerules_res *)iter->retlist;
798 	if (iter->retcode == IDMAP_NEXT && (namerules == NULL ||
799 	    iter->next >= namerules->rules.rules_len)) {
800 
801 		if ((arg = iter->arg) == NULL) {
802 			errno = EINVAL;
803 			return (IDMAP_ERR_ARG);
804 		}
805 		arg->limit = iter->limit;
806 
807 		retcode = _iter_get_next_list(IDMAP_LIST_NAMERULES,
808 		    iter, arg,
809 		    (uchar_t **)&namerules, sizeof (*namerules),
810 		    (xdrproc_t)xdr_idmap_list_namerules_1_argument,
811 		    (xdrproc_t)xdr_idmap_namerules_res);
812 		if (retcode != IDMAP_SUCCESS)
813 			return (retcode);
814 
815 		if (IDMAP_ERROR(namerules->retcode)) {
816 			retcode  = namerules->retcode;
817 			xdr_free(xdr_idmap_namerules_res, (caddr_t)namerules);
818 			free(namerules);
819 			iter->retlist = NULL;
820 			return (retcode);
821 		}
822 		iter->retcode = namerules->retcode;
823 		arg->lastrowid = namerules->lastrowid;
824 	}
825 
826 	if (namerules == NULL || namerules->rules.rules_len == 0)
827 		return (IDMAP_SUCCESS);
828 
829 	if (iter->next >= namerules->rules.rules_len) {
830 		return (IDMAP_ERR_ARG);
831 	}
832 
833 	retcode = idmap_strdupnull(windomain,
834 	    namerules->rules.rules_val[iter->next].windomain);
835 	if (retcode != IDMAP_SUCCESS)
836 		goto errout;
837 
838 	retcode = idmap_strdupnull(winname,
839 	    namerules->rules.rules_val[iter->next].winname);
840 	if (retcode != IDMAP_SUCCESS)
841 		goto errout;
842 
843 	retcode = idmap_strdupnull(unixname,
844 	    namerules->rules.rules_val[iter->next].unixname);
845 	if (retcode != IDMAP_SUCCESS)
846 		goto errout;
847 
848 	if (is_nt4)
849 		*is_nt4 = namerules->rules.rules_val[iter->next].is_nt4;
850 	if (is_user)
851 		*is_user = namerules->rules.rules_val[iter->next].is_user;
852 	if (is_wuser)
853 		*is_wuser = namerules->rules.rules_val[iter->next].is_wuser;
854 	if (direction)
855 		*direction = namerules->rules.rules_val[iter->next].direction;
856 	iter->next++;
857 
858 	if (iter->next == namerules->rules.rules_len)
859 		return (iter->retcode);
860 	else
861 		return (IDMAP_NEXT);
862 
863 errout:
864 	if (windomain && *windomain)
865 		free(*windomain);
866 	if (winname && *winname)
867 		free(*winname);
868 	if (unixname && *unixname)
869 		free(*unixname);
870 	return (retcode);
871 }
872 
873 
874 /*
875  * Create iterator to get SID to UID/GID mappings
876  *
877  * Output:
878  * iter - iterator
879  */
880 idmap_stat
881 idmap_iter_mappings(idmap_handle_t *handle, idmap_iter_t **iter, int flag)
882 {
883 	idmap_iter_t			*tmpiter;
884 	idmap_list_mappings_1_argument	*arg = NULL;
885 
886 	__ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_MAPPINGS);
887 
888 	arg->flag = flag;
889 	*iter = tmpiter;
890 	return (IDMAP_SUCCESS);
891 }
892 
893 
894 /*
895  * Iterate through the SID to UID/GID mappings
896  *
897  * Input:
898  * iter - iterator
899  *
900  * Output:
901  * sid - SID in canonical form
902  * pid - UID or GID
903  *
904  * Return value:
905  * 0   - done
906  * 1   - more results available
907  * < 0 - error
908  */
909 idmap_stat
910 idmap_iter_next_mapping(idmap_iter_t *iter, char **sidprefix,
911     idmap_rid_t *rid, uid_t *pid, char **winname,
912     char **windomain, char **unixname, boolean_t *is_user,
913     boolean_t *is_wuser, int *direction, idmap_info *info)
914 {
915 	idmap_mappings_res		*mappings;
916 	idmap_list_mappings_1_argument	*arg;
917 	idmap_retcode			retcode;
918 	char				*str;
919 
920 	if (sidprefix)
921 		*sidprefix = NULL;
922 	if (rid)
923 		*rid = UINT32_MAX;
924 	if (winname)
925 		*winname = NULL;
926 	if (windomain)
927 		*windomain = NULL;
928 	if (unixname)
929 		*unixname = NULL;
930 	if (pid)
931 		*pid = UINT32_MAX;
932 	if (is_user)
933 		*is_user = -1;
934 	if (is_wuser)
935 		*is_wuser = -1;
936 	if (direction)
937 		*direction = IDMAP_DIRECTION_UNDEF;
938 
939 	__ITER_CHECK(iter, IDMAP_LIST_MAPPINGS);
940 
941 	mappings = (idmap_mappings_res *)iter->retlist;
942 	if (iter->retcode == IDMAP_NEXT && (mappings == NULL ||
943 	    iter->next >= mappings->mappings.mappings_len)) {
944 
945 		if ((arg = iter->arg) == NULL) {
946 			errno = EINVAL;
947 			return (IDMAP_ERR_ARG);
948 		}
949 		arg->limit = iter->limit;
950 
951 		retcode = _iter_get_next_list(IDMAP_LIST_MAPPINGS,
952 		    iter, arg,
953 		    (uchar_t **)&mappings, sizeof (*mappings),
954 		    (xdrproc_t)xdr_idmap_list_mappings_1_argument,
955 		    (xdrproc_t)xdr_idmap_mappings_res);
956 		if (retcode != IDMAP_SUCCESS)
957 			return (retcode);
958 
959 		if (IDMAP_ERROR(mappings->retcode)) {
960 			retcode  = mappings->retcode;
961 			xdr_free(xdr_idmap_mappings_res, (caddr_t)mappings);
962 			free(mappings);
963 			iter->retlist = NULL;
964 			return (retcode);
965 		}
966 		iter->retcode = mappings->retcode;
967 		arg->lastrowid = mappings->lastrowid;
968 	}
969 
970 	if (mappings == NULL || mappings->mappings.mappings_len == 0)
971 		return (IDMAP_SUCCESS);
972 
973 	if (iter->next >= mappings->mappings.mappings_len) {
974 		return (IDMAP_ERR_ARG);
975 	}
976 
977 	if (sidprefix) {
978 		str = mappings->mappings.mappings_val[iter->next].id1.
979 		    idmap_id_u.sid.prefix;
980 		if (str && *str != '\0') {
981 			*sidprefix = strdup(str);
982 			if (*sidprefix == NULL) {
983 				retcode = IDMAP_ERR_MEMORY;
984 				goto errout;
985 			}
986 		}
987 	}
988 	if (rid)
989 		*rid = mappings->mappings.mappings_val[iter->next].id1.
990 		    idmap_id_u.sid.rid;
991 
992 	retcode = idmap_strdupnull(windomain,
993 	    mappings->mappings.mappings_val[iter->next].id1domain);
994 	if (retcode != IDMAP_SUCCESS)
995 		goto errout;
996 
997 	retcode = idmap_strdupnull(winname,
998 	    mappings->mappings.mappings_val[iter->next].id1name);
999 	if (retcode != IDMAP_SUCCESS)
1000 		goto errout;
1001 
1002 	retcode = idmap_strdupnull(unixname,
1003 	    mappings->mappings.mappings_val[iter->next].id2name);
1004 	if (retcode != IDMAP_SUCCESS)
1005 		goto errout;
1006 
1007 
1008 	if (pid)
1009 		*pid = mappings->mappings.mappings_val[iter->next].id2.
1010 		    idmap_id_u.uid;
1011 	if (direction)
1012 		*direction = mappings->mappings.mappings_val[iter->next].
1013 		    direction;
1014 	if (is_user)
1015 		*is_user = (mappings->mappings.mappings_val[iter->next].id2
1016 		    .idtype == IDMAP_UID)?1:0;
1017 	if (is_wuser)
1018 		*is_wuser = (mappings->mappings.mappings_val[iter->next].id1
1019 		    .idtype == IDMAP_USID)?1:0;
1020 
1021 	if (info) {
1022 		retcode = idmap_info_cpy(info,
1023 		    &mappings->mappings.mappings_val[iter->next].info);
1024 		if (retcode != IDMAP_SUCCESS)
1025 			goto errout;
1026 	}
1027 	iter->next++;
1028 
1029 	if (iter->next == mappings->mappings.mappings_len)
1030 		return (iter->retcode);
1031 	else
1032 		return (IDMAP_NEXT);
1033 
1034 errout:
1035 	if (sidprefix && *sidprefix)
1036 		free(*sidprefix);
1037 	if (winname && *winname)
1038 		free(*winname);
1039 	if (windomain && *windomain)
1040 		free(*windomain);
1041 	if (unixname && *unixname)
1042 		free(*unixname);
1043 	return (retcode);
1044 }
1045 
1046 
1047 /*
1048  * Destroy the iterator
1049  */
1050 void
1051 idmap_iter_destroy(idmap_iter_t *iter)
1052 {
1053 	xdrproc_t _xdr_argument, _xdr_result;
1054 
1055 	if (iter == NULL)
1056 		return;
1057 
1058 	switch (iter->type) {
1059 	case IDMAP_LIST_NAMERULES:
1060 		_xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
1061 		_xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
1062 		break;
1063 	case IDMAP_LIST_MAPPINGS:
1064 		_xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
1065 		_xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
1066 		break;
1067 	default:
1068 		free(iter);
1069 		return;
1070 	};
1071 
1072 	if (iter->arg) {
1073 		xdr_free(_xdr_argument, (caddr_t)iter->arg);
1074 		free(iter->arg);
1075 	}
1076 	if (iter->retlist) {
1077 		xdr_free(_xdr_result, (caddr_t)iter->retlist);
1078 		free(iter->retlist);
1079 	}
1080 	free(iter);
1081 }
1082 
1083 
1084 /*
1085  * Create handle to get SID to UID/GID mapping entries
1086  *
1087  * Input:
1088  * gh - "get mapping" handle
1089  */
1090 idmap_stat
1091 idmap_get_create(idmap_handle_t *handle, idmap_get_handle_t **gh)
1092 {
1093 	idmap_get_handle_t	*tmp;
1094 
1095 	/* sanity checks */
1096 	if (handle == NULL || gh == NULL) {
1097 		errno = EINVAL;
1098 		return (IDMAP_ERR_ARG);
1099 	}
1100 
1101 	/* allocate the handle */
1102 	if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
1103 		errno = ENOMEM;
1104 		return (IDMAP_ERR_MEMORY);
1105 	}
1106 
1107 	tmp->ih = handle;
1108 	*gh = tmp;
1109 	return (IDMAP_SUCCESS);
1110 }
1111 
1112 
1113 /*
1114  * Given SID, get UID
1115  *
1116  * Input:
1117  * sidprefix  - SID prefix
1118  * rid        - RID
1119  * flag       - flag
1120  *
1121  * Output:
1122  * stat - status of the get request
1123  * uid  - POSIX UID if stat = 0
1124  *
1125  * Note: The output parameters will be set by idmap_get_mappings()
1126  */
1127 idmap_stat
1128 idmap_get_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1129 		int flag, uid_t *uid, idmap_stat *stat)
1130 {
1131 	return (idmap_getext_uidbysid(gh, sidprefix, rid, flag, uid,
1132 	    NULL, stat));
1133 }
1134 
1135 /*
1136  * Given SID, get UID
1137  *
1138  * Input:
1139  * sidprefix  - SID prefix
1140  * rid        - RID
1141  * flag       - flag
1142  *
1143  * Output:
1144  * stat - status of the get request
1145  * uid  - POSIX UID if stat = 0
1146  * how  - mapping type if stat = 0
1147  *
1148  * Note: The output parameters will be set by idmap_get_mappings()
1149  */
1150 
1151 idmap_stat
1152 idmap_getext_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1153 		int flag, uid_t *uid, idmap_info *info, idmap_stat *stat)
1154 {
1155 	idmap_retcode	retcode;
1156 	idmap_mapping	*mapping = NULL;
1157 
1158 	/* sanity checks */
1159 	if (gh == NULL)
1160 		return (IDMAP_ERR_ARG);
1161 	if (uid == NULL || sidprefix == NULL)
1162 		return (IDMAP_ERR_ARG);
1163 
1164 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1165 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1166 		retcode = idmap_cache_lookup_uidbysid(sidprefix, rid, uid);
1167 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1168 			*stat = retcode;
1169 			return (retcode);
1170 		}
1171 	}
1172 
1173 	/* Extend the request array and the return list */
1174 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1175 		goto errout;
1176 
1177 	/* Setup the request */
1178 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1179 	mapping->flag = flag;
1180 	mapping->id1.idtype = IDMAP_SID;
1181 	mapping->id1.idmap_id_u.sid.rid = rid;
1182 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1183 		retcode = IDMAP_ERR_MEMORY;
1184 		goto errout;
1185 	}
1186 	mapping->id2.idtype = IDMAP_UID;
1187 
1188 	/* Setup pointers for the result */
1189 	gh->retlist[gh->next].idtype = IDMAP_UID;
1190 	gh->retlist[gh->next].uid = uid;
1191 	gh->retlist[gh->next].stat = stat;
1192 	gh->retlist[gh->next].info = info;
1193 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1194 
1195 	gh->next++;
1196 	return (IDMAP_SUCCESS);
1197 
1198 errout:
1199 	/* Batch created so far should still be usable */
1200 	if (mapping)
1201 		(void) memset(mapping, 0, sizeof (*mapping));
1202 	errno = idmap_stat2errno(retcode);
1203 	return (retcode);
1204 }
1205 
1206 
1207 /*
1208  * Given SID, get GID
1209  *
1210  * Input:
1211  * sidprefix  - SID prefix
1212  * rid        - rid
1213  * flag       - flag
1214  *
1215  * Output:
1216  * stat - status of the get request
1217  * gid  - POSIX GID if stat = 0
1218  *
1219  * Note: The output parameters will be set by idmap_get_mappings()
1220  */
1221 idmap_stat
1222 idmap_get_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1223 		int flag, gid_t *gid, idmap_stat *stat)
1224 {
1225 	return (idmap_getext_gidbysid(gh, sidprefix, rid, flag, gid,
1226 	    NULL, stat));
1227 }
1228 
1229 
1230 /*
1231  * Given SID, get GID
1232  *
1233  * Input:
1234  * sidprefix  - SID prefix
1235  * rid        - rid
1236  * flag       - flag
1237  *
1238  * Output:
1239  * stat - status of the get request
1240  * gid  - POSIX GID if stat = 0
1241  * how  - mapping type if stat = 0
1242  *
1243  * Note: The output parameters will be set by idmap_get_mappings()
1244  */
1245 idmap_stat
1246 idmap_getext_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1247 		int flag, gid_t *gid, idmap_info *info, idmap_stat *stat)
1248 {
1249 
1250 	idmap_retcode	retcode;
1251 	idmap_mapping	*mapping = NULL;
1252 
1253 	/* sanity checks */
1254 	if (gh == NULL)
1255 		return (IDMAP_ERR_ARG);
1256 	if (gid == NULL || sidprefix == NULL)
1257 		return (IDMAP_ERR_ARG);
1258 
1259 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1260 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1261 		retcode = idmap_cache_lookup_gidbysid(sidprefix, rid, gid);
1262 		if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1263 			*stat = retcode;
1264 			return (retcode);
1265 		}
1266 	}
1267 
1268 	/* Extend the request array and the return list */
1269 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1270 		goto errout;
1271 
1272 	/* Setup the request */
1273 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1274 	mapping->flag = flag;
1275 	mapping->id1.idtype = IDMAP_SID;
1276 	mapping->id1.idmap_id_u.sid.rid = rid;
1277 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1278 		retcode = IDMAP_ERR_MEMORY;
1279 		goto errout;
1280 	}
1281 	mapping->id2.idtype = IDMAP_GID;
1282 
1283 	/* Setup pointers for the result */
1284 	gh->retlist[gh->next].idtype = IDMAP_GID;
1285 	gh->retlist[gh->next].gid = gid;
1286 	gh->retlist[gh->next].stat = stat;
1287 	gh->retlist[gh->next].info = info;
1288 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1289 
1290 	gh->next++;
1291 	return (IDMAP_SUCCESS);
1292 
1293 errout:
1294 	if (mapping)
1295 		(void) memset(mapping, 0, sizeof (*mapping));
1296 	errno = idmap_stat2errno(retcode);
1297 	return (retcode);
1298 }
1299 
1300 
1301 
1302 /*
1303  * Given SID, get POSIX ID i.e. UID/GID
1304  *
1305  * Input:
1306  * sidprefix  - SID prefix
1307  * rid        - rid
1308  * flag       - flag
1309  *
1310  * Output:
1311  * stat    - status of the get request
1312  * is_user - user or group
1313  * pid     - POSIX UID if stat = 0 and is_user = 1
1314  *           POSIX GID if stat = 0 and is_user = 0
1315  *
1316  * Note: The output parameters will be set by idmap_get_mappings()
1317  */
1318 idmap_stat
1319 idmap_get_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1320 		int flag, uid_t *pid, int *is_user, idmap_stat *stat)
1321 {
1322 	return (idmap_getext_pidbysid(gh, sidprefix, rid, flag, pid, is_user,
1323 	    NULL, stat));
1324 }
1325 
1326 
1327 
1328 /*
1329  * Given SID, get POSIX ID i.e. UID/GID
1330  *
1331  * Input:
1332  * sidprefix  - SID prefix
1333  * rid        - rid
1334  * flag       - flag
1335  *
1336  * Output:
1337  * stat    - status of the get request
1338  * is_user - user or group
1339  * pid     - POSIX UID if stat = 0 and is_user = 1
1340  *           POSIX GID if stat = 0 and is_user = 0
1341  * how     - mapping type if stat = 0
1342  *
1343  * Note: The output parameters will be set by idmap_get_mappings()
1344  */
1345 idmap_stat
1346 idmap_getext_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1347 	int flag, uid_t *pid, int *is_user, idmap_info *info, idmap_stat *stat)
1348 {
1349 	idmap_retcode	retcode;
1350 	idmap_mapping	*mapping = NULL;
1351 
1352 	/* sanity checks */
1353 	if (gh == NULL)
1354 		return (IDMAP_ERR_ARG);
1355 	if (pid == NULL || sidprefix == NULL || is_user == NULL)
1356 		return (IDMAP_ERR_ARG);
1357 
1358 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1359 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1360 		retcode = idmap_cache_lookup_pidbysid(sidprefix, rid, pid,
1361 		    is_user);
1362 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1363 			*stat = retcode;
1364 			return (retcode);
1365 		}
1366 	}
1367 
1368 	/* Extend the request array and the return list */
1369 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1370 		goto errout;
1371 
1372 	/* Setup the request */
1373 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1374 	mapping->flag = flag;
1375 	mapping->id1.idtype = IDMAP_SID;
1376 	mapping->id1.idmap_id_u.sid.rid = rid;
1377 	if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1378 		retcode = IDMAP_ERR_MEMORY;
1379 		goto errout;
1380 	}
1381 	mapping->id2.idtype = IDMAP_POSIXID;
1382 
1383 	/* Setup pointers for the result */
1384 	gh->retlist[gh->next].idtype = IDMAP_POSIXID;
1385 	gh->retlist[gh->next].uid = pid;
1386 	gh->retlist[gh->next].gid = pid;
1387 	gh->retlist[gh->next].is_user = is_user;
1388 	gh->retlist[gh->next].stat = stat;
1389 	gh->retlist[gh->next].info = info;
1390 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1391 
1392 	gh->next++;
1393 	return (IDMAP_SUCCESS);
1394 
1395 errout:
1396 	if (mapping)
1397 		(void) memset(mapping, 0, sizeof (*mapping));
1398 	errno = idmap_stat2errno(retcode);
1399 	return (retcode);
1400 }
1401 
1402 
1403 /*
1404  * Given UID, get SID
1405  *
1406  * Input:
1407  * uid  - POSIX UID
1408  * flag - flag
1409  *
1410  * Output:
1411  * stat - status of the get request
1412  * sid  - SID prefix (if stat == 0)
1413  * rid  - rid
1414  *
1415  * Note: The output parameters will be set by idmap_get_mappings()
1416  */
1417 idmap_stat
1418 idmap_get_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
1419 		char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
1420 {
1421 	return (idmap_getext_sidbyuid(gh, uid, flag, sidprefix, rid,
1422 	    NULL, stat));
1423 }
1424 
1425 
1426 /*
1427  * Given UID, get SID
1428  *
1429  * Input:
1430  * uid  - POSIX UID
1431  * flag - flag
1432  *
1433  * Output:
1434  * stat - status of the get request
1435  * sid  - SID prefix (if stat == 0)
1436  * rid  - rid
1437  * how  - mapping type if stat = 0
1438  *
1439  * Note: The output parameters will be set by idmap_get_mappings()
1440  */
1441 idmap_stat
1442 idmap_getext_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
1443 	char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
1444 {
1445 
1446 	idmap_retcode	retcode;
1447 	idmap_mapping	*mapping = NULL;
1448 
1449 	/* sanity checks */
1450 	if (gh == NULL)
1451 		return (IDMAP_ERR_ARG);
1452 	if (sidprefix == NULL)
1453 		return (IDMAP_ERR_ARG);
1454 
1455 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1456 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1457 		retcode = idmap_cache_lookup_sidbyuid(sidprefix, rid, uid);
1458 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1459 			*stat = retcode;
1460 			return (retcode);
1461 		}
1462 	}
1463 
1464 	/* Extend the request array and the return list */
1465 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1466 		goto errout;
1467 
1468 	/* Setup the request */
1469 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1470 	mapping->flag = flag;
1471 	mapping->id1.idtype = IDMAP_UID;
1472 	mapping->id1.idmap_id_u.uid = uid;
1473 	mapping->id2.idtype = IDMAP_SID;
1474 
1475 	/* Setup pointers for the result */
1476 	gh->retlist[gh->next].idtype = IDMAP_SID;
1477 	gh->retlist[gh->next].sidprefix = sidprefix;
1478 	gh->retlist[gh->next].rid = rid;
1479 	gh->retlist[gh->next].stat = stat;
1480 	gh->retlist[gh->next].info = info;
1481 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1482 
1483 	gh->next++;
1484 	return (IDMAP_SUCCESS);
1485 
1486 errout:
1487 	if (mapping)
1488 		(void) memset(mapping, 0, sizeof (*mapping));
1489 	errno = idmap_stat2errno(retcode);
1490 	return (retcode);
1491 }
1492 
1493 
1494 /*
1495  * Given GID, get SID
1496  *
1497  * Input:
1498  * gid  - POSIX GID
1499  * flag - flag
1500  *
1501  * Output:
1502  * stat       - status of the get request
1503  * sidprefix  - SID prefix (if stat == 0)
1504  * rid        - rid
1505  *
1506  * Note: The output parameters will be set by idmap_get_mappings()
1507  */
1508 idmap_stat
1509 idmap_get_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
1510 		char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
1511 {
1512 	return (idmap_getext_sidbygid(gh, gid, flag, sidprefix, rid,
1513 	    NULL, stat));
1514 }
1515 
1516 
1517 /*
1518  * Given GID, get SID
1519  *
1520  * Input:
1521  * gid  - POSIX GID
1522  * flag - flag
1523  *
1524  * Output:
1525  * stat       - status of the get request
1526  * sidprefix  - SID prefix (if stat == 0)
1527  * rid        - rid
1528  * how        - mapping type if stat = 0
1529  *
1530  * Note: The output parameters will be set by idmap_get_mappings()
1531  */
1532 idmap_stat
1533 idmap_getext_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
1534 	char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
1535 {
1536 
1537 	idmap_retcode	retcode;
1538 	idmap_mapping	*mapping = NULL;
1539 
1540 	/* sanity checks */
1541 	if (gh == NULL)
1542 		return (IDMAP_ERR_ARG);
1543 	if (sidprefix == NULL)
1544 		return (IDMAP_ERR_ARG);
1545 
1546 	if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1547 	    !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1548 		retcode = idmap_cache_lookup_sidbygid(sidprefix, rid, gid);
1549 		if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1550 			*stat = retcode;
1551 			return (retcode);
1552 		}
1553 	}
1554 
1555 	/* Extend the request array and the return list */
1556 	if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1557 		goto errout;
1558 
1559 	/* Setup the request */
1560 	mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1561 	mapping->flag = flag;
1562 	mapping->id1.idtype = IDMAP_GID;
1563 	mapping->id1.idmap_id_u.gid = gid;
1564 	mapping->id2.idtype = IDMAP_SID;
1565 
1566 	/* Setup pointers for the result */
1567 	gh->retlist[gh->next].idtype = IDMAP_SID;
1568 	gh->retlist[gh->next].sidprefix = sidprefix;
1569 	gh->retlist[gh->next].rid = rid;
1570 	gh->retlist[gh->next].stat = stat;
1571 	gh->retlist[gh->next].info = info;
1572 	gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1573 
1574 	gh->next++;
1575 	return (IDMAP_SUCCESS);
1576 
1577 errout:
1578 	if (mapping)
1579 		(void) memset(mapping, 0, sizeof (*mapping));
1580 	errno = idmap_stat2errno(retcode);
1581 	return (retcode);
1582 }
1583 
1584 
1585 /*
1586  * Process the batched "get mapping" requests. The results (i.e.
1587  * status and identity) will be available in the data areas
1588  * provided by individual requests.
1589  */
1590 idmap_stat
1591 idmap_get_mappings(idmap_get_handle_t *gh)
1592 {
1593 	CLIENT		*clnt;
1594 	enum clnt_stat	clntstat;
1595 	idmap_retcode	retcode;
1596 	idmap_ids_res	res;
1597 	idmap_id	*res_id;
1598 	int		i;
1599 	idmap_id	*req_id;
1600 	int		direction;
1601 
1602 	if (gh == NULL) {
1603 		errno = EINVAL;
1604 		return (IDMAP_ERR_ARG);
1605 	}
1606 	_IDMAP_GET_CLIENT_HANDLE(gh->ih, clnt);
1607 
1608 	(void) memset(&res, 0, sizeof (idmap_ids_res));
1609 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_IDS,
1610 	    (xdrproc_t)xdr_idmap_mapping_batch,
1611 	    (caddr_t)&gh->batch,
1612 	    (xdrproc_t)xdr_idmap_ids_res,
1613 	    (caddr_t)&res,
1614 	    TIMEOUT);
1615 	if (clntstat != RPC_SUCCESS) {
1616 		retcode = _idmap_rpc2stat(clnt);
1617 		goto out;
1618 	}
1619 	if (res.retcode != IDMAP_SUCCESS) {
1620 		retcode = res.retcode;
1621 		goto out;
1622 	}
1623 	for (i = 0; i < gh->next; i++) {
1624 		if (i >= res.ids.ids_len) {
1625 			*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1626 			continue;
1627 		}
1628 		*gh->retlist[i].stat = res.ids.ids_val[i].retcode;
1629 		res_id = &res.ids.ids_val[i].id;
1630 		direction = res.ids.ids_val[i].direction;
1631 		req_id = &gh->batch.idmap_mapping_batch_val[i].id1;
1632 		switch (res_id->idtype) {
1633 		case IDMAP_UID:
1634 			if (gh->retlist[i].uid)
1635 				*gh->retlist[i].uid = res_id->idmap_id_u.uid;
1636 			if (gh->retlist[i].is_user)
1637 				*gh->retlist[i].is_user = 1;
1638 
1639 			if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1640 			    gh->retlist[i].cache_res) {
1641 				if (gh->retlist[i].is_user != NULL)
1642 					idmap_cache_add_sid2pid(
1643 					    req_id->idmap_id_u.sid.prefix,
1644 					    req_id->idmap_id_u.sid.rid,
1645 					    res_id->idmap_id_u.uid, 1,
1646 					    direction);
1647 				else
1648 					idmap_cache_add_sid2uid(
1649 					    req_id->idmap_id_u.sid.prefix,
1650 					    req_id->idmap_id_u.sid.rid,
1651 					    res_id->idmap_id_u.uid,
1652 					    direction);
1653 			}
1654 			break;
1655 
1656 		case IDMAP_GID:
1657 			if (gh->retlist[i].gid)
1658 				*gh->retlist[i].gid = res_id->idmap_id_u.gid;
1659 			if (gh->retlist[i].is_user)
1660 				*gh->retlist[i].is_user = 0;
1661 
1662 			if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1663 			    gh->retlist[i].cache_res) {
1664 				if (gh->retlist[i].is_user != NULL)
1665 					idmap_cache_add_sid2pid(
1666 					    req_id->idmap_id_u.sid.prefix,
1667 					    req_id->idmap_id_u.sid.rid,
1668 					    res_id->idmap_id_u.gid, 0,
1669 					    direction);
1670 				else
1671 					idmap_cache_add_sid2gid(
1672 					    req_id->idmap_id_u.sid.prefix,
1673 					    req_id->idmap_id_u.sid.rid,
1674 					    res_id->idmap_id_u.gid,
1675 					    direction);
1676 			}
1677 			break;
1678 
1679 		case IDMAP_POSIXID:
1680 			if (gh->retlist[i].uid)
1681 				*gh->retlist[i].uid = 60001;
1682 			if (gh->retlist[i].is_user)
1683 				*gh->retlist[i].is_user = -1;
1684 			break;
1685 
1686 		case IDMAP_SID:
1687 		case IDMAP_USID:
1688 		case IDMAP_GSID:
1689 			if (gh->retlist[i].rid)
1690 				*gh->retlist[i].rid =
1691 				    res_id->idmap_id_u.sid.rid;
1692 			if (gh->retlist[i].sidprefix) {
1693 				if (res_id->idmap_id_u.sid.prefix == NULL ||
1694 				    *res_id->idmap_id_u.sid.prefix == '\0') {
1695 					*gh->retlist[i].sidprefix = NULL;
1696 					break;
1697 				}
1698 				*gh->retlist[i].sidprefix =
1699 				    strdup(res_id->idmap_id_u.sid.prefix);
1700 				if (*gh->retlist[i].sidprefix == NULL)
1701 					*gh->retlist[i].stat =
1702 					    IDMAP_ERR_MEMORY;
1703 			}
1704 			if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1705 			    gh->retlist[i].cache_res) {
1706 				if (req_id->idtype == IDMAP_UID)
1707 					idmap_cache_add_sid2uid(
1708 					    res_id->idmap_id_u.sid.prefix,
1709 					    res_id->idmap_id_u.sid.rid,
1710 					    req_id->idmap_id_u.uid,
1711 					    direction);
1712 				else /* req_id->idtype == IDMAP_GID */
1713 					idmap_cache_add_sid2gid(
1714 					    res_id->idmap_id_u.sid.prefix,
1715 					    res_id->idmap_id_u.sid.rid,
1716 					    req_id->idmap_id_u.gid,
1717 					    direction);
1718 			}
1719 			break;
1720 
1721 		case IDMAP_NONE:
1722 			break;
1723 
1724 		default:
1725 			*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1726 			break;
1727 		}
1728 		if (gh->retlist[i].info != NULL)
1729 			(void) idmap_info_cpy(gh->retlist[i].info,
1730 			    &res.ids.ids_val[i].info);
1731 	}
1732 	retcode = IDMAP_SUCCESS;
1733 
1734 out:
1735 	_IDMAP_RESET_GET_HANDLE(gh);
1736 	(void) xdr_free(xdr_idmap_ids_res, (caddr_t)&res);
1737 	errno = idmap_stat2errno(retcode);
1738 	return (retcode);
1739 }
1740 
1741 
1742 /*
1743  * Destroy the "get mapping" handle
1744  */
1745 void
1746 idmap_get_destroy(idmap_get_handle_t *gh)
1747 {
1748 	if (gh == NULL)
1749 		return;
1750 	(void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
1751 	if (gh->retlist)
1752 		free(gh->retlist);
1753 	free(gh);
1754 }
1755 
1756 
1757 /*
1758  * Get windows to unix mapping
1759  */
1760 idmap_stat
1761 idmap_get_w2u_mapping(idmap_handle_t *handle,
1762 		const char *sidprefix, idmap_rid_t *rid,
1763 		const char *winname, const char *windomain,
1764 		int flag, int *is_user, int *is_wuser,
1765 		uid_t *pid, char **unixname, int *direction, idmap_info *info)
1766 {
1767 	CLIENT			*clnt;
1768 	enum clnt_stat		clntstat;
1769 	idmap_mapping		request, *mapping;
1770 	idmap_mappings_res	result;
1771 	idmap_retcode		retcode, rc;
1772 
1773 	if (handle == NULL) {
1774 		errno = EINVAL;
1775 		return (IDMAP_ERR_ARG);
1776 	}
1777 
1778 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1779 
1780 	(void) memset(&request, 0, sizeof (request));
1781 	(void) memset(&result, 0, sizeof (result));
1782 
1783 	if (pid)
1784 		*pid = UINT32_MAX;
1785 	if (unixname)
1786 		*unixname = NULL;
1787 	if (direction)
1788 		*direction = IDMAP_DIRECTION_UNDEF;
1789 
1790 	request.flag = flag;
1791 	request.id1.idtype = IDMAP_SID;
1792 	if (sidprefix && rid) {
1793 		request.id1.idmap_id_u.sid.prefix = (char *)sidprefix;
1794 		request.id1.idmap_id_u.sid.rid = *rid;
1795 	} else if (winname) {
1796 		retcode = idmap_strdupnull(&request.id1name, winname);
1797 		if (retcode != IDMAP_SUCCESS)
1798 			goto out;
1799 
1800 		retcode = idmap_strdupnull(&request.id1domain, windomain);
1801 		if (retcode != IDMAP_SUCCESS)
1802 			goto out;
1803 
1804 		request.id1.idmap_id_u.sid.prefix = NULL;
1805 	} else {
1806 		errno = EINVAL;
1807 		return (IDMAP_ERR_ARG);
1808 	}
1809 
1810 	if (*is_user == 1)
1811 		request.id2.idtype = IDMAP_UID;
1812 	else if (*is_user == 0)
1813 		request.id2.idtype = IDMAP_GID;
1814 	else
1815 		request.id2.idtype = IDMAP_POSIXID;
1816 
1817 	if (*is_wuser == 1)
1818 		request.id1.idtype = IDMAP_USID;
1819 	else if (*is_wuser == 0)
1820 		request.id1.idtype = IDMAP_GSID;
1821 	else
1822 		request.id1.idtype = IDMAP_SID;
1823 
1824 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1825 	    (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1826 	    (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1827 	    TIMEOUT);
1828 
1829 	if (clntstat != RPC_SUCCESS)
1830 		return (_idmap_rpc2stat(clnt));
1831 
1832 	retcode = result.retcode;
1833 
1834 	if ((mapping = result.mappings.mappings_val) == NULL) {
1835 		if (retcode == IDMAP_SUCCESS)
1836 			retcode = IDMAP_ERR_NORESULT;
1837 		goto out;
1838 	}
1839 
1840 	if (mapping->id2.idtype == IDMAP_UID) {
1841 		*is_user = 1;
1842 	} else if (mapping->id2.idtype == IDMAP_GID) {
1843 		*is_user = 0;
1844 	} else {
1845 		goto out;
1846 	}
1847 
1848 	if (mapping->id1.idtype == IDMAP_USID) {
1849 		*is_wuser = 1;
1850 	} else if (mapping->id1.idtype == IDMAP_GSID) {
1851 		*is_wuser = 0;
1852 	} else {
1853 		goto out;
1854 	}
1855 
1856 	if (direction)
1857 		*direction = mapping->direction;
1858 	if (pid)
1859 		*pid = mapping->id2.idmap_id_u.uid;
1860 
1861 	rc = idmap_strdupnull(unixname, mapping->id2name);
1862 	if (rc != IDMAP_SUCCESS)
1863 		retcode = rc;
1864 
1865 	rc = idmap_info_cpy(info, &mapping->info);
1866 	if (rc != IDMAP_SUCCESS)
1867 		retcode = rc;
1868 
1869 out:
1870 	if (request.id1name != NULL)
1871 		free(request.id1name);
1872 	if (request.id1domain != NULL)
1873 		free(request.id1domain);
1874 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1875 	if (retcode != IDMAP_SUCCESS)
1876 		errno = idmap_stat2errno(retcode);
1877 	return (retcode);
1878 }
1879 
1880 
1881 /*
1882  * Get unix to windows mapping
1883  */
1884 idmap_stat
1885 idmap_get_u2w_mapping(idmap_handle_t *handle,
1886 		uid_t *pid, const char *unixname,
1887 		int flag, int is_user, int *is_wuser,
1888 		char **sidprefix, idmap_rid_t *rid,
1889 		char **winname, char **windomain,
1890 		int *direction, idmap_info *info)
1891 {
1892 	CLIENT			*clnt;
1893 	enum clnt_stat		clntstat;
1894 	idmap_mapping		request, *mapping;
1895 	idmap_mappings_res	result;
1896 	idmap_retcode		retcode, rc;
1897 
1898 	if (handle == NULL) {
1899 		errno = EINVAL;
1900 		return (IDMAP_ERR_ARG);
1901 	}
1902 
1903 	_IDMAP_GET_CLIENT_HANDLE(handle, clnt);
1904 
1905 	if (sidprefix)
1906 		*sidprefix = NULL;
1907 	if (winname)
1908 		*winname = NULL;
1909 	if (windomain)
1910 		*windomain = NULL;
1911 	if (rid)
1912 		*rid = UINT32_MAX;
1913 	if (direction)
1914 		*direction = IDMAP_DIRECTION_UNDEF;
1915 
1916 	(void) memset(&request, 0, sizeof (request));
1917 	(void) memset(&result, 0, sizeof (result));
1918 
1919 	request.flag = flag;
1920 	request.id1.idtype = is_user?IDMAP_UID:IDMAP_GID;
1921 
1922 	if (pid && *pid != UINT32_MAX) {
1923 		request.id1.idmap_id_u.uid = *pid;
1924 	} else if (unixname) {
1925 		request.id1name = (char *)unixname;
1926 		request.id1.idmap_id_u.uid = UINT32_MAX;
1927 	} else {
1928 		errno = EINVAL;
1929 		return (IDMAP_ERR_ARG);
1930 	}
1931 
1932 	if (is_wuser == NULL)
1933 		request.id2.idtype = IDMAP_SID;
1934 	else if (*is_wuser == -1)
1935 		request.id2.idtype = IDMAP_SID;
1936 	else if (*is_wuser == 0)
1937 		request.id2.idtype = IDMAP_GSID;
1938 	else if (*is_wuser == 1)
1939 		request.id2.idtype = IDMAP_USID;
1940 
1941 	clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
1942 	    (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1943 	    (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1944 	    TIMEOUT);
1945 
1946 	if (clntstat != RPC_SUCCESS)
1947 		return (_idmap_rpc2stat(clnt));
1948 
1949 	retcode = result.retcode;
1950 
1951 	if ((mapping = result.mappings.mappings_val) == NULL) {
1952 		if (retcode == IDMAP_SUCCESS)
1953 			retcode = IDMAP_ERR_NORESULT;
1954 		goto out;
1955 	}
1956 
1957 	if (direction != NULL)
1958 		*direction = mapping->direction;
1959 
1960 	if (is_wuser != NULL) {
1961 		if (mapping->id2.idtype == IDMAP_USID)
1962 			*is_wuser = 1;
1963 		else if (mapping->id2.idtype == IDMAP_GSID)
1964 			*is_wuser = 0;
1965 		else
1966 			*is_wuser = -1;
1967 	}
1968 
1969 	if (sidprefix && mapping->id2.idmap_id_u.sid.prefix &&
1970 	    *mapping->id2.idmap_id_u.sid.prefix != '\0') {
1971 		*sidprefix = strdup(mapping->id2.idmap_id_u.sid.prefix);
1972 		if (*sidprefix == NULL) {
1973 			retcode = IDMAP_ERR_MEMORY;
1974 			goto errout;
1975 		}
1976 	}
1977 	if (rid)
1978 		*rid = mapping->id2.idmap_id_u.sid.rid;
1979 
1980 	rc = idmap_strdupnull(winname, mapping->id2name);
1981 	if (rc != IDMAP_SUCCESS)
1982 		retcode = rc;
1983 
1984 	rc = idmap_strdupnull(windomain, mapping->id2domain);
1985 	if (rc != IDMAP_SUCCESS)
1986 		retcode = rc;
1987 
1988 	rc = idmap_info_cpy(info, &mapping->info);
1989 	if (rc != IDMAP_SUCCESS)
1990 		retcode = rc;
1991 
1992 	goto out;
1993 
1994 errout:
1995 	if (sidprefix && *sidprefix) {
1996 		free(*sidprefix);
1997 		*sidprefix = NULL;
1998 	}
1999 	if (winname && *winname) {
2000 		free(*winname);
2001 		*winname = NULL;
2002 	}
2003 	if (windomain && *windomain) {
2004 		free(*windomain);
2005 		*windomain = NULL;
2006 	}
2007 
2008 out:
2009 	xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
2010 	if (retcode != IDMAP_SUCCESS)
2011 		errno = idmap_stat2errno(retcode);
2012 	return (retcode);
2013 }
2014 
2015 
2016 
2017 #define	gettext(s)	s
2018 static stat_table_t stattable[] = {
2019 	{IDMAP_SUCCESS, gettext("Success"), 0},
2020 	{IDMAP_NEXT, gettext("More results available"), 0},
2021 	{IDMAP_ERR_OTHER, gettext("Undefined error"), EINVAL},
2022 	{IDMAP_ERR_INTERNAL, gettext("Internal error"), EINVAL},
2023 	{IDMAP_ERR_MEMORY, gettext("Out of memory"), ENOMEM},
2024 	{IDMAP_ERR_NORESULT, gettext("No results available"), EINVAL},
2025 	{IDMAP_ERR_NOTUSER, gettext("Not a user"), EINVAL},
2026 	{IDMAP_ERR_NOTGROUP, gettext("Not a group"), EINVAL},
2027 	{IDMAP_ERR_NOTSUPPORTED, gettext("Operation not supported"), ENOTSUP},
2028 	{IDMAP_ERR_W2U_NAMERULE,
2029 		gettext("Invalid Windows to UNIX name-based rule"), EINVAL},
2030 	{IDMAP_ERR_U2W_NAMERULE,
2031 		gettext("Invalid UNIX to Windows name-based rule"), EINVAL},
2032 	{IDMAP_ERR_CACHE, gettext("Invalid cache"), EINVAL},
2033 	{IDMAP_ERR_DB, gettext("Invalid database"), EINVAL},
2034 	{IDMAP_ERR_ARG, gettext("Invalid argument"), EINVAL},
2035 	{IDMAP_ERR_SID, gettext("Invalid SID"), EINVAL},
2036 	{IDMAP_ERR_IDTYPE, gettext("Invalid identity type"), EINVAL},
2037 	{IDMAP_ERR_RPC_HANDLE, gettext("Bad RPC handle"), EBADF},
2038 	{IDMAP_ERR_RPC, gettext("RPC error"), EINVAL},
2039 	{IDMAP_ERR_CLIENT_HANDLE, gettext("Bad client handle"), EINVAL},
2040 	{IDMAP_ERR_BUSY, gettext("Server is busy"), EBUSY},
2041 	{IDMAP_ERR_PERMISSION_DENIED, gettext("Permission denied"), EACCES},
2042 	{IDMAP_ERR_NOMAPPING,
2043 		gettext("Mapping not found or inhibited"), EINVAL},
2044 	{IDMAP_ERR_NEW_ID_ALLOC_REQD,
2045 		gettext("New mapping needs to be created"), EINVAL},
2046 	{IDMAP_ERR_DOMAIN, gettext("Invalid domain"), EINVAL},
2047 	{IDMAP_ERR_SECURITY, gettext("Security issue"), EINVAL},
2048 	{IDMAP_ERR_NOTFOUND, gettext("Not found"), EINVAL},
2049 	{IDMAP_ERR_DOMAIN_NOTFOUND, gettext("Domain not found"), EINVAL},
2050 	{IDMAP_ERR_UPDATE_NOTALLOWED, gettext("Update not allowed"), EINVAL},
2051 	{IDMAP_ERR_CFG, gettext("Configuration error"), EINVAL},
2052 	{IDMAP_ERR_CFG_CHANGE, gettext("Invalid configuration change"), EINVAL},
2053 	{IDMAP_ERR_NOTMAPPED_WELLKNOWN,
2054 		gettext("No mapping for well-known SID"), EINVAL},
2055 	{IDMAP_ERR_RETRIABLE_NET_ERR,
2056 		gettext("Windows lookup failed"), EINVAL},
2057 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
2058 		gettext("Duplicate rule or conflicts with an existing "
2059 		"Windows to UNIX name-based rule"), EINVAL},
2060 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
2061 		gettext("Duplicate rule or conflicts with an existing "
2062 		"Unix to Windows name-based rule"), EINVAL},
2063 	{IDMAP_ERR_BAD_UTF8,
2064 		gettext("Invalid or illegal UTF-8 sequence found in "
2065 		"a given Windows entity name or domain name"), EINVAL},
2066 	{IDMAP_ERR_NONEGENERATED,
2067 		gettext("Mapping not found and none created (see -c option)"),
2068 		EINVAL},
2069 	{IDMAP_ERR_PROP_UNKNOWN,
2070 		gettext("Undefined property"),
2071 		EINVAL},
2072 	{IDMAP_ERR_NS_LDAP_CFG,
2073 		gettext("Native LDAP configuration error"), EINVAL},
2074 	{IDMAP_ERR_NS_LDAP_PARTIAL,
2075 		gettext("Partial result from Native LDAP"), EINVAL},
2076 	{IDMAP_ERR_NS_LDAP_OP_FAILED,
2077 		gettext("Native LDAP operation failed"), EINVAL},
2078 	{IDMAP_ERR_NS_LDAP_BAD_WINNAME,
2079 		gettext("Improper winname form found in Native LDAP"), EINVAL},
2080 	{-1, NULL, 0}
2081 };
2082 #undef	gettext
2083 
2084 
2085 /*
2086  * Get description of status code
2087  *
2088  * Input:
2089  * status - Status code returned by libidmap API call
2090  *
2091  * Return Value:
2092  * human-readable localized description of idmap_stat
2093  */
2094 /* ARGSUSED */
2095 const char *
2096 idmap_stat2string(idmap_handle_t *handle, idmap_stat status)
2097 {
2098 	int i;
2099 
2100 	for (i = 0; stattable[i].msg; i++) {
2101 		if (stattable[i].retcode == status)
2102 			return (gettext(stattable[i].msg));
2103 	}
2104 	return (gettext("Unknown error"));
2105 }
2106 
2107 
2108 static int
2109 idmap_stat2errno(idmap_stat stat)
2110 {
2111 	int i;
2112 	for (i = 0; stattable[i].msg; i++) {
2113 		if (stattable[i].retcode == stat)
2114 			return (stattable[i].errnum);
2115 	}
2116 	return (EINVAL);
2117 }
2118 
2119 
2120 /*
2121  * Get status code from string
2122  */
2123 idmap_stat
2124 idmap_string2stat(const char *str)
2125 {
2126 	if (str == NULL)
2127 		return (IDMAP_ERR_INTERNAL);
2128 
2129 #define	return_cmp(a) \
2130 	if (0 == strcmp(str, "IDMAP_ERR_" #a)) \
2131 		return (IDMAP_ERR_ ## a);
2132 
2133 	return_cmp(OTHER);
2134 	return_cmp(INTERNAL);
2135 	return_cmp(MEMORY);
2136 	return_cmp(NORESULT);
2137 	return_cmp(NOTUSER);
2138 	return_cmp(NOTGROUP);
2139 	return_cmp(NOTSUPPORTED);
2140 	return_cmp(W2U_NAMERULE);
2141 	return_cmp(U2W_NAMERULE);
2142 	return_cmp(CACHE);
2143 	return_cmp(DB);
2144 	return_cmp(ARG);
2145 	return_cmp(SID);
2146 	return_cmp(IDTYPE);
2147 	return_cmp(RPC_HANDLE);
2148 	return_cmp(RPC);
2149 	return_cmp(CLIENT_HANDLE);
2150 	return_cmp(BUSY);
2151 	return_cmp(PERMISSION_DENIED);
2152 	return_cmp(NOMAPPING);
2153 	return_cmp(NEW_ID_ALLOC_REQD);
2154 	return_cmp(DOMAIN);
2155 	return_cmp(SECURITY);
2156 	return_cmp(NOTFOUND);
2157 	return_cmp(DOMAIN_NOTFOUND);
2158 	return_cmp(MEMORY);
2159 	return_cmp(UPDATE_NOTALLOWED);
2160 	return_cmp(CFG);
2161 	return_cmp(CFG_CHANGE);
2162 	return_cmp(NOTMAPPED_WELLKNOWN);
2163 	return_cmp(RETRIABLE_NET_ERR);
2164 	return_cmp(W2U_NAMERULE_CONFLICT);
2165 	return_cmp(U2W_NAMERULE_CONFLICT);
2166 	return_cmp(BAD_UTF8);
2167 	return_cmp(NONEGENERATED);
2168 	return_cmp(PROP_UNKNOWN);
2169 	return_cmp(NS_LDAP_CFG);
2170 	return_cmp(NS_LDAP_PARTIAL);
2171 	return_cmp(NS_LDAP_OP_FAILED);
2172 	return_cmp(NS_LDAP_BAD_WINNAME);
2173 #undef return_cmp
2174 
2175 	return (IDMAP_ERR_OTHER);
2176 }
2177 
2178 
2179 /*
2180  * Map the given status to one that can be returned by the protocol
2181  */
2182 idmap_stat
2183 idmap_stat4prot(idmap_stat status)
2184 {
2185 	switch (status) {
2186 	case IDMAP_ERR_MEMORY:
2187 	case IDMAP_ERR_CACHE:
2188 		return (IDMAP_ERR_INTERNAL);
2189 	}
2190 	return (status);
2191 }
2192 
2193 
2194 /*
2195  * This is a convenience routine which duplicates a string after
2196  * checking for NULL pointers. This function will return success if
2197  * either the 'to' OR 'from' pointers are NULL.
2198  */
2199 static idmap_stat
2200 idmap_strdupnull(char **to, const char *from)
2201 {
2202 	if (to == NULL)
2203 		return (IDMAP_SUCCESS);
2204 
2205 	if (from == NULL || *from == '\0') {
2206 		*to = NULL;
2207 		return (IDMAP_SUCCESS);
2208 	}
2209 
2210 	*to = strdup(from);
2211 	if (*to == NULL)
2212 		return (IDMAP_ERR_MEMORY);
2213 	return (IDMAP_SUCCESS);
2214 }
2215 
2216 
2217 idmap_stat
2218 idmap_namerule_cpy(idmap_namerule *to, idmap_namerule *from)
2219 {
2220 	idmap_stat retval;
2221 
2222 	if (to == NULL)
2223 		return (IDMAP_SUCCESS);
2224 
2225 	(void) memcpy(to, from, sizeof (idmap_namerule));
2226 	to->windomain = NULL;
2227 	to->winname = NULL;
2228 	to->unixname = NULL;
2229 
2230 	retval = idmap_strdupnull(&to->windomain, from->windomain);
2231 	if (retval != IDMAP_SUCCESS)
2232 		return (retval);
2233 
2234 	retval = idmap_strdupnull(&to->winname, from->winname);
2235 	if (retval != IDMAP_SUCCESS) {
2236 		free(to->windomain);
2237 		to->windomain = NULL;
2238 		return (retval);
2239 	}
2240 
2241 	retval = idmap_strdupnull(&to->unixname, from->unixname);
2242 	if (retval != IDMAP_SUCCESS) {
2243 		free(to->windomain);
2244 		to->windomain = NULL;
2245 		free(to->winname);
2246 		to->winname = NULL;
2247 		return (retval);
2248 	}
2249 
2250 	return (retval);
2251 }
2252 
2253 
2254 static
2255 idmap_stat
2256 idmap_how_ds_based_cpy(idmap_how_ds_based *to, idmap_how_ds_based *from)
2257 {
2258 	idmap_stat retval;
2259 
2260 	if (to == NULL)
2261 		return (IDMAP_SUCCESS);
2262 
2263 	retval = idmap_strdupnull(&to->dn, from->dn);
2264 	if (retval != IDMAP_SUCCESS)
2265 		return (retval);
2266 
2267 	retval = idmap_strdupnull(&to->attr, from->attr);
2268 	if (retval != IDMAP_SUCCESS) {
2269 		free(to->dn);
2270 		to->dn = NULL;
2271 		return (retval);
2272 	}
2273 
2274 	retval = idmap_strdupnull(&to->value, from->value);
2275 	if (retval != IDMAP_SUCCESS) {
2276 		free(to->dn);
2277 		to->dn = NULL;
2278 		free(to->attr);
2279 		to->attr = NULL;
2280 		return (retval);
2281 	}
2282 
2283 	return (retval);
2284 }
2285 
2286 
2287 idmap_stat
2288 idmap_info_cpy(idmap_info *to, idmap_info *from)
2289 {
2290 	idmap_stat retval = IDMAP_SUCCESS;
2291 
2292 	if (to == NULL)
2293 		return (IDMAP_SUCCESS);
2294 
2295 	(void) memset(to, 0, sizeof (idmap_info));
2296 
2297 	to->src = from->src;
2298 	to->how.map_type = from->how.map_type;
2299 	switch (to->how.map_type) {
2300 	case IDMAP_MAP_TYPE_DS_AD:
2301 		retval = idmap_how_ds_based_cpy(&to->how.idmap_how_u.ad,
2302 		    &from->how.idmap_how_u.ad);
2303 		break;
2304 
2305 	case IDMAP_MAP_TYPE_DS_NLDAP:
2306 		retval = idmap_how_ds_based_cpy(&to->how.idmap_how_u.nldap,
2307 		    &from->how.idmap_how_u.nldap);
2308 		break;
2309 
2310 	case IDMAP_MAP_TYPE_RULE_BASED:
2311 		retval = idmap_namerule_cpy(&to->how.idmap_how_u.rule,
2312 		    &from->how.idmap_how_u.rule);
2313 		break;
2314 
2315 	case IDMAP_MAP_TYPE_EPHEMERAL:
2316 		break;
2317 
2318 	case IDMAP_MAP_TYPE_LOCAL_SID:
2319 		break;
2320 
2321 	case IDMAP_MAP_TYPE_KNOWN_SID:
2322 		break;
2323 	}
2324 	return (retval);
2325 }
2326 
2327 
2328 /*
2329  * This routine is similar to idmap_info_cpy, but the strings
2330  * are moved from the "from" info to the "to" info.
2331  * This routine is equivelent of:
2332  *
2333  *	idmap_info_cpy(to,from);
2334  *	idmap_info_free(from);
2335  */
2336 idmap_stat
2337 idmap_info_mov(idmap_info *to, idmap_info *from)
2338 {
2339 	idmap_stat retval = IDMAP_SUCCESS;
2340 
2341 	if (to == NULL) {
2342 		idmap_info_free(from);
2343 		return (IDMAP_SUCCESS);
2344 	}
2345 	(void) memcpy(to, from, sizeof (idmap_info));
2346 
2347 	(void) memset(from, 0, sizeof (idmap_info));
2348 
2349 	return (retval);
2350 }
2351 
2352 
2353 void
2354 idmap_info_free(idmap_info *info)
2355 {
2356 	idmap_how *how;
2357 
2358 	if (info == NULL)
2359 		return;
2360 
2361 	how = &info->how;
2362 	switch (how->map_type) {
2363 	case IDMAP_MAP_TYPE_DS_AD:
2364 		free(how->idmap_how_u.ad.dn);
2365 		how->idmap_how_u.ad.dn = NULL;
2366 		free(how->idmap_how_u.ad.attr);
2367 		how->idmap_how_u.ad.attr = NULL;
2368 		free(how->idmap_how_u.ad.value);
2369 		how->idmap_how_u.ad.value = NULL;
2370 		break;
2371 
2372 	case IDMAP_MAP_TYPE_DS_NLDAP:
2373 		free(how->idmap_how_u.nldap.dn);
2374 		how->idmap_how_u.nldap.dn = NULL;
2375 		free(how->idmap_how_u.nldap.attr);
2376 		how->idmap_how_u.nldap.attr = NULL;
2377 		free(how->idmap_how_u.nldap.value);
2378 		how->idmap_how_u.nldap.value = NULL;
2379 		break;
2380 
2381 	case IDMAP_MAP_TYPE_RULE_BASED:
2382 		free(how->idmap_how_u.rule.windomain);
2383 		how->idmap_how_u.rule.windomain = NULL;
2384 		free(how->idmap_how_u.rule.winname);
2385 		how->idmap_how_u.rule.winname = NULL;
2386 		free(how->idmap_how_u.rule.unixname);
2387 		how->idmap_how_u.rule.unixname = NULL;
2388 		break;
2389 
2390 	case IDMAP_MAP_TYPE_EPHEMERAL:
2391 		break;
2392 
2393 	case IDMAP_MAP_TYPE_LOCAL_SID:
2394 		break;
2395 	}
2396 	how->map_type = IDMAP_MAP_TYPE_UNKNOWN;
2397 	info->src = IDMAP_MAP_SRC_UNKNOWN;
2398 }
2399 
2400 
2401 /*
2402  * Get uid given Windows name
2403  */
2404 idmap_stat
2405 idmap_getuidbywinname(const char *name, const char *domain, int flag,
2406 	uid_t *uid)
2407 {
2408 	idmap_handle_t	*ih;
2409 	idmap_retcode	rc;
2410 	int		is_user = 1;
2411 	int		is_wuser = -1;
2412 	int 		direction;
2413 
2414 	if (uid == NULL)
2415 		return (IDMAP_ERR_ARG);
2416 
2417 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2418 		rc = idmap_cache_lookup_uidbywinname(name, domain, uid);
2419 		if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
2420 			return (rc);
2421 	}
2422 	/* Get mapping */
2423 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
2424 		return (rc);
2425 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, flag,
2426 	    &is_user, &is_wuser, uid, NULL, &direction, NULL);
2427 	(void) idmap_fini(ih);
2428 
2429 	if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
2430 		/* If we have not got the domain don't store UID to winname */
2431 		if (domain == NULL)
2432 			direction = IDMAP_DIRECTION_W2U;
2433 		idmap_cache_add_winname2uid(name, domain, *uid, direction);
2434 	}
2435 
2436 	return (rc);
2437 }
2438 
2439 
2440 /*
2441  * Get gid given Windows name
2442  */
2443 idmap_stat
2444 idmap_getgidbywinname(const char *name, const char *domain, int flag,
2445 	gid_t *gid)
2446 {
2447 	idmap_handle_t	*ih;
2448 	idmap_retcode	rc;
2449 	int		is_user = 0;
2450 	int		is_wuser = -1;
2451 	int		direction;
2452 
2453 	if (gid == NULL)
2454 		return (IDMAP_ERR_ARG);
2455 
2456 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2457 		rc = idmap_cache_lookup_gidbywinname(name, domain, gid);
2458 		if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
2459 			return (rc);
2460 	}
2461 
2462 	/* Get mapping */
2463 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
2464 		return (rc);
2465 	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, flag,
2466 	    &is_user, &is_wuser, gid, NULL, &direction, NULL);
2467 	(void) idmap_fini(ih);
2468 
2469 	if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
2470 		/* If we have not got the domain don't store GID to winname */
2471 		if (domain == NULL)
2472 			direction = IDMAP_DIRECTION_W2U;
2473 		idmap_cache_add_winname2gid(name, domain, *gid, direction);
2474 	}
2475 
2476 	return (rc);
2477 }
2478 
2479 
2480 /*
2481  * Get winname given pid
2482  */
2483 static idmap_retcode
2484 idmap_getwinnamebypid(uid_t pid, int is_user, int flag, char **name,
2485 	char **domain)
2486 {
2487 	idmap_handle_t	*ih;
2488 	idmap_retcode	rc;
2489 	int		len;
2490 	char		*winname, *windomain;
2491 	int		direction;
2492 
2493 	if (name == NULL)
2494 		return (IDMAP_ERR_ARG);
2495 
2496 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2497 		if (is_user)
2498 			rc = idmap_cache_lookup_winnamebyuid(&winname,
2499 			    &windomain, pid);
2500 		else
2501 			rc = idmap_cache_lookup_winnamebygid(&winname,
2502 			    &windomain, pid);
2503 		if (rc == IDMAP_SUCCESS)
2504 			goto out;
2505 		if (rc == IDMAP_ERR_MEMORY)
2506 			return (rc);
2507 	}
2508 
2509 	/* Get mapping */
2510 	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
2511 		return (rc);
2512 	rc = idmap_get_u2w_mapping(ih, &pid, NULL, flag, is_user, NULL,
2513 	    NULL, NULL, &winname, &windomain, &direction, NULL);
2514 	(void) idmap_fini(ih);
2515 
2516 	/* Return on error */
2517 	if (rc != IDMAP_SUCCESS)
2518 		return (rc);
2519 
2520 	/*
2521 	 * The given PID may have been mapped to a locally
2522 	 * generated SID in which case there isn't any
2523 	 * Windows name
2524 	 */
2525 	if (winname == NULL || windomain == NULL) {
2526 		idmap_free(winname);
2527 		idmap_free(windomain);
2528 		return (IDMAP_ERR_NORESULT);
2529 	}
2530 
2531 	if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2532 		if (is_user)
2533 			idmap_cache_add_winname2uid(winname, windomain,
2534 			    pid, direction);
2535 		else
2536 			idmap_cache_add_winname2gid(winname, windomain,
2537 			    pid, direction);
2538 	}
2539 
2540 out:
2541 	if (domain != NULL) {
2542 		*name = winname;
2543 		*domain = windomain;
2544 	} else {
2545 		len = strlen(winname) + strlen(windomain) + 2;
2546 		if ((*name = malloc(len)) != NULL)
2547 			(void) snprintf(*name, len, "%s@%s", winname,
2548 			    windomain);
2549 		else
2550 			rc = IDMAP_ERR_MEMORY;
2551 		idmap_free(winname);
2552 		idmap_free(windomain);
2553 	}
2554 
2555 	return (rc);
2556 }
2557 
2558 
2559 /*
2560  * Get winname given uid
2561  */
2562 idmap_stat
2563 idmap_getwinnamebyuid(uid_t uid, int flag, char **name, char **domain)
2564 {
2565 	return (idmap_getwinnamebypid(uid, 1, flag, name, domain));
2566 }
2567 
2568 
2569 /*
2570  * Get winname given gid
2571  */
2572 idmap_stat
2573 idmap_getwinnamebygid(gid_t gid, int flag, char **name, char **domain)
2574 {
2575 	return (idmap_getwinnamebypid(gid, 0, flag, name, domain));
2576 }
2577 
2578 
2579 /* printflike */
2580 void
2581 idmapdlog(int pri, const char *format, ...) {
2582 	va_list args;
2583 
2584 	va_start(args, format);
2585 	if (pri <= logstate.max_pri) {
2586 		(void) vfprintf(stderr, format, args);
2587 		(void) fprintf(stderr, "\n");
2588 	}
2589 
2590 	/*
2591 	 * We don't want to fill up the logs with useless messages when
2592 	 * we're degraded, but we still want to log.
2593 	 */
2594 	if (logstate.degraded)
2595 		pri = LOG_DEBUG;
2596 
2597 	if (logstate.write_syslog)
2598 		(void) vsyslog(pri, format, args);
2599 	va_end(args);
2600 }
2601 
2602 void
2603 idmap_log_stderr(int pri)
2604 {
2605 	logstate.max_pri = pri;
2606 }
2607 
2608 void
2609 idmap_log_syslog(bool_t what)
2610 {
2611 	logstate.write_syslog = what;
2612 }
2613 
2614 void
2615 idmap_log_degraded(bool_t what)
2616 {
2617 	logstate.degraded = what;
2618 }
2619