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