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