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