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