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