xref: /illumos-gate/usr/src/uts/common/idmap/idmap_kapi.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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  */
65 typedef 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 */
77 struct 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 */
87 typedef 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 
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 	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  */
184 void
185 idmap_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 
196 static int
197 kidmap_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 
205 retry:
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 
306 static idmap_zone_specific_t *
307 idmap_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 
334 static void
335 /* ARGSUSED */
336 idmap_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 
350 int
351 kidmap_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 
361 int
362 kidmap_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  */
374 door_handle_t
375 idmap_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  */
398 void
399 idmap_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  */
424 idmap_stat
425 kidmap_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  */
501 idmap_stat
502 kidmap_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  */
578 idmap_stat
579 kidmap_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  */
666 idmap_stat
667 kidmap_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  */
750 idmap_stat
751 kidmap_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  */
828 idmap_get_handle_t *
829 kidmap_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  */
853 static void
854 kidmap_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  */
895 idmap_stat
896 kidmap_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  */
951 idmap_stat
952 kidmap_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  */
1009 idmap_stat
1010 kidmap_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  */
1066 idmap_stat
1067 kidmap_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  */
1121 idmap_stat
1122 kidmap_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 
1172 idmap_stat
1173 kidmap_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 
1336 error:
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  */
1364 void
1365 kidmap_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 
1382 static int
1383 kidmap_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 
1401 retry:
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 
1485 exit:
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