xref: /titanic_52/usr/src/uts/common/idmap/idmap_kapi.c (revision 263f549e5da8b32c4922f586afb365b8ae388a6c)
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  * Notes:
894  * The output parameters will be set by idmap_get_mappings()
895  * The sid_prefix is copied.
896  */
897 idmap_stat
898 kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
899 			uint32_t rid, uid_t *uid, idmap_stat *stat)
900 {
901 	idmap_mapping	*mapping;
902 	idmap_get_res 	*result;
903 
904 	if (get_handle == NULL || sid_prefix == NULL ||
905 	    uid == NULL || stat == NULL)
906 		return (IDMAP_ERR_ARG);
907 
908 	if (kidmap_cache_lookup_uidbysid(&get_handle->zs->cache, sid_prefix,
909 	    rid, uid) == IDMAP_SUCCESS) {
910 		*stat = IDMAP_SUCCESS;
911 		return (IDMAP_SUCCESS);
912 	}
913 
914 	/* Get a copy of sid_prefix */
915 	sid_prefix = kidmap_find_sid_prefix(sid_prefix);
916 
917 	if (get_handle->mapping_num >= get_handle->mapping_size)
918 		kidmap_get_extend(get_handle);
919 
920 	mapping = &get_handle->mapping[get_handle->mapping_num];
921 	mapping->flag = 0;
922 	mapping->id1.idtype = IDMAP_SID;
923 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
924 	mapping->id1.idmap_id_u.sid.rid = rid;
925 	mapping->id2.idtype = IDMAP_UID;
926 
927 	result = &get_handle->result[get_handle->mapping_num];
928 	result->idtype = IDMAP_UID;
929 	result->uid = uid;
930 	result->gid = NULL;
931 	result->pid = NULL;
932 	result->sid_prefix = NULL;
933 	result->rid = NULL;
934 	result->is_user = NULL;
935 	result->stat = stat;
936 
937 	get_handle->mapping_num++;
938 
939 	return (IDMAP_SUCCESS);
940 }
941 
942 
943 /*
944  * Given Domain SID and RID, get GID
945  *
946  * Input:
947  * sid_prefix	- Domain SID in canonical form
948  * rid	- RID
949  *
950  * Output:
951  * stat - status of the get request
952  * gid  - POSIX GID if stat == IDMAP_SUCCESS
953  *
954  * Notes:
955  * The output parameters will be set by idmap_get_mappings()
956  * The sid_prefix is copied.
957  */
958 idmap_stat
959 kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
960 			uint32_t rid, uid_t *gid, idmap_stat *stat)
961 {
962 	idmap_mapping	*mapping;
963 	idmap_get_res 	*result;
964 
965 	if (get_handle == NULL || sid_prefix == NULL ||
966 	    gid == NULL || stat == NULL)
967 		return (IDMAP_ERR_ARG);
968 
969 	if (kidmap_cache_lookup_gidbysid(&get_handle->zs->cache, sid_prefix,
970 	    rid, gid) == IDMAP_SUCCESS) {
971 		*stat = IDMAP_SUCCESS;
972 		return (IDMAP_SUCCESS);
973 	}
974 
975 	/* Get a copy of sid_prefix */
976 	sid_prefix = kidmap_find_sid_prefix(sid_prefix);
977 
978 	if (get_handle->mapping_num >= get_handle->mapping_size)
979 		kidmap_get_extend(get_handle);
980 
981 	mapping = &get_handle->mapping[get_handle->mapping_num];
982 	mapping->flag = 0;
983 	mapping->id1.idtype = IDMAP_SID;
984 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
985 	mapping->id1.idmap_id_u.sid.rid = rid;
986 	mapping->id2.idtype = IDMAP_GID;
987 
988 	result = &get_handle->result[get_handle->mapping_num];
989 	result->idtype = IDMAP_GID;
990 	result->uid = NULL;
991 	result->gid = gid;
992 	result->pid = NULL;
993 	result->sid_prefix = NULL;
994 	result->rid = NULL;
995 	result->is_user = NULL;
996 	result->stat = stat;
997 
998 	get_handle->mapping_num++;
999 
1000 	return (IDMAP_SUCCESS);
1001 }
1002 
1003 
1004 /*
1005  * Given Domain SID and RID, get Posix ID
1006  *
1007  * Input:
1008  * sid_prefix	- Domain SID in canonical form
1009  * rid	- RID
1010  *
1011  * Output:
1012  * stat    - status of the get request
1013  * is_user - user or group
1014  * pid     - POSIX UID if stat == IDMAP_SUCCESS and is_user == 1
1015  *           POSIX GID if stat == IDMAP_SUCCESS and is_user == 0
1016  *
1017  * Notes:
1018  * The output parameters will be set by idmap_get_mappings()
1019  * The sid_prefix is copied.
1020  */
1021 idmap_stat
1022 kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
1023 		uint32_t rid, uid_t *pid, int *is_user, idmap_stat *stat)
1024 {
1025 	idmap_mapping	*mapping;
1026 	idmap_get_res 	*result;
1027 
1028 	if (get_handle == NULL || sid_prefix == NULL || pid == NULL ||
1029 	    is_user == NULL || stat == NULL)
1030 		return (IDMAP_ERR_ARG);
1031 
1032 	if (kidmap_cache_lookup_pidbysid(&get_handle->zs->cache, sid_prefix,
1033 	    rid, pid, is_user) == IDMAP_SUCCESS) {
1034 		*stat = IDMAP_SUCCESS;
1035 		return (IDMAP_SUCCESS);
1036 	}
1037 
1038 	/* Get a copy of sid_prefix */
1039 	sid_prefix = kidmap_find_sid_prefix(sid_prefix);
1040 
1041 	if (get_handle->mapping_num >= get_handle->mapping_size)
1042 		kidmap_get_extend(get_handle);
1043 
1044 	mapping = &get_handle->mapping[get_handle->mapping_num];
1045 	mapping->flag = 0;
1046 	mapping->id1.idtype = IDMAP_SID;
1047 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
1048 	mapping->id1.idmap_id_u.sid.rid = rid;
1049 	mapping->id2.idtype = IDMAP_POSIXID;
1050 
1051 	result = &get_handle->result[get_handle->mapping_num];
1052 	result->idtype = IDMAP_POSIXID;
1053 	result->uid = NULL;
1054 	result->gid = NULL;
1055 	result->pid = pid;
1056 	result->sid_prefix = NULL;
1057 	result->rid = NULL;
1058 	result->is_user = is_user;
1059 	result->stat = stat;
1060 
1061 	get_handle->mapping_num++;
1062 
1063 	return (IDMAP_SUCCESS);
1064 }
1065 
1066 
1067 /*
1068  * Given UID, get SID and RID
1069  *
1070  * Input:
1071  * uid  - POSIX UID
1072  *
1073  * Output:
1074  * stat - status of the get request
1075  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
1076  * rid	- RID (if stat == IDMAP_SUCCESS)
1077  *
1078  * Note: The output parameters will be set by idmap_get_mappings()
1079  */
1080 idmap_stat
1081 kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
1082 		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
1083 {
1084 	idmap_mapping	*mapping;
1085 	idmap_get_res 	*result;
1086 
1087 	if (get_handle == NULL || sid_prefix == NULL ||
1088 	    rid == NULL || stat == NULL)
1089 		return (IDMAP_ERR_ARG);
1090 
1091 	if (kidmap_cache_lookup_sidbyuid(&get_handle->zs->cache,
1092 	    sid_prefix, rid, uid) == IDMAP_SUCCESS) {
1093 		*stat = IDMAP_SUCCESS;
1094 		return (IDMAP_SUCCESS);
1095 	}
1096 
1097 	if (get_handle->mapping_num >= get_handle->mapping_size)
1098 		kidmap_get_extend(get_handle);
1099 
1100 	mapping = &get_handle->mapping[get_handle->mapping_num];
1101 	mapping->flag = 0;
1102 	mapping->id1.idtype = IDMAP_UID;
1103 	mapping->id1.idmap_id_u.uid = uid;
1104 	mapping->id2.idtype = IDMAP_SID;
1105 
1106 	result = &get_handle->result[get_handle->mapping_num];
1107 	result->idtype = IDMAP_SID;
1108 	result->uid = NULL;
1109 	result->gid = NULL;
1110 	result->pid = NULL;
1111 	result->sid_prefix = sid_prefix;
1112 	result->rid = rid;
1113 	result->is_user = NULL;
1114 	result->stat = stat;
1115 
1116 	get_handle->mapping_num++;
1117 
1118 	return (IDMAP_SUCCESS);
1119 }
1120 
1121 
1122 /*
1123  * Given GID, get SID and RID
1124  *
1125  * Input:
1126  * gid  - POSIX GID
1127  *
1128  * Output:
1129  * stat - status of the get request
1130  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
1131  * rid	- RID (if stat == IDMAP_SUCCESS)
1132  *
1133  * Note: The output parameters will be set by idmap_get_mappings()
1134  */
1135 idmap_stat
1136 kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
1137 		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
1138 {
1139 	idmap_mapping	*mapping;
1140 	idmap_get_res 	*result;
1141 
1142 	if (get_handle == NULL || sid_prefix == NULL ||
1143 	    rid == NULL || stat == NULL)
1144 		return (IDMAP_ERR_ARG);
1145 
1146 	if (kidmap_cache_lookup_sidbygid(&get_handle->zs->cache,
1147 	    sid_prefix, rid, gid) == IDMAP_SUCCESS) {
1148 		*stat = IDMAP_SUCCESS;
1149 		return (IDMAP_SUCCESS);
1150 	}
1151 
1152 	if (get_handle->mapping_num >= get_handle->mapping_size)
1153 		kidmap_get_extend(get_handle);
1154 
1155 	mapping = &get_handle->mapping[get_handle->mapping_num];
1156 	mapping->flag = 0;
1157 	mapping->id1.idtype = IDMAP_GID;
1158 	mapping->id1.idmap_id_u.gid = gid;
1159 	mapping->id2.idtype = IDMAP_SID;
1160 
1161 	result = &get_handle->result[get_handle->mapping_num];
1162 	result->idtype = IDMAP_SID;
1163 	result->uid = NULL;
1164 	result->gid = NULL;
1165 	result->pid = NULL;
1166 	result->sid_prefix = sid_prefix;
1167 	result->rid = rid;
1168 	result->is_user = NULL;
1169 	result->stat = stat;
1170 
1171 	get_handle->mapping_num++;
1172 
1173 	return (IDMAP_SUCCESS);
1174 }
1175 
1176 
1177 /*
1178  * Process the batched "get mapping" requests. The results (i.e.
1179  * status and identity) will be available in the data areas
1180  * provided by individual requests.
1181  *
1182  * If the door call fails the status IDMAP_ERR_NOMAPPING is
1183  * return and the UID or UID result is set to "nobody"
1184  */
1185 
1186 idmap_stat
1187 kidmap_get_mappings(idmap_get_handle_t *get_handle)
1188 {
1189 	idmap_mapping_batch	rpc_args;
1190 	idmap_ids_res		rpc_res;
1191 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
1192 	idmap_mapping		*request;
1193 	idmap_get_res		*result;
1194 	idmap_id		*id;
1195 	int			status;
1196 	int			i;
1197 	const char		*sid_prefix;
1198 	int			is_user;
1199 	idmap_cache_t		*cache;
1200 	int			direction;
1201 
1202 	if (get_handle == NULL)
1203 		return (IDMAP_ERR_ARG);
1204 
1205 	if (get_handle->mapping_num == 0)
1206 		return (IDMAP_SUCCESS);
1207 	cache = &get_handle->zs->cache;
1208 
1209 	bzero(&rpc_res, sizeof (idmap_ids_res));
1210 
1211 	rpc_args.idmap_mapping_batch_len = get_handle->mapping_num;
1212 	rpc_args.idmap_mapping_batch_val = get_handle->mapping;
1213 
1214 	if (kidmap_rpc_call(get_handle->zs, op, xdr_idmap_mapping_batch,
1215 	    (caddr_t)&rpc_args, xdr_idmap_ids_res,
1216 	    (caddr_t)&rpc_res) != 0) {
1217 		/* Door call failed */
1218 		status = IDMAP_ERR_NOMAPPING;
1219 		goto error;
1220 	}
1221 
1222 	status = rpc_res.retcode;
1223 	if (status != IDMAP_SUCCESS) {
1224 		/* RPC returned idmap error code */
1225 		xdr_free(xdr_idmap_ids_res, (char *)&rpc_res);
1226 		goto error;
1227 	}
1228 
1229 	for (i = 0; i < get_handle->mapping_num; i++) {
1230 		request = &get_handle->mapping[i];
1231 		result =  &get_handle->result[i];
1232 
1233 		if (i >= rpc_res.ids.ids_len) {
1234 			*result->stat =	IDMAP_ERR_NOMAPPING;
1235 			if (result->uid)
1236 				*result->uid = UID_NOBODY;
1237 			if (result->gid)
1238 				*result->gid = GID_NOBODY;
1239 			if (result->pid)
1240 				*result->pid = UID_NOBODY;
1241 			if (result->is_user)
1242 				*result->is_user = 1;
1243 			if (result->sid_prefix)
1244 				*result->sid_prefix = NULL;
1245 			if (result->rid)
1246 				*result->rid = 0;
1247 			continue;
1248 		}
1249 
1250 		*result->stat = rpc_res.ids.ids_val[i].retcode;
1251 
1252 		id = &rpc_res.ids.ids_val[i].id;
1253 		direction = rpc_res.ids.ids_val[i].direction;
1254 
1255 		switch (id->idtype) {
1256 		case IDMAP_UID:
1257 			if (result->uid)
1258 				*result->uid = id->idmap_id_u.uid;
1259 			if (result->pid)
1260 				*result->pid = id->idmap_id_u.uid;
1261 			if (result->is_user)
1262 				*result->is_user = 1;
1263 			sid_prefix = kidmap_find_sid_prefix(
1264 			    request->id1.idmap_id_u.sid.prefix);
1265 			if (*result->stat == IDMAP_SUCCESS && result->uid)
1266 				kidmap_cache_add_sid2uid(
1267 				    cache, sid_prefix,
1268 				    request->id1.idmap_id_u.sid.rid,
1269 				    id->idmap_id_u.uid,
1270 				    direction);
1271 			else if (*result->stat == IDMAP_SUCCESS && result->pid)
1272 				kidmap_cache_add_sid2pid(
1273 				    cache, sid_prefix,
1274 				    request->id1.idmap_id_u.sid.rid,
1275 				    id->idmap_id_u.uid, 1,
1276 				    direction);
1277 			break;
1278 
1279 		case IDMAP_GID:
1280 			if (result->gid)
1281 				*result->gid = id->idmap_id_u.gid;
1282 			if (result->pid)
1283 				*result->pid = id->idmap_id_u.gid;
1284 			if (result->is_user)
1285 				*result->is_user = 0;
1286 			sid_prefix = kidmap_find_sid_prefix(
1287 			    request->id1.idmap_id_u.sid.prefix);
1288 			if (*result->stat == IDMAP_SUCCESS && result->gid)
1289 				kidmap_cache_add_sid2gid(
1290 				    cache, sid_prefix,
1291 				    request->id1.idmap_id_u.sid.rid,
1292 				    id->idmap_id_u.gid,
1293 				    direction);
1294 			else if (*result->stat == IDMAP_SUCCESS && result->pid)
1295 				kidmap_cache_add_sid2pid(
1296 				    cache, sid_prefix,
1297 				    request->id1.idmap_id_u.sid.rid,
1298 				    id->idmap_id_u.gid, 0,
1299 				    direction);
1300 			break;
1301 
1302 		case IDMAP_SID:
1303 		case IDMAP_USID:
1304 		case IDMAP_GSID:
1305 			sid_prefix = kidmap_find_sid_prefix(
1306 			    id->idmap_id_u.sid.prefix);
1307 			if (result->sid_prefix && result->rid) {
1308 				*result->sid_prefix = sid_prefix;
1309 				*result->rid = id->idmap_id_u.sid.rid;
1310 			}
1311 			if (*result->stat == IDMAP_SUCCESS &&
1312 			    request->id1.idtype == IDMAP_UID)
1313 				kidmap_cache_add_sid2uid(
1314 				    cache, sid_prefix,
1315 				    id->idmap_id_u.sid.rid,
1316 				    request->id1.idmap_id_u.uid,
1317 				    direction);
1318 			else if (*result->stat == IDMAP_SUCCESS &&
1319 			    request->id1.idtype == IDMAP_GID)
1320 				kidmap_cache_add_sid2gid(
1321 				    cache, sid_prefix,
1322 				    id->idmap_id_u.sid.rid,
1323 				    request->id1.idmap_id_u.gid,
1324 				    direction);
1325 			break;
1326 
1327 		default:
1328 			*result->stat = IDMAP_ERR_NORESULT;
1329 			if (result->uid)
1330 				*result->uid = UID_NOBODY;
1331 			if (result->gid)
1332 				*result->gid = GID_NOBODY;
1333 			if (result->pid)
1334 				*result->pid = UID_NOBODY;
1335 			if (result->is_user)
1336 				*result->is_user = 1;
1337 			if (result->sid_prefix)
1338 				*result->sid_prefix = NULL;
1339 			if (result->rid)
1340 				*result->rid = 0;
1341 			break;
1342 		}
1343 	}
1344 	xdr_free(xdr_idmap_ids_res, (char *)&rpc_res);
1345 
1346 	/* Reset get_handle for new resquests */
1347 	get_handle->mapping_num = 0;
1348 	return (status);
1349 
1350 error:
1351 	for (i = 0; i < get_handle->mapping_num; i++) {
1352 		result =  &get_handle->result[i];
1353 
1354 		*result->stat = status;
1355 		if (result->uid)
1356 			*result->uid = UID_NOBODY;
1357 		if (result->gid)
1358 			*result->gid = GID_NOBODY;
1359 		if (result->pid)
1360 			*result->pid = UID_NOBODY;
1361 		if (result->is_user)
1362 			*result->is_user = 1;
1363 		if (result->sid_prefix)
1364 			*result->sid_prefix = NULL;
1365 		if (result->rid)
1366 			*result->rid = 0;
1367 	}
1368 
1369 	/* Reset get_handle for new resquests */
1370 	get_handle->mapping_num = 0;
1371 	return (status);
1372 }
1373 
1374 
1375 /*
1376  * Destroy the "get mapping" handle
1377  */
1378 void
1379 kidmap_get_destroy(idmap_get_handle_t *get_handle)
1380 {
1381 	if (get_handle == NULL)
1382 		return;
1383 
1384 	kmem_free(get_handle->mapping,
1385 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
1386 	get_handle->mapping = NULL;
1387 
1388 	kmem_free(get_handle->result,
1389 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
1390 	get_handle->result = NULL;
1391 
1392 	kmem_free(get_handle, sizeof (idmap_get_handle_t));
1393 }
1394 
1395 
1396 static int
1397 kidmap_rpc_call(idmap_zone_specific_t *zs, uint32_t op, xdrproc_t xdr_args,
1398 		caddr_t args, xdrproc_t xdr_res, caddr_t res)
1399 {
1400 	XDR		xdr_ctx;
1401 	struct	rpc_msg reply_msg;
1402 	char		*inbuf_ptr = NULL;
1403 	size_t		inbuf_size = 4096;
1404 	char		*outbuf_ptr = NULL;
1405 	size_t 		outbuf_size = 4096;
1406 	size_t		size;
1407 	int		status = 0;
1408 	door_arg_t	params;
1409 	int 		retry = 0;
1410 	struct rpc_msg	call_msg;
1411 
1412 	params.rbuf = NULL;
1413 	params.rsize = 0;
1414 
1415 retry:
1416 	inbuf_ptr = kmem_alloc(inbuf_size, KM_SLEEP);
1417 	outbuf_ptr = kmem_alloc(outbuf_size, KM_SLEEP);
1418 
1419 	xdrmem_create(&xdr_ctx, inbuf_ptr, inbuf_size, XDR_ENCODE);
1420 
1421 	call_msg.rm_call.cb_prog = IDMAP_PROG;
1422 	call_msg.rm_call.cb_vers = IDMAP_V1;
1423 	call_msg.rm_xid = atomic_inc_32_nv(&zs->message_id);
1424 
1425 	if (!xdr_callhdr(&xdr_ctx, &call_msg)) {
1426 #ifdef	DEBUG
1427 		zcmn_err(zs->zone_id, CE_WARN,
1428 		    "idmap: xdr encoding header error");
1429 #endif	/* DEBUG */
1430 		status = -1;
1431 		goto exit;
1432 	}
1433 
1434 	if (!xdr_uint32(&xdr_ctx, &op) ||
1435 	    /* Auth none */
1436 	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1437 	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1438 	    /* RPC args */
1439 	    !xdr_args(&xdr_ctx, args)) {
1440 #ifdef	DEBUG
1441 		zcmn_err(zs->zone_id, CE_WARN, "idmap: xdr encoding error");
1442 #endif	/* DEBUG */
1443 		if (retry > 2) {
1444 			status = -1;
1445 			goto exit;
1446 		}
1447 		retry++;
1448 		if (inbuf_ptr) {
1449 			kmem_free(inbuf_ptr, inbuf_size);
1450 			inbuf_ptr = NULL;
1451 		}
1452 		if (outbuf_ptr) {
1453 			kmem_free(outbuf_ptr, outbuf_size);
1454 			outbuf_ptr = NULL;
1455 		}
1456 		if ((size = xdr_sizeof(xdr_args, args)) == 0) {
1457 #ifdef	DEBUG
1458 			zcmn_err(zs->zone_id, CE_WARN,
1459 			    "idmap: xdr_sizeof error");
1460 #endif	/* DEBUG */
1461 			status = -1;
1462 			goto exit;
1463 		}
1464 		inbuf_size = size + 1024;
1465 		outbuf_size = size + 1024;
1466 		goto retry;
1467 	}
1468 
1469 	params.data_ptr = inbuf_ptr;
1470 	params.data_size = XDR_GETPOS(&xdr_ctx);
1471 	params.desc_ptr = NULL;
1472 	params.desc_num = 0;
1473 	params.rbuf = outbuf_ptr;
1474 	params.rsize = outbuf_size;
1475 
1476 	if (kidmap_call_door(zs, &params) != 0) {
1477 		status = -1;
1478 		goto exit;
1479 	}
1480 
1481 	reply_msg.acpted_rply.ar_verf = _null_auth;
1482 	reply_msg.acpted_rply.ar_results.where = res;
1483 	reply_msg.acpted_rply.ar_results.proc = xdr_res;
1484 	xdrmem_create(&xdr_ctx, params.data_ptr, params.data_size, XDR_DECODE);
1485 	if (xdr_replymsg(&xdr_ctx, &reply_msg)) {
1486 		if (reply_msg.rm_reply.rp_stat != MSG_ACCEPTED ||
1487 		    reply_msg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
1488 			status = -1;
1489 			goto exit;
1490 		}
1491 	} else {
1492 #ifdef	DEBUG
1493 		zcmn_err(zs->zone_id, CE_WARN,
1494 		    "idmap: xdr decoding reply message error");
1495 #endif	/* DEBUG */
1496 		status = -1;
1497 	}
1498 
1499 exit:
1500 	if (outbuf_ptr != params.rbuf && params.rbuf != NULL)
1501 		kmem_free(params.rbuf, params.rsize);
1502 	if (inbuf_ptr)
1503 		kmem_free(inbuf_ptr, inbuf_size);
1504 	if (outbuf_ptr)
1505 		kmem_free(outbuf_ptr, outbuf_size);
1506 	return (status);
1507 }
1508