idmap_kapi.c revision 9565:f0422a11592c
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/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Windows to Solaris Identity Mapping kernel API
29 * This module provides an API to map Windows SIDs to
30 * Solaris UID and GIDs.
31 */
32
33
34#include <sys/types.h>
35#include <sys/ksynch.h>
36#include <sys/door.h>
37#include <rpc/rpc_msg.h>
38#include <rpc/xdr.h>
39#include <rpc/auth.h>
40#include <rpc/rpc_sztypes.h>
41#ifdef	DEBUG
42#include <sys/cmn_err.h>
43#endif	/* DEBUG */
44#include <sys/proc.h>
45#include <sys/sunddi.h>
46#include <sys/param.h>
47#include <sys/atomic.h>
48#include <sys/sysmacros.h>
49#include <sys/disp.h>
50#include <sys/kidmap.h>
51#include <sys/zone.h>
52#include <rpcsvc/idmap_prot.h>
53#include "kidmap_priv.h"
54
55
56/*
57 * Defined types
58 */
59
60
61/*
62 * This structure holds pointers for the
63 * batch mapping results.
64 */
65typedef struct idmap_get_res {
66	idmap_id_type	idtype;
67	uid_t		*uid;
68	gid_t		*gid;
69	uid_t		*pid;
70	int		*is_user;
71	const char	**sid_prefix;
72	uint32_t	*rid;
73	idmap_stat	*stat;
74} idmap_get_res;
75
76/* Batch mapping handle structure */
77struct idmap_get_handle {
78	struct idmap_zone_specific *zs;
79	int 		mapping_num;
80	int 		mapping_size;
81	idmap_mapping	*mapping;
82	idmap_get_res	*result;
83};
84
85
86/* Zone specific data */
87typedef struct idmap_zone_specific {
88	zoneid_t	zone_id;
89	kmutex_t	zone_mutex;
90	idmap_cache_t	cache;
91	door_handle_t 	door_handle;
92	int		door_valid;
93	int		door_retried;
94	uint32_t	message_id;
95} idmap_zone_specific_t;
96
97
98
99/*
100 * Module global data
101 */
102
103static kmutex_t		idmap_zone_mutex;
104static zone_key_t	idmap_zone_key;
105
106
107/*
108 * Local function definitions
109 */
110
111
112static int
113kidmap_rpc_call(idmap_zone_specific_t *zs, uint32_t op,
114		xdrproc_t xdr_args, caddr_t args,
115		xdrproc_t xdr_res, caddr_t res);
116
117static int
118kidmap_call_door(idmap_zone_specific_t *zs, door_arg_t *arg);
119
120static idmap_zone_specific_t *
121idmap_get_zone_specific(zone_t *zone);
122
123
124
125int
126idmap_reg_dh(zone_t *zone, door_handle_t dh)
127{
128	idmap_zone_specific_t *zs;
129
130	zs = idmap_get_zone_specific(zone);
131
132	mutex_enter(&zs->zone_mutex);
133
134	if (zs->door_valid)
135		door_ki_rele(zs->door_handle);
136
137	zs->door_handle = dh;
138	zs->door_valid = 1;
139
140	mutex_exit(&zs->zone_mutex);
141
142	return (0);
143}
144
145/*
146 * idmap_unreg_dh
147 *
148 * This routine is called by system call idmap_unreg().
149 * idmap_unreg() calls door_ki_rele() on the supplied
150 * door handle after this routine returns. We only
151 * need to perform one door release on zs->door_handle
152 */
153int
154idmap_unreg_dh(zone_t *zone, door_handle_t dh)
155{
156	idmap_zone_specific_t *zs;
157
158	zs = idmap_get_zone_specific(zone);
159
160	kidmap_cache_purge(&zs->cache);
161
162	mutex_enter(&zs->zone_mutex);
163
164	if (!zs->door_valid || zs->door_handle != dh) {
165		mutex_exit(&zs->zone_mutex);
166		return (EINVAL);
167	}
168
169	door_ki_rele(zs->door_handle);
170
171	zs->door_valid = 0;
172	zs->door_retried = 0;
173	mutex_exit(&zs->zone_mutex);
174
175	return (0);
176}
177
178
179/*
180 * IMPORTANT. This function idmap_get_cache_data() is project
181 * private and is for use of the test system only and should
182 * not be used for other purposes.
183 */
184void
185idmap_get_cache_data(zone_t *zone, size_t *uidbysid, size_t *gidbysid,
186	size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid)
187{
188	idmap_zone_specific_t *zs;
189
190	zs = idmap_get_zone_specific(zone);
191
192	kidmap_cache_get_data(&zs->cache, uidbysid, gidbysid,
193	    pidbysid, sidbyuid, sidbygid);
194}
195
196static int
197kidmap_call_door(idmap_zone_specific_t *zs, door_arg_t *arg)
198{
199	door_handle_t 	dh;
200	door_info_t	di;
201	int		status = 0;
202	int		num_retries = 5;
203	int		door_retried;
204
205retry:
206	mutex_enter(&zs->zone_mutex);
207	if (zs->door_valid) {
208		dh = zs->door_handle;
209		door_ki_hold(dh);
210	} else {
211		dh = NULL;
212		door_retried = zs->door_retried;
213	}
214	mutex_exit(&zs->zone_mutex);
215
216	if (dh == NULL) {
217		/* The door has been retried before so dont wait */
218		if (door_retried)
219			return (-1);
220
221		/*
222		 * There is no door handle yet. Give
223		 * smf a chance to restart idmapd
224		 */
225		if (num_retries-- > 0) {
226			delay(hz);
227			goto retry;
228		}
229
230#ifdef	DEBUG
231		zcmn_err(zs->zone_id, CE_WARN,
232		    "idmap: Error no registered door to call the "
233		    "idmap daemon\n");
234#endif
235		mutex_enter(&zs->zone_mutex);
236		if (!zs->door_valid)
237			zs->door_retried = 1;
238		mutex_exit(&zs->zone_mutex);
239
240		return (-1);
241	}
242
243	status = door_ki_upcall_limited(dh, arg, NULL, SIZE_MAX, 0);
244
245	switch (status) {
246	case 0:	/* Success */
247		door_ki_rele(dh);
248		return (0);
249
250	case EINTR:
251		/* If we took an interrupt we have to bail out. */
252		if (ttolwp(curthread) && ISSIG(curthread, JUSTLOOKING)) {
253			door_ki_rele(dh);
254#ifdef	DEBUG
255			zcmn_err(zs->zone_id, CE_WARN,
256			    "idmap: Interrupted\n");
257#endif
258			return (-1);
259		}
260		/*
261		 * Just retry and see what happens.
262		 */
263		/* FALLTHROUGH */
264
265	case EAGAIN:
266		/* A resouce problem */
267		door_ki_rele(dh);
268		/* Back off before retrying */
269#ifdef	DEBUG
270		zcmn_err(zs->zone_id, CE_WARN,
271		    "idmap: Door call returned error %d. Retrying\n", status);
272#endif	/* DEBUG */
273		delay(hz);
274		goto retry;
275
276	case EBADF:
277		/* Stale door handle. See if smf restarts the daemon. */
278		door_ki_rele(dh);
279		mutex_enter(&zs->zone_mutex);
280		if (zs->door_valid && dh == zs->door_handle) {
281			zs->door_valid = 0;
282			zs->door_retried = 0;
283			door_ki_rele(zs->door_handle);
284		}
285		mutex_exit(&zs->zone_mutex);
286		/* Back off before retrying */
287#ifdef	DEBUG
288		zcmn_err(zs->zone_id, CE_WARN,
289		    "idmap: Door call returned error %d. Retrying\n", status);
290#endif	/* DEBUG */
291		delay(hz);
292		goto retry;
293
294	default:
295		/* Unknown error */
296#ifdef	DEBUG
297		zcmn_err(zs->zone_id, CE_WARN,
298		    "idmap: Door call returned error %d.\n", status);
299#endif	/* DEBUG */
300		door_ki_rele(dh);
301		return (-1);
302	}
303}
304
305
306static idmap_zone_specific_t *
307idmap_get_zone_specific(zone_t *zone)
308{
309	idmap_zone_specific_t *zs;
310
311	ASSERT(zone != NULL);
312
313	zs = zone_getspecific(idmap_zone_key, zone);
314	if (zs != NULL)
315		return (zs);
316
317	mutex_enter(&idmap_zone_mutex);
318	zs = zone_getspecific(idmap_zone_key, zone);
319	if (zs == NULL) {
320		zs = kmem_zalloc(sizeof (idmap_zone_specific_t), KM_SLEEP);
321		mutex_init(&zs->zone_mutex, NULL, MUTEX_DEFAULT, NULL);
322		kidmap_cache_create(&zs->cache);
323		zs->zone_id = zone->zone_id;
324		(void) zone_setspecific(idmap_zone_key, zone, zs);
325		mutex_exit(&idmap_zone_mutex);
326		return (zs);
327	}
328	mutex_exit(&idmap_zone_mutex);
329
330	return (zs);
331}
332
333
334static void
335/* ARGSUSED */
336idmap_zone_destroy(zoneid_t zone_id, void *arg)
337{
338	idmap_zone_specific_t *zs = arg;
339	if (zs != NULL) {
340		kidmap_cache_delete(&zs->cache);
341		if (zs->door_valid) {
342			door_ki_rele(zs->door_handle);
343		}
344		mutex_destroy(&zs->zone_mutex);
345		kmem_free(zs, sizeof (idmap_zone_specific_t));
346	}
347}
348
349
350int
351kidmap_start(void)
352{
353	mutex_init(&idmap_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
354	zone_key_create(&idmap_zone_key, NULL, NULL, idmap_zone_destroy);
355	kidmap_sid_prefix_store_init();
356
357	return (0);
358}
359
360
361int
362kidmap_stop(void)
363{
364	return (EBUSY);
365}
366
367
368/*
369 * idmap_get_door
370 *
371 * This is called by the system call allocids() to get the door for the
372 * given zone.
373 */
374door_handle_t
375idmap_get_door(zone_t *zone)
376{
377	door_handle_t dh = NULL;
378	idmap_zone_specific_t *zs;
379
380	zs = idmap_get_zone_specific(zone);
381
382	mutex_enter(&zs->zone_mutex);
383	if (zs->door_valid) {
384		dh = zs->door_handle;
385		door_ki_hold(dh);
386	}
387	mutex_exit(&zs->zone_mutex);
388	return (dh);
389}
390
391
392/*
393 * idmap_purge_cache
394 *
395 * This is called by the system call allocids() to purge the cache for the
396 * given zone.
397 */
398void
399idmap_purge_cache(zone_t *zone)
400{
401	idmap_zone_specific_t *zs;
402
403	zs = idmap_get_zone_specific(zone);
404
405	kidmap_cache_purge(&zs->cache);
406}
407
408
409
410
411/*
412 * Given Domain SID and RID, get UID
413 *
414 * Input:
415 * sid_prefix	- Domain SID in canonical form
416 * rid	- RID
417 *
418 * Output:
419 * uid  - POSIX UID if return == IDMAP_SUCCESS
420 *
421 * Return:
422 * Success return IDMAP_SUCCESS else IDMAP error
423 */
424idmap_stat
425kidmap_getuidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
426		uid_t *uid)
427{
428	idmap_zone_specific_t	*zs;
429	idmap_mapping_batch	args;
430	idmap_mapping		mapping;
431	idmap_ids_res		results;
432	uint32_t		op = IDMAP_GET_MAPPED_IDS;
433	const char		*new_sid_prefix;
434	idmap_stat		status;
435
436	if (sid_prefix == NULL || uid == NULL)
437		return (IDMAP_ERR_ARG);
438
439	zs = idmap_get_zone_specific(zone);
440
441	if (kidmap_cache_lookup_uidbysid(&zs->cache, sid_prefix, rid, uid)
442	    == IDMAP_SUCCESS)
443		return (IDMAP_SUCCESS);
444
445	bzero(&mapping, sizeof (idmap_mapping));
446	mapping.id1.idtype = IDMAP_SID;
447	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
448	mapping.id1.idmap_id_u.sid.rid = rid;
449	mapping.id2.idtype = IDMAP_UID;
450
451	bzero(&results, sizeof (idmap_ids_res));
452
453	args.idmap_mapping_batch_len = 1;
454	args.idmap_mapping_batch_val = &mapping;
455
456	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
457	    (caddr_t)&args, xdr_idmap_ids_res,
458	    (caddr_t)&results) == 0) {
459		/* Door call succeded */
460		if (results.retcode != IDMAP_SUCCESS) {
461			status = results.retcode;
462			*uid = UID_NOBODY;
463		} else if (results.ids.ids_len >= 1 &&
464		    results.ids.ids_val[0].id.idtype == IDMAP_UID) {
465			status = results.ids.ids_val[0].retcode;
466			*uid = results.ids.ids_val[0].id.idmap_id_u.uid;
467			if (status == IDMAP_SUCCESS) {
468				new_sid_prefix = kidmap_find_sid_prefix(
469				    sid_prefix);
470				kidmap_cache_add_sid2uid(&zs->cache,
471				    new_sid_prefix, rid, *uid,
472				    results.ids.ids_val[0].direction);
473			}
474		} else {
475			status = IDMAP_ERR_NOMAPPING;
476			*uid = UID_NOBODY;
477		}
478		xdr_free(xdr_idmap_ids_res, (char *)&results);
479	} else {
480		/* Door call failed */
481		status = IDMAP_ERR_NOMAPPING;
482		*uid = UID_NOBODY;
483	}
484	return (status);
485}
486
487
488/*
489 * Given Domain SID and RID, get GID
490 *
491 * Input:
492 * sid_prefix	- Domain SID in canonical form
493 * rid	- RID
494 *
495 * Output:
496 * gid  - POSIX UID if return == IDMAP_SUCCESS
497 *
498 * Return:
499 * Success return IDMAP_SUCCESS else IDMAP error
500 */
501idmap_stat
502kidmap_getgidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
503		gid_t *gid)
504{
505	idmap_zone_specific_t	*zs;
506	idmap_mapping_batch	args;
507	idmap_mapping		mapping;
508	idmap_ids_res		results;
509	uint32_t		op = IDMAP_GET_MAPPED_IDS;
510	const char		*new_sid_prefix;
511	idmap_stat		status;
512
513	if (sid_prefix == NULL || gid == NULL)
514		return (IDMAP_ERR_ARG);
515
516	zs = idmap_get_zone_specific(zone);
517
518	if (kidmap_cache_lookup_gidbysid(&zs->cache, sid_prefix, rid, gid)
519	    == IDMAP_SUCCESS)
520		return (IDMAP_SUCCESS);
521
522	bzero(&mapping, sizeof (idmap_mapping));
523	mapping.id1.idtype = IDMAP_SID;
524	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
525	mapping.id1.idmap_id_u.sid.rid = rid;
526	mapping.id2.idtype = IDMAP_GID;
527
528	bzero(&results, sizeof (idmap_ids_res));
529
530	args.idmap_mapping_batch_len = 1;
531	args.idmap_mapping_batch_val = &mapping;
532
533	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
534	    (caddr_t)&args, xdr_idmap_ids_res,
535	    (caddr_t)&results) == 0) {
536		/* Door call succeded */
537		if (results.retcode != IDMAP_SUCCESS) {
538			status = results.retcode;
539			*gid = GID_NOBODY;
540		} else if (results.ids.ids_len >= 1 &&
541		    results.ids.ids_val[0].id.idtype == IDMAP_GID) {
542			status = results.ids.ids_val[0].retcode;
543			*gid = results.ids.ids_val[0].id.idmap_id_u.gid;
544			if (status == IDMAP_SUCCESS) {
545				new_sid_prefix = kidmap_find_sid_prefix(
546				    sid_prefix);
547				kidmap_cache_add_sid2gid(&zs->cache,
548				    new_sid_prefix, rid, *gid,
549				    results.ids.ids_val[0].direction);
550			}
551		} else {
552			status = IDMAP_ERR_NOMAPPING;
553			*gid = GID_NOBODY;
554		}
555		xdr_free(xdr_idmap_ids_res, (char *)&results);
556	} else {
557		/* Door call failed */
558		status = IDMAP_ERR_NOMAPPING;
559		*gid = GID_NOBODY;
560	}
561	return (status);
562}
563
564/*
565 * Given Domain SID and RID, get Posix ID
566 *
567 * Input:
568 * sid_prefix	- Domain SID in canonical form
569 * rid	- RID
570 *
571 * Output:
572 * pid  - POSIX ID if return == IDMAP_SUCCESS
573 * is_user - 1 == UID, 0 == GID  if return == IDMAP_SUCCESS
574 *
575 * Return:
576 * Success return IDMAP_SUCCESS else IDMAP error
577 */
578idmap_stat
579kidmap_getpidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
580		uid_t *pid, int *is_user)
581{
582	idmap_zone_specific_t	*zs;
583	idmap_mapping_batch	args;
584	idmap_mapping		mapping;
585	idmap_ids_res		results;
586	uint32_t		op = IDMAP_GET_MAPPED_IDS;
587	const char		*new_sid_prefix;
588	idmap_stat		status;
589
590	if (sid_prefix == NULL || pid == NULL || is_user == NULL)
591		return (IDMAP_ERR_ARG);
592
593	zs = idmap_get_zone_specific(zone);
594
595	if (kidmap_cache_lookup_pidbysid(&zs->cache, sid_prefix, rid, pid,
596	    is_user) == IDMAP_SUCCESS)
597		return (IDMAP_SUCCESS);
598
599	bzero(&mapping, sizeof (idmap_mapping));
600	mapping.id1.idtype = IDMAP_SID;
601	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
602	mapping.id1.idmap_id_u.sid.rid = rid;
603	mapping.id2.idtype = IDMAP_POSIXID;
604
605	bzero(&results, sizeof (idmap_ids_res));
606
607	args.idmap_mapping_batch_len = 1;
608	args.idmap_mapping_batch_val = &mapping;
609
610	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
611	    (caddr_t)&args, xdr_idmap_ids_res,
612	    (caddr_t)&results) == 0) {
613		/* Door call succeded */
614		if (results.retcode != IDMAP_SUCCESS) {
615			status = results.retcode;
616			*is_user = 1;
617			*pid = UID_NOBODY;
618		} else if (results.ids.ids_len >= 1 && (
619		    results.ids.ids_val[0].id.idtype == IDMAP_UID ||
620		    results.ids.ids_val[0].id.idtype == IDMAP_GID)) {
621			status = results.ids.ids_val[0].retcode;
622			if (results.ids.ids_val[0].id.idtype == IDMAP_UID) {
623				*is_user = 1;
624				*pid = results.ids.ids_val[0].id.idmap_id_u.uid;
625			} else {
626				*is_user = 0;
627				*pid = results.ids.ids_val[0].id.idmap_id_u.gid;
628			}
629			if (status == IDMAP_SUCCESS) {
630				new_sid_prefix = kidmap_find_sid_prefix(
631				    sid_prefix);
632				kidmap_cache_add_sid2pid(&zs->cache,
633				    new_sid_prefix, rid, *pid,
634				    *is_user,
635				    results.ids.ids_val[0].direction);
636			}
637		} else {
638			status = IDMAP_ERR_NOMAPPING;
639			*is_user = 1;
640			*pid = UID_NOBODY;
641		}
642		xdr_free(xdr_idmap_ids_res, (char *)&results);
643	} else {
644		/* Door call failed */
645		status = IDMAP_ERR_NOMAPPING;
646		*is_user = 1;
647		*pid = UID_NOBODY;
648	}
649	return (status);
650}
651
652
653/*
654 * Given UID, get Domain SID and RID
655 *
656 * Input:
657 * uid - Posix UID
658 *
659 * Output:
660 * sid_prefix	- Domain SID if return == IDMAP_SUCCESS
661 * rid	- RID if return == IDMAP_SUCCESS
662 *
663 * Return:
664 * Success return IDMAP_SUCCESS else IDMAP error
665 */
666idmap_stat
667kidmap_getsidbyuid(zone_t *zone, uid_t uid, const char **sid_prefix,
668		uint32_t *rid)
669{
670	idmap_zone_specific_t	*zs;
671	idmap_mapping_batch	args;
672	idmap_mapping		mapping;
673	idmap_ids_res		results;
674	uint32_t		op = IDMAP_GET_MAPPED_IDS;
675	idmap_stat		status;
676	time_t			entry_ttl;
677	idmap_id		*id;
678
679	if (sid_prefix == NULL || rid == NULL)
680		return (IDMAP_ERR_ARG);
681
682	zs = idmap_get_zone_specific(zone);
683
684	if (kidmap_cache_lookup_sidbyuid(&zs->cache, sid_prefix, rid, uid)
685	    == IDMAP_SUCCESS) {
686		return (IDMAP_SUCCESS);
687	}
688
689	bzero(&mapping, sizeof (idmap_mapping));
690	mapping.id1.idtype = IDMAP_UID;
691	mapping.id1.idmap_id_u.uid = uid;
692	mapping.id2.idtype = IDMAP_SID;
693
694	bzero(&results, sizeof (idmap_ids_res));
695
696	args.idmap_mapping_batch_len = 1;
697	args.idmap_mapping_batch_val = &mapping;
698
699	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
700	    (caddr_t)&args, xdr_idmap_ids_res,
701	    (caddr_t)&results) == 0) {
702		/* Door call succeded */
703		if (results.retcode != IDMAP_SUCCESS) {
704			status = results.retcode;
705			*rid = 0;
706			*sid_prefix = NULL;
707		} else if (results.ids.ids_len >= 1 &&
708		    (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
709		    results.ids.ids_val[0].id.idtype == IDMAP_USID ||
710		    results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
711			status = results.ids.ids_val[0].retcode;
712			id = &results.ids.ids_val[0].id;
713			*sid_prefix = kidmap_find_sid_prefix(
714			    id->idmap_id_u.sid.prefix);
715			*rid = id->idmap_id_u.sid.rid;
716			if (status == IDMAP_SUCCESS) {
717				kidmap_cache_add_sid2uid(&zs->cache,
718				    *sid_prefix, *rid, uid,
719				    results.ids.ids_val[0].direction);
720			}
721		} else {
722			status = IDMAP_ERR_NOMAPPING;
723			*rid = 0;
724			*sid_prefix = NULL;
725		}
726		xdr_free(xdr_idmap_ids_res, (char *)&results);
727	} else {
728		/* Door call failed */
729		status = IDMAP_ERR_NOMAPPING;
730		*rid = 0;
731		*sid_prefix = NULL;
732	}
733	return (status);
734}
735
736
737/*
738 * Given GID, get Domain SID and RID
739 *
740 * Input:
741 * gid - Posix GID
742 *
743 * Output:
744 * sid_prefix	- Domain SID if return == IDMAP_SUCCESS
745 * rid	- RID if return == IDMAP_SUCCESS
746 *
747 * Return:
748 * Success return IDMAP_SUCCESS else IDMAP error
749 */
750idmap_stat
751kidmap_getsidbygid(zone_t *zone, gid_t gid, const char **sid_prefix,
752		uint32_t *rid)
753{
754	idmap_zone_specific_t	*zs;
755	idmap_mapping_batch	args;
756	idmap_mapping		mapping;
757	idmap_ids_res		results;
758	uint32_t		op = IDMAP_GET_MAPPED_IDS;
759	idmap_stat		status;
760	idmap_id		*id;
761
762	if (sid_prefix == NULL || rid == NULL)
763		return (IDMAP_ERR_ARG);
764
765	zs = idmap_get_zone_specific(zone);
766
767	if (kidmap_cache_lookup_sidbygid(&zs->cache, sid_prefix, rid, gid)
768	    == IDMAP_SUCCESS) {
769		return (IDMAP_SUCCESS);
770	}
771
772	bzero(&mapping, sizeof (idmap_mapping));
773	mapping.id1.idtype = IDMAP_GID;
774	mapping.id1.idmap_id_u.uid = gid;
775	mapping.id2.idtype = IDMAP_SID;
776
777	bzero(&results, sizeof (idmap_ids_res));
778
779	args.idmap_mapping_batch_len = 1;
780	args.idmap_mapping_batch_val = &mapping;
781
782	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
783	    (caddr_t)&args, xdr_idmap_ids_res,
784	    (caddr_t)&results) == 0) {
785		/* Door call succeded */
786		if (results.retcode != IDMAP_SUCCESS) {
787			status = results.retcode;
788			*rid = 0;
789			*sid_prefix = NULL;
790		} else if (results.ids.ids_len >= 1 &&
791		    (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
792		    results.ids.ids_val[0].id.idtype == IDMAP_USID ||
793		    results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
794			status = results.ids.ids_val[0].retcode;
795			id = &results.ids.ids_val[0].id;
796			*sid_prefix = kidmap_find_sid_prefix(
797			    id->idmap_id_u.sid.prefix);
798			*rid = id->idmap_id_u.sid.rid;
799			if (status == IDMAP_SUCCESS) {
800				kidmap_cache_add_sid2gid(&zs->cache,
801				    *sid_prefix, *rid, gid,
802				    results.ids.ids_val[0].direction);
803			}
804		} else {
805			status = IDMAP_ERR_NOMAPPING;
806			*rid = 0;
807			*sid_prefix = NULL;
808		}
809		xdr_free(xdr_idmap_ids_res, (char *)&results);
810	} else {
811		/* Door call failed */
812		status = IDMAP_ERR_NOMAPPING;
813		*rid = 0;
814		*sid_prefix = NULL;
815	}
816	return (status);
817}
818
819/*
820 * Create handle to get SID to UID/GID mapping entries
821 *
822 * Input:
823 * 	none
824 * Return:
825 *	get_handle
826 *
827 */
828idmap_get_handle_t *
829kidmap_get_create(zone_t *zone)
830{
831	idmap_zone_specific_t	*zs;
832	idmap_get_handle_t	*handle;
833#define	INIT_MAPPING_SIZE	32
834
835	zs = idmap_get_zone_specific(zone);
836
837	handle = kmem_zalloc(sizeof (idmap_get_handle_t), KM_SLEEP);
838
839	handle->mapping = kmem_zalloc((sizeof (idmap_mapping)) *
840	    INIT_MAPPING_SIZE, KM_SLEEP);
841
842	handle->result = kmem_zalloc((sizeof (idmap_get_res)) *
843	    INIT_MAPPING_SIZE, KM_SLEEP);
844	handle->mapping_size = INIT_MAPPING_SIZE;
845	handle->zs = zs;
846
847	return (handle);
848}
849
850/*
851 * Internal routine to extend a "get_handle"
852 */
853static void
854kidmap_get_extend(idmap_get_handle_t *get_handle)
855{
856	idmap_mapping *mapping;
857	idmap_get_res *result;
858	int new_size = get_handle->mapping_size + INIT_MAPPING_SIZE;
859
860	mapping = kmem_zalloc((sizeof (idmap_mapping)) *
861	    new_size, KM_SLEEP);
862	(void) memcpy(mapping, get_handle->mapping,
863	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
864
865	result = kmem_zalloc((sizeof (idmap_get_res)) *
866	    new_size, KM_SLEEP);
867	(void) memcpy(result, get_handle->result,
868	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
869
870	kmem_free(get_handle->mapping,
871	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
872	get_handle->mapping = mapping;
873
874	kmem_free(get_handle->result,
875	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
876	get_handle->result = result;
877
878	get_handle->mapping_size = new_size;
879}
880
881
882/*
883 * Given Domain SID and RID, get UID
884 *
885 * Input:
886 * sid_prefix	- Domain SID in canonical form
887 * rid	- RID
888 *
889 * Output:
890 * stat - status of the get request
891 * uid  - POSIX UID if stat == IDMAP_SUCCESS
892 *
893 * Note: The output parameters will be set by idmap_get_mappings()
894 */
895idmap_stat
896kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
897			uint32_t rid, uid_t *uid, idmap_stat *stat)
898{
899	idmap_mapping	*mapping;
900	idmap_get_res 	*result;
901
902	if (get_handle == NULL || sid_prefix == NULL ||
903	    uid == NULL || stat == NULL)
904		return (IDMAP_ERR_ARG);
905
906	if (kidmap_cache_lookup_uidbysid(&get_handle->zs->cache, sid_prefix,
907	    rid, uid) == IDMAP_SUCCESS) {
908		*stat = IDMAP_SUCCESS;
909		return (IDMAP_SUCCESS);
910	}
911
912	if (get_handle->mapping_num >= get_handle->mapping_size)
913		kidmap_get_extend(get_handle);
914
915	mapping = &get_handle->mapping[get_handle->mapping_num];
916	mapping->flag = 0;
917	mapping->id1.idtype = IDMAP_SID;
918	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
919	mapping->id1.idmap_id_u.sid.rid = rid;
920	mapping->id2.idtype = IDMAP_UID;
921
922	result = &get_handle->result[get_handle->mapping_num];
923	result->idtype = IDMAP_UID;
924	result->uid = uid;
925	result->gid = NULL;
926	result->pid = NULL;
927	result->sid_prefix = NULL;
928	result->rid = NULL;
929	result->is_user = NULL;
930	result->stat = stat;
931
932	get_handle->mapping_num++;
933
934	return (IDMAP_SUCCESS);
935}
936
937
938/*
939 * Given Domain SID and RID, get GID
940 *
941 * Input:
942 * sid_prefix	- Domain SID in canonical form
943 * rid	- RID
944 *
945 * Output:
946 * stat - status of the get request
947 * gid  - POSIX GID if stat == IDMAP_SUCCESS
948 *
949 * Note: The output parameters will be set by idmap_get_mappings()
950 */
951idmap_stat
952kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
953			uint32_t rid, uid_t *gid, idmap_stat *stat)
954{
955	idmap_mapping	*mapping;
956	idmap_get_res 	*result;
957
958	if (get_handle == NULL || sid_prefix == NULL ||
959	    gid == NULL || stat == NULL)
960		return (IDMAP_ERR_ARG);
961
962	if (kidmap_cache_lookup_gidbysid(&get_handle->zs->cache, sid_prefix,
963	    rid, gid) == IDMAP_SUCCESS) {
964		*stat = IDMAP_SUCCESS;
965		return (IDMAP_SUCCESS);
966	}
967
968	if (get_handle->mapping_num >= get_handle->mapping_size)
969		kidmap_get_extend(get_handle);
970
971	mapping = &get_handle->mapping[get_handle->mapping_num];
972	mapping->flag = 0;
973	mapping->id1.idtype = IDMAP_SID;
974	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
975	mapping->id1.idmap_id_u.sid.rid = rid;
976	mapping->id2.idtype = IDMAP_GID;
977
978	result = &get_handle->result[get_handle->mapping_num];
979	result->idtype = IDMAP_GID;
980	result->uid = NULL;
981	result->gid = gid;
982	result->pid = NULL;
983	result->sid_prefix = NULL;
984	result->rid = NULL;
985	result->is_user = NULL;
986	result->stat = stat;
987
988	get_handle->mapping_num++;
989
990	return (IDMAP_SUCCESS);
991}
992
993
994/*
995 * Given Domain SID and RID, get Posix ID
996 *
997 * Input:
998 * sid_prefix	- Domain SID in canonical form
999 * rid	- RID
1000 *
1001 * Output:
1002 * stat    - status of the get request
1003 * is_user - user or group
1004 * pid     - POSIX UID if stat == IDMAP_SUCCESS and is_user == 1
1005 *           POSIX GID if stat == IDMAP_SUCCESS and is_user == 0
1006 *
1007 * Note: The output parameters will be set by idmap_get_mappings()
1008 */
1009idmap_stat
1010kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
1011		uint32_t rid, uid_t *pid, int *is_user, idmap_stat *stat)
1012{
1013	idmap_mapping	*mapping;
1014	idmap_get_res 	*result;
1015
1016	if (get_handle == NULL || sid_prefix == NULL || pid == NULL ||
1017	    is_user == NULL || stat == NULL)
1018		return (IDMAP_ERR_ARG);
1019
1020	if (kidmap_cache_lookup_pidbysid(&get_handle->zs->cache, sid_prefix,
1021	    rid, pid, is_user) == IDMAP_SUCCESS) {
1022		*stat = IDMAP_SUCCESS;
1023		return (IDMAP_SUCCESS);
1024	}
1025
1026
1027	if (get_handle->mapping_num >= get_handle->mapping_size)
1028		kidmap_get_extend(get_handle);
1029
1030	mapping = &get_handle->mapping[get_handle->mapping_num];
1031	mapping->flag = 0;
1032	mapping->id1.idtype = IDMAP_SID;
1033	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
1034	mapping->id1.idmap_id_u.sid.rid = rid;
1035	mapping->id2.idtype = IDMAP_POSIXID;
1036
1037	result = &get_handle->result[get_handle->mapping_num];
1038	result->idtype = IDMAP_POSIXID;
1039	result->uid = NULL;
1040	result->gid = NULL;
1041	result->pid = pid;
1042	result->sid_prefix = NULL;
1043	result->rid = NULL;
1044	result->is_user = is_user;
1045	result->stat = stat;
1046
1047	get_handle->mapping_num++;
1048
1049	return (IDMAP_SUCCESS);
1050}
1051
1052
1053/*
1054 * Given UID, get SID and RID
1055 *
1056 * Input:
1057 * uid  - POSIX UID
1058 *
1059 * Output:
1060 * stat - status of the get request
1061 * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
1062 * rid	- RID (if stat == IDMAP_SUCCESS)
1063 *
1064 * Note: The output parameters will be set by idmap_get_mappings()
1065 */
1066idmap_stat
1067kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
1068		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
1069{
1070	idmap_mapping	*mapping;
1071	idmap_get_res 	*result;
1072
1073	if (get_handle == NULL || sid_prefix == NULL ||
1074	    rid == NULL || stat == NULL)
1075		return (IDMAP_ERR_ARG);
1076
1077	if (kidmap_cache_lookup_sidbyuid(&get_handle->zs->cache,
1078	    sid_prefix, rid, uid) == IDMAP_SUCCESS) {
1079		*stat = IDMAP_SUCCESS;
1080		return (IDMAP_SUCCESS);
1081	}
1082
1083	if (get_handle->mapping_num >= get_handle->mapping_size)
1084		kidmap_get_extend(get_handle);
1085
1086	mapping = &get_handle->mapping[get_handle->mapping_num];
1087	mapping->flag = 0;
1088	mapping->id1.idtype = IDMAP_UID;
1089	mapping->id1.idmap_id_u.uid = uid;
1090	mapping->id2.idtype = IDMAP_SID;
1091
1092	result = &get_handle->result[get_handle->mapping_num];
1093	result->idtype = IDMAP_SID;
1094	result->uid = NULL;
1095	result->gid = NULL;
1096	result->pid = NULL;
1097	result->sid_prefix = sid_prefix;
1098	result->rid = rid;
1099	result->is_user = NULL;
1100	result->stat = stat;
1101
1102	get_handle->mapping_num++;
1103
1104	return (IDMAP_SUCCESS);
1105}
1106
1107
1108/*
1109 * Given GID, get SID and RID
1110 *
1111 * Input:
1112 * gid  - POSIX GID
1113 *
1114 * Output:
1115 * stat - status of the get request
1116 * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
1117 * rid	- RID (if stat == IDMAP_SUCCESS)
1118 *
1119 * Note: The output parameters will be set by idmap_get_mappings()
1120 */
1121idmap_stat
1122kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
1123		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
1124{
1125	idmap_mapping	*mapping;
1126	idmap_get_res 	*result;
1127
1128	if (get_handle == NULL || sid_prefix == NULL ||
1129	    rid == NULL || stat == NULL)
1130		return (IDMAP_ERR_ARG);
1131
1132	if (kidmap_cache_lookup_sidbygid(&get_handle->zs->cache,
1133	    sid_prefix, rid, gid) == IDMAP_SUCCESS) {
1134		*stat = IDMAP_SUCCESS;
1135		return (IDMAP_SUCCESS);
1136	}
1137
1138	if (get_handle->mapping_num >= get_handle->mapping_size)
1139		kidmap_get_extend(get_handle);
1140
1141	mapping = &get_handle->mapping[get_handle->mapping_num];
1142	mapping->flag = 0;
1143	mapping->id1.idtype = IDMAP_GID;
1144	mapping->id1.idmap_id_u.gid = gid;
1145	mapping->id2.idtype = IDMAP_SID;
1146
1147	result = &get_handle->result[get_handle->mapping_num];
1148	result->idtype = IDMAP_SID;
1149	result->uid = NULL;
1150	result->gid = NULL;
1151	result->pid = NULL;
1152	result->sid_prefix = sid_prefix;
1153	result->rid = rid;
1154	result->is_user = NULL;
1155	result->stat = stat;
1156
1157	get_handle->mapping_num++;
1158
1159	return (IDMAP_SUCCESS);
1160}
1161
1162
1163/*
1164 * Process the batched "get mapping" requests. The results (i.e.
1165 * status and identity) will be available in the data areas
1166 * provided by individual requests.
1167 *
1168 * If the door call fails the status IDMAP_ERR_NOMAPPING is
1169 * return and the UID or UID result is set to "nobody"
1170 */
1171
1172idmap_stat
1173kidmap_get_mappings(idmap_get_handle_t *get_handle)
1174{
1175	idmap_mapping_batch	rpc_args;
1176	idmap_ids_res		rpc_res;
1177	uint32_t		op = IDMAP_GET_MAPPED_IDS;
1178	idmap_mapping		*request;
1179	idmap_get_res		*result;
1180	idmap_id		*id;
1181	int			status;
1182	int			i;
1183	const char		*sid_prefix;
1184	int			is_user;
1185	idmap_cache_t		*cache;
1186	int			direction;
1187
1188	if (get_handle == NULL)
1189		return (IDMAP_ERR_ARG);
1190
1191	if (get_handle->mapping_num == 0)
1192		return (IDMAP_SUCCESS);
1193	cache = &get_handle->zs->cache;
1194
1195	bzero(&rpc_res, sizeof (idmap_ids_res));
1196
1197	rpc_args.idmap_mapping_batch_len = get_handle->mapping_num;
1198	rpc_args.idmap_mapping_batch_val = get_handle->mapping;
1199
1200	if (kidmap_rpc_call(get_handle->zs, op, xdr_idmap_mapping_batch,
1201	    (caddr_t)&rpc_args, xdr_idmap_ids_res,
1202	    (caddr_t)&rpc_res) != 0) {
1203		/* Door call failed */
1204		status = IDMAP_ERR_NOMAPPING;
1205		goto error;
1206	}
1207
1208	status = rpc_res.retcode;
1209	if (status != IDMAP_SUCCESS) {
1210		/* RPC returned idmap error code */
1211		xdr_free(xdr_idmap_ids_res, (char *)&rpc_res);
1212		goto error;
1213	}
1214
1215	for (i = 0; i < get_handle->mapping_num; i++) {
1216		request = &get_handle->mapping[i];
1217		result =  &get_handle->result[i];
1218
1219		if (i >= rpc_res.ids.ids_len) {
1220			*result->stat =	IDMAP_ERR_NOMAPPING;
1221			if (result->uid)
1222				*result->uid = UID_NOBODY;
1223			if (result->gid)
1224				*result->gid = GID_NOBODY;
1225			if (result->pid)
1226				*result->pid = UID_NOBODY;
1227			if (result->is_user)
1228				*result->is_user = 1;
1229			if (result->sid_prefix)
1230				*result->sid_prefix = NULL;
1231			if (result->rid)
1232				*result->rid = 0;
1233			continue;
1234		}
1235
1236		*result->stat = rpc_res.ids.ids_val[i].retcode;
1237
1238		id = &rpc_res.ids.ids_val[i].id;
1239		direction = rpc_res.ids.ids_val[i].direction;
1240
1241		switch (id->idtype) {
1242		case IDMAP_UID:
1243			if (result->uid)
1244				*result->uid = id->idmap_id_u.uid;
1245			if (result->pid)
1246				*result->pid = id->idmap_id_u.uid;
1247			if (result->is_user)
1248				*result->is_user = 1;
1249			sid_prefix = kidmap_find_sid_prefix(
1250			    request->id1.idmap_id_u.sid.prefix);
1251			if (*result->stat == IDMAP_SUCCESS && result->uid)
1252				kidmap_cache_add_sid2uid(
1253				    cache, sid_prefix,
1254				    request->id1.idmap_id_u.sid.rid,
1255				    id->idmap_id_u.uid,
1256				    direction);
1257			else if (*result->stat == IDMAP_SUCCESS && result->pid)
1258				kidmap_cache_add_sid2pid(
1259				    cache, sid_prefix,
1260				    request->id1.idmap_id_u.sid.rid,
1261				    id->idmap_id_u.uid, 1,
1262				    direction);
1263			break;
1264
1265		case IDMAP_GID:
1266			if (result->gid)
1267				*result->gid = id->idmap_id_u.gid;
1268			if (result->pid)
1269				*result->pid = id->idmap_id_u.gid;
1270			if (result->is_user)
1271				*result->is_user = 0;
1272			sid_prefix = kidmap_find_sid_prefix(
1273			    request->id1.idmap_id_u.sid.prefix);
1274			if (*result->stat == IDMAP_SUCCESS && result->gid)
1275				kidmap_cache_add_sid2gid(
1276				    cache, sid_prefix,
1277				    request->id1.idmap_id_u.sid.rid,
1278				    id->idmap_id_u.gid,
1279				    direction);
1280			else if (*result->stat == IDMAP_SUCCESS && result->pid)
1281				kidmap_cache_add_sid2pid(
1282				    cache, sid_prefix,
1283				    request->id1.idmap_id_u.sid.rid,
1284				    id->idmap_id_u.gid, 0,
1285				    direction);
1286			break;
1287
1288		case IDMAP_SID:
1289		case IDMAP_USID:
1290		case IDMAP_GSID:
1291			sid_prefix = kidmap_find_sid_prefix(
1292			    id->idmap_id_u.sid.prefix);
1293			if (result->sid_prefix && result->rid) {
1294				*result->sid_prefix = sid_prefix;
1295				*result->rid = id->idmap_id_u.sid.rid;
1296			}
1297			if (*result->stat == IDMAP_SUCCESS &&
1298			    request->id1.idtype == IDMAP_UID)
1299				kidmap_cache_add_sid2uid(
1300				    cache, sid_prefix,
1301				    id->idmap_id_u.sid.rid,
1302				    request->id1.idmap_id_u.uid,
1303				    direction);
1304			else if (*result->stat == IDMAP_SUCCESS &&
1305			    request->id1.idtype == IDMAP_GID)
1306				kidmap_cache_add_sid2gid(
1307				    cache, sid_prefix,
1308				    id->idmap_id_u.sid.rid,
1309				    request->id1.idmap_id_u.gid,
1310				    direction);
1311			break;
1312
1313		default:
1314			*result->stat = IDMAP_ERR_NORESULT;
1315			if (result->uid)
1316				*result->uid = UID_NOBODY;
1317			if (result->gid)
1318				*result->gid = GID_NOBODY;
1319			if (result->pid)
1320				*result->pid = UID_NOBODY;
1321			if (result->is_user)
1322				*result->is_user = 1;
1323			if (result->sid_prefix)
1324				*result->sid_prefix = NULL;
1325			if (result->rid)
1326				*result->rid = 0;
1327			break;
1328		}
1329	}
1330	xdr_free(xdr_idmap_ids_res, (char *)&rpc_res);
1331
1332	/* Reset get_handle for new resquests */
1333	get_handle->mapping_num = 0;
1334	return (status);
1335
1336error:
1337	for (i = 0; i < get_handle->mapping_num; i++) {
1338		result =  &get_handle->result[i];
1339
1340		*result->stat = status;
1341		if (result->uid)
1342			*result->uid = UID_NOBODY;
1343		if (result->gid)
1344			*result->gid = GID_NOBODY;
1345		if (result->pid)
1346			*result->pid = UID_NOBODY;
1347		if (result->is_user)
1348			*result->is_user = 1;
1349		if (result->sid_prefix)
1350			*result->sid_prefix = NULL;
1351		if (result->rid)
1352			*result->rid = 0;
1353	}
1354
1355	/* Reset get_handle for new resquests */
1356	get_handle->mapping_num = 0;
1357	return (status);
1358}
1359
1360
1361/*
1362 * Destroy the "get mapping" handle
1363 */
1364void
1365kidmap_get_destroy(idmap_get_handle_t *get_handle)
1366{
1367	if (get_handle == NULL)
1368		return;
1369
1370	kmem_free(get_handle->mapping,
1371	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
1372	get_handle->mapping = NULL;
1373
1374	kmem_free(get_handle->result,
1375	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
1376	get_handle->result = NULL;
1377
1378	kmem_free(get_handle, sizeof (idmap_get_handle_t));
1379}
1380
1381
1382static int
1383kidmap_rpc_call(idmap_zone_specific_t *zs, uint32_t op, xdrproc_t xdr_args,
1384		caddr_t args, xdrproc_t xdr_res, caddr_t res)
1385{
1386	XDR		xdr_ctx;
1387	struct	rpc_msg reply_msg;
1388	char		*inbuf_ptr = NULL;
1389	size_t		inbuf_size = 4096;
1390	char		*outbuf_ptr = NULL;
1391	size_t 		outbuf_size = 4096;
1392	size_t		size;
1393	int		status = 0;
1394	door_arg_t	params;
1395	int 		retry = 0;
1396	struct rpc_msg	call_msg;
1397
1398	params.rbuf = NULL;
1399	params.rsize = 0;
1400
1401retry:
1402	inbuf_ptr = kmem_alloc(inbuf_size, KM_SLEEP);
1403	outbuf_ptr = kmem_alloc(outbuf_size, KM_SLEEP);
1404
1405	xdrmem_create(&xdr_ctx, inbuf_ptr, inbuf_size, XDR_ENCODE);
1406
1407	call_msg.rm_call.cb_prog = IDMAP_PROG;
1408	call_msg.rm_call.cb_vers = IDMAP_V1;
1409	call_msg.rm_xid = atomic_inc_32_nv(&zs->message_id);
1410
1411	if (!xdr_callhdr(&xdr_ctx, &call_msg)) {
1412#ifdef	DEBUG
1413		zcmn_err(zs->zone_id, CE_WARN,
1414		    "idmap: xdr encoding header error");
1415#endif	/* DEBUG */
1416		status = -1;
1417		goto exit;
1418	}
1419
1420	if (!xdr_uint32(&xdr_ctx, &op) ||
1421	    /* Auth none */
1422	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1423	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1424	    /* RPC args */
1425	    !xdr_args(&xdr_ctx, args)) {
1426#ifdef	DEBUG
1427		zcmn_err(zs->zone_id, CE_WARN, "idmap: xdr encoding error");
1428#endif	/* DEBUG */
1429		if (retry > 2) {
1430			status = -1;
1431			goto exit;
1432		}
1433		retry++;
1434		if (inbuf_ptr) {
1435			kmem_free(inbuf_ptr, inbuf_size);
1436			inbuf_ptr = NULL;
1437		}
1438		if (outbuf_ptr) {
1439			kmem_free(outbuf_ptr, outbuf_size);
1440			outbuf_ptr = NULL;
1441		}
1442		if ((size = xdr_sizeof(xdr_args, args)) == 0) {
1443#ifdef	DEBUG
1444			zcmn_err(zs->zone_id, CE_WARN,
1445			    "idmap: xdr_sizeof error");
1446#endif	/* DEBUG */
1447			status = -1;
1448			goto exit;
1449		}
1450		inbuf_size = size + 1024;
1451		outbuf_size = size + 1024;
1452		goto retry;
1453	}
1454
1455	params.data_ptr = inbuf_ptr;
1456	params.data_size = XDR_GETPOS(&xdr_ctx);
1457	params.desc_ptr = NULL;
1458	params.desc_num = 0;
1459	params.rbuf = outbuf_ptr;
1460	params.rsize = outbuf_size;
1461
1462	if (kidmap_call_door(zs, &params) != 0) {
1463		status = -1;
1464		goto exit;
1465	}
1466
1467	reply_msg.acpted_rply.ar_verf = _null_auth;
1468	reply_msg.acpted_rply.ar_results.where = res;
1469	reply_msg.acpted_rply.ar_results.proc = xdr_res;
1470	xdrmem_create(&xdr_ctx, params.data_ptr, params.data_size, XDR_DECODE);
1471	if (xdr_replymsg(&xdr_ctx, &reply_msg)) {
1472		if (reply_msg.rm_reply.rp_stat != MSG_ACCEPTED ||
1473		    reply_msg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
1474			status = -1;
1475			goto exit;
1476		}
1477	} else {
1478#ifdef	DEBUG
1479		zcmn_err(zs->zone_id, CE_WARN,
1480		    "idmap: xdr decoding reply message error");
1481#endif	/* DEBUG */
1482		status = -1;
1483	}
1484
1485exit:
1486	if (outbuf_ptr != params.rbuf && params.rbuf != NULL)
1487		kmem_free(params.rbuf, params.rsize);
1488	if (inbuf_ptr)
1489		kmem_free(inbuf_ptr, inbuf_size);
1490	if (outbuf_ptr)
1491		kmem_free(outbuf_ptr, outbuf_size);
1492	return (status);
1493}
1494