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