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