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