Home | History | Annotate | Download | only in idmap
      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 
     34 #include <sys/types.h>
     35 #include <sys/ksynch.h>
     36 #include <sys/door.h>
     37 #include <rpc/rpc_msg.h>
     38 #include <rpc/xdr.h>
     39 #include <rpc/auth.h>
     40 #include <rpc/rpc_sztypes.h>
     41 #ifdef	DEBUG
     42 #include <sys/cmn_err.h>
     43 #endif	/* DEBUG */
     44 #include <sys/proc.h>
     45 #include <sys/sunddi.h>
     46 #include <sys/param.h>
     47 #include <sys/atomic.h>
     48 #include <sys/sysmacros.h>
     49 #include <sys/disp.h>
     50 #include <sys/kidmap.h>
     51 #include <sys/zone.h>
     52 #include "idmap_prot.h"
     53 #include "kidmap_priv.h"
     54 
     55 
     56 /*
     57  * Defined types
     58  */
     59 
     60 
     61 /*
     62  * This structure holds pointers for the
     63  * batch mapping results.
     64  */
     65 typedef struct idmap_get_res {
     66 	idmap_id_type	idtype;
     67 	uid_t		*uid;
     68 	gid_t		*gid;
     69 	uid_t		*pid;
     70 	int		*is_user;
     71 	const char	**sid_prefix;
     72 	uint32_t	*rid;
     73 	idmap_stat	*stat;
     74 } idmap_get_res;
     75 
     76 /* Batch mapping handle structure */
     77 struct idmap_get_handle {
     78 	struct idmap_zone_specific *zs;
     79 	int 		mapping_num;
     80 	int 		mapping_size;
     81 	idmap_mapping	*mapping;
     82 	idmap_get_res	*result;
     83 };
     84 
     85 
     86 /* Zone specific data */
     87 typedef struct idmap_zone_specific {
     88 	zoneid_t	zone_id;
     89 	kmutex_t	zone_mutex;
     90 	idmap_cache_t	cache;
     91 	door_handle_t 	door_handle;
     92 	int		door_valid;
     93 	int		door_retried;
     94 	uint32_t	message_id;
     95 } idmap_zone_specific_t;
     96 
     97 
     98 
     99 /*
    100  * Module global data
    101  */
    102 
    103 static kmutex_t		idmap_zone_mutex;
    104 static zone_key_t	idmap_zone_key;
    105 
    106 
    107 /*
    108  * Local function definitions
    109  */
    110 
    111 
    112 static int
    113 kidmap_rpc_call(idmap_zone_specific_t *zs, uint32_t op,
    114 		xdrproc_t xdr_args, caddr_t args,
    115 		xdrproc_t xdr_res, caddr_t res);
    116 
    117 static int
    118 kidmap_call_door(idmap_zone_specific_t *zs, door_arg_t *arg);
    119 
    120 static idmap_zone_specific_t *
    121 idmap_get_zone_specific(zone_t *zone);
    122 
    123 
    124 
    125 int
    126 idmap_reg_dh(zone_t *zone, door_handle_t dh)
    127 {
    128 	idmap_zone_specific_t *zs;
    129 
    130 	zs = idmap_get_zone_specific(zone);
    131 
    132 	mutex_enter(&zs->zone_mutex);
    133 
    134 	if (zs->door_valid)
    135 		door_ki_rele(zs->door_handle);
    136 
    137 	zs->door_handle = dh;
    138 	zs->door_valid = 1;
    139 
    140 	mutex_exit(&zs->zone_mutex);
    141 
    142 	return (0);
    143 }
    144 
    145 /*
    146  * idmap_unreg_dh
    147  *
    148  * This routine is called by system call idmap_unreg().
    149  * idmap_unreg() calls door_ki_rele() on the supplied
    150  * door handle after this routine returns. We only
    151  * need to perform one door release on zs->door_handle
    152  */
    153 int
    154 idmap_unreg_dh(zone_t *zone, door_handle_t dh)
    155 {
    156 	idmap_zone_specific_t *zs;
    157 
    158 	zs = idmap_get_zone_specific(zone);
    159 
    160 	kidmap_cache_purge(&zs->cache);
    161 
    162 	mutex_enter(&zs->zone_mutex);
    163 
    164 	if (!zs->door_valid || zs->door_handle != dh) {
    165 		mutex_exit(&zs->zone_mutex);
    166 		return (EINVAL);
    167 	}
    168 
    169 	door_ki_rele(zs->door_handle);
    170 
    171 	zs->door_valid = 0;
    172 	zs->door_retried = 0;
    173 	mutex_exit(&zs->zone_mutex);
    174 
    175 	return (0);
    176 }
    177 
    178 
    179 /*
    180  * IMPORTANT. This function idmap_get_cache_data() is project
    181  * private and is for use of the test system only and should
    182  * not be used for other purposes.
    183  */
    184 void
    185 idmap_get_cache_data(zone_t *zone, size_t *uidbysid, size_t *gidbysid,
    186 	size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid)
    187 {
    188 	idmap_zone_specific_t *zs;
    189 
    190 	zs = idmap_get_zone_specific(zone);
    191 
    192 	kidmap_cache_get_data(&zs->cache, uidbysid, gidbysid,
    193 	    pidbysid, sidbyuid, sidbygid);
    194 }
    195 
    196 static int
    197 kidmap_call_door(idmap_zone_specific_t *zs, door_arg_t *arg)
    198 {
    199 	door_handle_t 	dh;
    200 	door_info_t	di;
    201 	int		status = 0;
    202 	int		num_retries = 5;
    203 	int		door_retried;
    204 
    205 retry:
    206 	mutex_enter(&zs->zone_mutex);
    207 	if (zs->door_valid) {
    208 		dh = zs->door_handle;
    209 		door_ki_hold(dh);
    210 	} else {
    211 		dh = NULL;
    212 		door_retried = zs->door_retried;
    213 	}
    214 	mutex_exit(&zs->zone_mutex);
    215 
    216 	if (dh == NULL) {
    217 		/* The door has been retried before so dont wait */
    218 		if (door_retried)
    219 			return (-1);
    220 
    221 		/*
    222 		 * There is no door handle yet. Give
    223 		 * smf a chance to restart idmapd
    224 		 */
    225 		if (num_retries-- > 0) {
    226 			delay(hz);
    227 			goto retry;
    228 		}
    229 
    230 #ifdef	DEBUG
    231 		zcmn_err(zs->zone_id, CE_WARN,
    232 		    "idmap: Error no registered door to call the "
    233 		    "idmap daemon\n");
    234 #endif
    235 		mutex_enter(&zs->zone_mutex);
    236 		if (!zs->door_valid)
    237 			zs->door_retried = 1;
    238 		mutex_exit(&zs->zone_mutex);
    239 
    240 		return (-1);
    241 	}
    242 
    243 	status = door_ki_upcall_limited(dh, arg, NULL, SIZE_MAX, 0);
    244 
    245 	switch (status) {
    246 	case 0:	/* Success */
    247 		door_ki_rele(dh);
    248 		return (0);
    249 
    250 	case EINTR:
    251 		/* If we took an interrupt we have to bail out. */
    252 		if (ttolwp(curthread) && ISSIG(curthread, JUSTLOOKING)) {
    253 			door_ki_rele(dh);
    254 #ifdef	DEBUG
    255 			zcmn_err(zs->zone_id, CE_WARN,
    256 			    "idmap: Interrupted\n");
    257 #endif
    258 			return (-1);
    259 		}
    260 		/*
    261 		 * Just retry and see what happens.
    262 		 */
    263 		/* FALLTHROUGH */
    264 
    265 	case EAGAIN:
    266 		/* A resouce problem */
    267 		door_ki_rele(dh);
    268 		/* Back off before retrying */
    269 #ifdef	DEBUG
    270 		zcmn_err(zs->zone_id, CE_WARN,
    271 		    "idmap: Door call returned error %d. Retrying\n", status);
    272 #endif	/* DEBUG */
    273 		delay(hz);
    274 		goto retry;
    275 
    276 	case EBADF:
    277 		/* Stale door handle. See if smf restarts the daemon. */
    278 		door_ki_rele(dh);
    279 		mutex_enter(&zs->zone_mutex);
    280 		if (zs->door_valid && dh == zs->door_handle) {
    281 			zs->door_valid = 0;
    282 			zs->door_retried = 0;
    283 			door_ki_rele(zs->door_handle);
    284 		}
    285 		mutex_exit(&zs->zone_mutex);
    286 		/* Back off before retrying */
    287 #ifdef	DEBUG
    288 		zcmn_err(zs->zone_id, CE_WARN,
    289 		    "idmap: Door call returned error %d. Retrying\n", status);
    290 #endif	/* DEBUG */
    291 		delay(hz);
    292 		goto retry;
    293 
    294 	default:
    295 		/* Unknown error */
    296 #ifdef	DEBUG
    297 		zcmn_err(zs->zone_id, CE_WARN,
    298 		    "idmap: Door call returned error %d.\n", status);
    299 #endif	/* DEBUG */
    300 		door_ki_rele(dh);
    301 		return (-1);
    302 	}
    303 }
    304 
    305 
    306 static idmap_zone_specific_t *
    307 idmap_get_zone_specific(zone_t *zone)
    308 {
    309 	idmap_zone_specific_t *zs;
    310 
    311 	ASSERT(zone != NULL);
    312 
    313 	zs = zone_getspecific(idmap_zone_key, zone);
    314 	if (zs != NULL)
    315 		return (zs);
    316 
    317 	mutex_enter(&idmap_zone_mutex);
    318 	zs = zone_getspecific(idmap_zone_key, zone);
    319 	if (zs == NULL) {
    320 		zs = kmem_zalloc(sizeof (idmap_zone_specific_t), KM_SLEEP);
    321 		mutex_init(&zs->zone_mutex, NULL, MUTEX_DEFAULT, NULL);
    322 		kidmap_cache_create(&zs->cache);
    323 		zs->zone_id = zone->zone_id;
    324 		(void) zone_setspecific(idmap_zone_key, zone, zs);
    325 		mutex_exit(&idmap_zone_mutex);
    326 		return (zs);
    327 	}
    328 	mutex_exit(&idmap_zone_mutex);
    329 
    330 	return (zs);
    331 }
    332 
    333 
    334 static void
    335 /* ARGSUSED */
    336 idmap_zone_destroy(zoneid_t zone_id, void *arg)
    337 {
    338 	idmap_zone_specific_t *zs = arg;
    339 	if (zs != NULL) {
    340 		kidmap_cache_delete(&zs->cache);
    341 		if (zs->door_valid) {
    342 			door_ki_rele(zs->door_handle);
    343 		}
    344 		mutex_destroy(&zs->zone_mutex);
    345 		kmem_free(zs, sizeof (idmap_zone_specific_t));
    346 	}
    347 }
    348 
    349 
    350 int
    351 kidmap_start(void)
    352 {
    353 	mutex_init(&idmap_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
    354 	zone_key_create(&idmap_zone_key, NULL, NULL, idmap_zone_destroy);
    355 	kidmap_sid_prefix_store_init();
    356 
    357 	return (0);
    358 }
    359 
    360 
    361 int
    362 kidmap_stop(void)
    363 {
    364 	return (EBUSY);
    365 }
    366 
    367 
    368 /*
    369  * idmap_get_door
    370  *
    371  * This is called by the system call allocids() to get the door for the
    372  * given zone.
    373  */
    374 door_handle_t
    375 idmap_get_door(zone_t *zone)
    376 {
    377 	door_handle_t dh = NULL;
    378 	idmap_zone_specific_t *zs;
    379 
    380 	zs = idmap_get_zone_specific(zone);
    381 
    382 	mutex_enter(&zs->zone_mutex);
    383 	if (zs->door_valid) {
    384 		dh = zs->door_handle;
    385 		door_ki_hold(dh);
    386 	}
    387 	mutex_exit(&zs->zone_mutex);
    388 	return (dh);
    389 }
    390 
    391 
    392 /*
    393  * idmap_purge_cache
    394  *
    395  * This is called by the system call allocids() to purge the cache for the
    396  * given zone.
    397  */
    398 void
    399 idmap_purge_cache(zone_t *zone)
    400 {
    401 	idmap_zone_specific_t *zs;
    402 
    403 	zs = idmap_get_zone_specific(zone);
    404 
    405 	kidmap_cache_purge(&zs->cache);
    406 }
    407 
    408 
    409 
    410 
    411 /*
    412  * Given Domain SID and RID, get UID
    413  *
    414  * Input:
    415  * sid_prefix	- Domain SID in canonical form
    416  * rid	- RID
    417  *
    418  * Output:
    419  * uid  - POSIX UID if return == IDMAP_SUCCESS
    420  *
    421  * Return:
    422  * Success return IDMAP_SUCCESS else IDMAP error
    423  */
    424 idmap_stat
    425 kidmap_getuidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
    426 		uid_t *uid)
    427 {
    428 	idmap_zone_specific_t	*zs;
    429 	idmap_mapping_batch	args;
    430 	idmap_mapping		mapping;
    431 	idmap_ids_res		results;
    432 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
    433 	const char		*new_sid_prefix;
    434 	idmap_stat		status;
    435 
    436 	if (sid_prefix == NULL || uid == NULL)
    437 		return (IDMAP_ERR_ARG);
    438 
    439 	zs = idmap_get_zone_specific(zone);
    440 
    441 	if (kidmap_cache_lookup_uidbysid(&zs->cache, sid_prefix, rid, uid)
    442 	    == IDMAP_SUCCESS)
    443 		return (IDMAP_SUCCESS);
    444 
    445 	bzero(&mapping, sizeof (idmap_mapping));
    446 	mapping.id1.idtype = IDMAP_SID;
    447 	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
    448 	mapping.id1.idmap_id_u.sid.rid = rid;
    449 	mapping.id2.idtype = IDMAP_UID;
    450 
    451 	bzero(&results, sizeof (idmap_ids_res));
    452 
    453 	args.idmap_mapping_batch_len = 1;
    454 	args.idmap_mapping_batch_val = &mapping;
    455 
    456 	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
    457 	    (caddr_t)&args, xdr_idmap_ids_res,
    458 	    (caddr_t)&results) == 0) {
    459 		/* Door call succeded */
    460 		if (results.retcode != IDMAP_SUCCESS) {
    461 			status = results.retcode;
    462 			*uid = UID_NOBODY;
    463 		} else if (results.ids.ids_len >= 1 &&
    464 		    results.ids.ids_val[0].id.idtype == IDMAP_UID) {
    465 			status = results.ids.ids_val[0].retcode;
    466 			*uid = results.ids.ids_val[0].id.idmap_id_u.uid;
    467 			if (status == IDMAP_SUCCESS) {
    468 				new_sid_prefix = kidmap_find_sid_prefix(
    469 				    sid_prefix);
    470 				kidmap_cache_add_sid2uid(&zs->cache,
    471 				    new_sid_prefix, rid, *uid,
    472 				    results.ids.ids_val[0].direction);
    473 			}
    474 		} else {
    475 			status = IDMAP_ERR_NOMAPPING;
    476 			*uid = UID_NOBODY;
    477 		}
    478 		xdr_free(xdr_idmap_ids_res, (char *)&results);
    479 	} else {
    480 		/* Door call failed */
    481 		status = IDMAP_ERR_NOMAPPING;
    482 		*uid = UID_NOBODY;
    483 	}
    484 	return (status);
    485 }
    486 
    487 
    488 /*
    489  * Given Domain SID and RID, get GID
    490  *
    491  * Input:
    492  * sid_prefix	- Domain SID in canonical form
    493  * rid	- RID
    494  *
    495  * Output:
    496  * gid  - POSIX UID if return == IDMAP_SUCCESS
    497  *
    498  * Return:
    499  * Success return IDMAP_SUCCESS else IDMAP error
    500  */
    501 idmap_stat
    502 kidmap_getgidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
    503 		gid_t *gid)
    504 {
    505 	idmap_zone_specific_t	*zs;
    506 	idmap_mapping_batch	args;
    507 	idmap_mapping		mapping;
    508 	idmap_ids_res		results;
    509 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
    510 	const char		*new_sid_prefix;
    511 	idmap_stat		status;
    512 
    513 	if (sid_prefix == NULL || gid == NULL)
    514 		return (IDMAP_ERR_ARG);
    515 
    516 	zs = idmap_get_zone_specific(zone);
    517 
    518 	if (kidmap_cache_lookup_gidbysid(&zs->cache, sid_prefix, rid, gid)
    519 	    == IDMAP_SUCCESS)
    520 		return (IDMAP_SUCCESS);
    521 
    522 	bzero(&mapping, sizeof (idmap_mapping));
    523 	mapping.id1.idtype = IDMAP_SID;
    524 	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
    525 	mapping.id1.idmap_id_u.sid.rid = rid;
    526 	mapping.id2.idtype = IDMAP_GID;
    527 
    528 	bzero(&results, sizeof (idmap_ids_res));
    529 
    530 	args.idmap_mapping_batch_len = 1;
    531 	args.idmap_mapping_batch_val = &mapping;
    532 
    533 	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
    534 	    (caddr_t)&args, xdr_idmap_ids_res,
    535 	    (caddr_t)&results) == 0) {
    536 		/* Door call succeded */
    537 		if (results.retcode != IDMAP_SUCCESS) {
    538 			status = results.retcode;
    539 			*gid = GID_NOBODY;
    540 		} else if (results.ids.ids_len >= 1 &&
    541 		    results.ids.ids_val[0].id.idtype == IDMAP_GID) {
    542 			status = results.ids.ids_val[0].retcode;
    543 			*gid = results.ids.ids_val[0].id.idmap_id_u.gid;
    544 			if (status == IDMAP_SUCCESS) {
    545 				new_sid_prefix = kidmap_find_sid_prefix(
    546 				    sid_prefix);
    547 				kidmap_cache_add_sid2gid(&zs->cache,
    548 				    new_sid_prefix, rid, *gid,
    549 				    results.ids.ids_val[0].direction);
    550 			}
    551 		} else {
    552 			status = IDMAP_ERR_NOMAPPING;
    553 			*gid = GID_NOBODY;
    554 		}
    555 		xdr_free(xdr_idmap_ids_res, (char *)&results);
    556 	} else {
    557 		/* Door call failed */
    558 		status = IDMAP_ERR_NOMAPPING;
    559 		*gid = GID_NOBODY;
    560 	}
    561 	return (status);
    562 }
    563 
    564 /*
    565  * Given Domain SID and RID, get Posix ID
    566  *
    567  * Input:
    568  * sid_prefix	- Domain SID in canonical form
    569  * rid	- RID
    570  *
    571  * Output:
    572  * pid  - POSIX ID if return == IDMAP_SUCCESS
    573  * is_user - 1 == UID, 0 == GID  if return == IDMAP_SUCCESS
    574  *
    575  * Return:
    576  * Success return IDMAP_SUCCESS else IDMAP error
    577  */
    578 idmap_stat
    579 kidmap_getpidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
    580 		uid_t *pid, int *is_user)
    581 {
    582 	idmap_zone_specific_t	*zs;
    583 	idmap_mapping_batch	args;
    584 	idmap_mapping		mapping;
    585 	idmap_ids_res		results;
    586 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
    587 	const char		*new_sid_prefix;
    588 	idmap_stat		status;
    589 
    590 	if (sid_prefix == NULL || pid == NULL || is_user == NULL)
    591 		return (IDMAP_ERR_ARG);
    592 
    593 	zs = idmap_get_zone_specific(zone);
    594 
    595 	if (kidmap_cache_lookup_pidbysid(&zs->cache, sid_prefix, rid, pid,
    596 	    is_user) == IDMAP_SUCCESS)
    597 		return (IDMAP_SUCCESS);
    598 
    599 	bzero(&mapping, sizeof (idmap_mapping));
    600 	mapping.id1.idtype = IDMAP_SID;
    601 	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
    602 	mapping.id1.idmap_id_u.sid.rid = rid;
    603 	mapping.id2.idtype = IDMAP_POSIXID;
    604 
    605 	bzero(&results, sizeof (idmap_ids_res));
    606 
    607 	args.idmap_mapping_batch_len = 1;
    608 	args.idmap_mapping_batch_val = &mapping;
    609 
    610 	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
    611 	    (caddr_t)&args, xdr_idmap_ids_res,
    612 	    (caddr_t)&results) == 0) {
    613 		/* Door call succeded */
    614 		if (results.retcode != IDMAP_SUCCESS) {
    615 			status = results.retcode;
    616 			*is_user = 1;
    617 			*pid = UID_NOBODY;
    618 		} else if (results.ids.ids_len >= 1 && (
    619 		    results.ids.ids_val[0].id.idtype == IDMAP_UID ||
    620 		    results.ids.ids_val[0].id.idtype == IDMAP_GID)) {
    621 			status = results.ids.ids_val[0].retcode;
    622 			if (results.ids.ids_val[0].id.idtype == IDMAP_UID) {
    623 				*is_user = 1;
    624 				*pid = results.ids.ids_val[0].id.idmap_id_u.uid;
    625 			} else {
    626 				*is_user = 0;
    627 				*pid = results.ids.ids_val[0].id.idmap_id_u.gid;
    628 			}
    629 			if (status == IDMAP_SUCCESS) {
    630 				new_sid_prefix = kidmap_find_sid_prefix(
    631 				    sid_prefix);
    632 				kidmap_cache_add_sid2pid(&zs->cache,
    633 				    new_sid_prefix, rid, *pid,
    634 				    *is_user,
    635 				    results.ids.ids_val[0].direction);
    636 			}
    637 		} else {
    638 			status = IDMAP_ERR_NOMAPPING;
    639 			*is_user = 1;
    640 			*pid = UID_NOBODY;
    641 		}
    642 		xdr_free(xdr_idmap_ids_res, (char *)&results);
    643 	} else {
    644 		/* Door call failed */
    645 		status = IDMAP_ERR_NOMAPPING;
    646 		*is_user = 1;
    647 		*pid = UID_NOBODY;
    648 	}
    649 	return (status);
    650 }
    651 
    652 
    653 /*
    654  * Given UID, get Domain SID and RID
    655  *
    656  * Input:
    657  * uid - Posix UID
    658  *
    659  * Output:
    660  * sid_prefix	- Domain SID if return == IDMAP_SUCCESS
    661  * rid	- RID if return == IDMAP_SUCCESS
    662  *
    663  * Return:
    664  * Success return IDMAP_SUCCESS else IDMAP error
    665  */
    666 idmap_stat
    667 kidmap_getsidbyuid(zone_t *zone, uid_t uid, const char **sid_prefix,
    668 		uint32_t *rid)
    669 {
    670 	idmap_zone_specific_t	*zs;
    671 	idmap_mapping_batch	args;
    672 	idmap_mapping		mapping;
    673 	idmap_ids_res		results;
    674 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
    675 	idmap_stat		status;
    676 	time_t			entry_ttl;
    677 	idmap_id		*id;
    678 
    679 	if (sid_prefix == NULL || rid == NULL)
    680 		return (IDMAP_ERR_ARG);
    681 
    682 	zs = idmap_get_zone_specific(zone);
    683 
    684 	if (kidmap_cache_lookup_sidbyuid(&zs->cache, sid_prefix, rid, uid)
    685 	    == IDMAP_SUCCESS) {
    686 		return (IDMAP_SUCCESS);
    687 	}
    688 
    689 	bzero(&mapping, sizeof (idmap_mapping));
    690 	mapping.id1.idtype = IDMAP_UID;
    691 	mapping.id1.idmap_id_u.uid = uid;
    692 	mapping.id2.idtype = IDMAP_SID;
    693 
    694 	bzero(&results, sizeof (idmap_ids_res));
    695 
    696 	args.idmap_mapping_batch_len = 1;
    697 	args.idmap_mapping_batch_val = &mapping;
    698 
    699 	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
    700 	    (caddr_t)&args, xdr_idmap_ids_res,
    701 	    (caddr_t)&results) == 0) {
    702 		/* Door call succeded */
    703 		if (results.retcode != IDMAP_SUCCESS) {
    704 			status = results.retcode;
    705 			*rid = 0;
    706 			*sid_prefix = NULL;
    707 		} else if (results.ids.ids_len >= 1 &&
    708 		    (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
    709 		    results.ids.ids_val[0].id.idtype == IDMAP_USID ||
    710 		    results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
    711 			status = results.ids.ids_val[0].retcode;
    712 			id = &results.ids.ids_val[0].id;
    713 			*sid_prefix = kidmap_find_sid_prefix(
    714 			    id->idmap_id_u.sid.prefix);
    715 			*rid = id->idmap_id_u.sid.rid;
    716 			if (status == IDMAP_SUCCESS) {
    717 				kidmap_cache_add_sid2uid(&zs->cache,
    718 				    *sid_prefix, *rid, uid,
    719 				    results.ids.ids_val[0].direction);
    720 			}
    721 		} else {
    722 			status = IDMAP_ERR_NOMAPPING;
    723 			*rid = 0;
    724 			*sid_prefix = NULL;
    725 		}
    726 		xdr_free(xdr_idmap_ids_res, (char *)&results);
    727 	} else {
    728 		/* Door call failed */
    729 		status = IDMAP_ERR_NOMAPPING;
    730 		*rid = 0;
    731 		*sid_prefix = NULL;
    732 	}
    733 	return (status);
    734 }
    735 
    736 
    737 /*
    738  * Given GID, get Domain SID and RID
    739  *
    740  * Input:
    741  * gid - Posix GID
    742  *
    743  * Output:
    744  * sid_prefix	- Domain SID if return == IDMAP_SUCCESS
    745  * rid	- RID if return == IDMAP_SUCCESS
    746  *
    747  * Return:
    748  * Success return IDMAP_SUCCESS else IDMAP error
    749  */
    750 idmap_stat
    751 kidmap_getsidbygid(zone_t *zone, gid_t gid, const char **sid_prefix,
    752 		uint32_t *rid)
    753 {
    754 	idmap_zone_specific_t	*zs;
    755 	idmap_mapping_batch	args;
    756 	idmap_mapping		mapping;
    757 	idmap_ids_res		results;
    758 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
    759 	idmap_stat		status;
    760 	idmap_id		*id;
    761 
    762 	if (sid_prefix == NULL || rid == NULL)
    763 		return (IDMAP_ERR_ARG);
    764 
    765 	zs = idmap_get_zone_specific(zone);
    766 
    767 	if (kidmap_cache_lookup_sidbygid(&zs->cache, sid_prefix, rid, gid)
    768 	    == IDMAP_SUCCESS) {
    769 		return (IDMAP_SUCCESS);
    770 	}
    771 
    772 	bzero(&mapping, sizeof (idmap_mapping));
    773 	mapping.id1.idtype = IDMAP_GID;
    774 	mapping.id1.idmap_id_u.uid = gid;
    775 	mapping.id2.idtype = IDMAP_SID;
    776 
    777 	bzero(&results, sizeof (idmap_ids_res));
    778 
    779 	args.idmap_mapping_batch_len = 1;
    780 	args.idmap_mapping_batch_val = &mapping;
    781 
    782 	if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
    783 	    (caddr_t)&args, xdr_idmap_ids_res,
    784 	    (caddr_t)&results) == 0) {
    785 		/* Door call succeded */
    786 		if (results.retcode != IDMAP_SUCCESS) {
    787 			status = results.retcode;
    788 			*rid = 0;
    789 			*sid_prefix = NULL;
    790 		} else if (results.ids.ids_len >= 1 &&
    791 		    (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
    792 		    results.ids.ids_val[0].id.idtype == IDMAP_USID ||
    793 		    results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
    794 			status = results.ids.ids_val[0].retcode;
    795 			id = &results.ids.ids_val[0].id;
    796 			*sid_prefix = kidmap_find_sid_prefix(
    797 			    id->idmap_id_u.sid.prefix);
    798 			*rid = id->idmap_id_u.sid.rid;
    799 			if (status == IDMAP_SUCCESS) {
    800 				kidmap_cache_add_sid2gid(&zs->cache,
    801 				    *sid_prefix, *rid, gid,
    802 				    results.ids.ids_val[0].direction);
    803 			}
    804 		} else {
    805 			status = IDMAP_ERR_NOMAPPING;
    806 			*rid = 0;
    807 			*sid_prefix = NULL;
    808 		}
    809 		xdr_free(xdr_idmap_ids_res, (char *)&results);
    810 	} else {
    811 		/* Door call failed */
    812 		status = IDMAP_ERR_NOMAPPING;
    813 		*rid = 0;
    814 		*sid_prefix = NULL;
    815 	}
    816 	return (status);
    817 }
    818 
    819 /*
    820  * Create handle to get SID to UID/GID mapping entries
    821  *
    822  * Input:
    823  * 	none
    824  * Return:
    825  *	get_handle
    826  *
    827  */
    828 idmap_get_handle_t *
    829 kidmap_get_create(zone_t *zone)
    830 {
    831 	idmap_zone_specific_t	*zs;
    832 	idmap_get_handle_t	*handle;
    833 #define	INIT_MAPPING_SIZE	32
    834 
    835 	zs = idmap_get_zone_specific(zone);
    836 
    837 	handle = kmem_zalloc(sizeof (idmap_get_handle_t), KM_SLEEP);
    838 
    839 	handle->mapping = kmem_zalloc((sizeof (idmap_mapping)) *
    840 	    INIT_MAPPING_SIZE, KM_SLEEP);
    841 
    842 	handle->result = kmem_zalloc((sizeof (idmap_get_res)) *
    843 	    INIT_MAPPING_SIZE, KM_SLEEP);
    844 	handle->mapping_size = INIT_MAPPING_SIZE;
    845 	handle->zs = zs;
    846 
    847 	return (handle);
    848 }
    849 
    850 /*
    851  * Internal routine to extend a "get_handle"
    852  */
    853 static void
    854 kidmap_get_extend(idmap_get_handle_t *get_handle)
    855 {
    856 	idmap_mapping *mapping;
    857 	idmap_get_res *result;
    858 	int new_size = get_handle->mapping_size + INIT_MAPPING_SIZE;
    859 
    860 	mapping = kmem_zalloc((sizeof (idmap_mapping)) *
    861 	    new_size, KM_SLEEP);
    862 	(void) memcpy(mapping, get_handle->mapping,
    863 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
    864 
    865 	result = kmem_zalloc((sizeof (idmap_get_res)) *
    866 	    new_size, KM_SLEEP);
    867 	(void) memcpy(result, get_handle->result,
    868 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
    869 
    870 	kmem_free(get_handle->mapping,
    871 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
    872 	get_handle->mapping = mapping;
    873 
    874 	kmem_free(get_handle->result,
    875 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
    876 	get_handle->result = result;
    877 
    878 	get_handle->mapping_size = new_size;
    879 }
    880 
    881 
    882 /*
    883  * Given Domain SID and RID, get UID
    884  *
    885  * Input:
    886  * sid_prefix	- Domain SID in canonical form
    887  * rid	- RID
    888  *
    889  * Output:
    890  * stat - status of the get request
    891  * uid  - POSIX UID if stat == IDMAP_SUCCESS
    892  *
    893  * Note: The output parameters will be set by idmap_get_mappings()
    894  */
    895 idmap_stat
    896 kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
    897 			uint32_t rid, uid_t *uid, idmap_stat *stat)
    898 {
    899 	idmap_mapping	*mapping;
    900 	idmap_get_res 	*result;
    901 
    902 	if (get_handle == NULL || sid_prefix == NULL ||
    903 	    uid == NULL || stat == NULL)
    904 		return (IDMAP_ERR_ARG);
    905 
    906 	if (kidmap_cache_lookup_uidbysid(&get_handle->zs->cache, sid_prefix,
    907 	    rid, uid) == IDMAP_SUCCESS) {
    908 		*stat = IDMAP_SUCCESS;
    909 		return (IDMAP_SUCCESS);
    910 	}
    911 
    912 	if (get_handle->mapping_num >= get_handle->mapping_size)
    913 		kidmap_get_extend(get_handle);
    914 
    915 	mapping = &get_handle->mapping[get_handle->mapping_num];
    916 	mapping->flag = 0;
    917 	mapping->id1.idtype = IDMAP_SID;
    918 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
    919 	mapping->id1.idmap_id_u.sid.rid = rid;
    920 	mapping->id2.idtype = IDMAP_UID;
    921 
    922 	result = &get_handle->result[get_handle->mapping_num];
    923 	result->idtype = IDMAP_UID;
    924 	result->uid = uid;
    925 	result->gid = NULL;
    926 	result->pid = NULL;
    927 	result->sid_prefix = NULL;
    928 	result->rid = NULL;
    929 	result->is_user = NULL;
    930 	result->stat = stat;
    931 
    932 	get_handle->mapping_num++;
    933 
    934 	return (IDMAP_SUCCESS);
    935 }
    936 
    937 
    938 /*
    939  * Given Domain SID and RID, get GID
    940  *
    941  * Input:
    942  * sid_prefix	- Domain SID in canonical form
    943  * rid	- RID
    944  *
    945  * Output:
    946  * stat - status of the get request
    947  * gid  - POSIX GID if stat == IDMAP_SUCCESS
    948  *
    949  * Note: The output parameters will be set by idmap_get_mappings()
    950  */
    951 idmap_stat
    952 kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
    953 			uint32_t rid, uid_t *gid, idmap_stat *stat)
    954 {
    955 	idmap_mapping	*mapping;
    956 	idmap_get_res 	*result;
    957 
    958 	if (get_handle == NULL || sid_prefix == NULL ||
    959 	    gid == NULL || stat == NULL)
    960 		return (IDMAP_ERR_ARG);
    961 
    962 	if (kidmap_cache_lookup_gidbysid(&get_handle->zs->cache, sid_prefix,
    963 	    rid, gid) == IDMAP_SUCCESS) {
    964 		*stat = IDMAP_SUCCESS;
    965 		return (IDMAP_SUCCESS);
    966 	}
    967 
    968 	if (get_handle->mapping_num >= get_handle->mapping_size)
    969 		kidmap_get_extend(get_handle);
    970 
    971 	mapping = &get_handle->mapping[get_handle->mapping_num];
    972 	mapping->flag = 0;
    973 	mapping->id1.idtype = IDMAP_SID;
    974 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
    975 	mapping->id1.idmap_id_u.sid.rid = rid;
    976 	mapping->id2.idtype = IDMAP_GID;
    977 
    978 	result = &get_handle->result[get_handle->mapping_num];
    979 	result->idtype = IDMAP_GID;
    980 	result->uid = NULL;
    981 	result->gid = gid;
    982 	result->pid = NULL;
    983 	result->sid_prefix = NULL;
    984 	result->rid = NULL;
    985 	result->is_user = NULL;
    986 	result->stat = stat;
    987 
    988 	get_handle->mapping_num++;
    989 
    990 	return (IDMAP_SUCCESS);
    991 }
    992 
    993 
    994 /*
    995  * Given Domain SID and RID, get Posix ID
    996  *
    997  * Input:
    998  * sid_prefix	- Domain SID in canonical form
    999  * rid	- RID
   1000  *
   1001  * Output:
   1002  * stat    - status of the get request
   1003  * is_user - user or group
   1004  * pid     - POSIX UID if stat == IDMAP_SUCCESS and is_user == 1
   1005  *           POSIX GID if stat == IDMAP_SUCCESS and is_user == 0
   1006  *
   1007  * Note: The output parameters will be set by idmap_get_mappings()
   1008  */
   1009 idmap_stat
   1010 kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
   1011 		uint32_t rid, uid_t *pid, int *is_user, idmap_stat *stat)
   1012 {
   1013 	idmap_mapping	*mapping;
   1014 	idmap_get_res 	*result;
   1015 
   1016 	if (get_handle == NULL || sid_prefix == NULL || pid == NULL ||
   1017 	    is_user == NULL || stat == NULL)
   1018 		return (IDMAP_ERR_ARG);
   1019 
   1020 	if (kidmap_cache_lookup_pidbysid(&get_handle->zs->cache, sid_prefix,
   1021 	    rid, pid, is_user) == IDMAP_SUCCESS) {
   1022 		*stat = IDMAP_SUCCESS;
   1023 		return (IDMAP_SUCCESS);
   1024 	}
   1025 
   1026 
   1027 	if (get_handle->mapping_num >= get_handle->mapping_size)
   1028 		kidmap_get_extend(get_handle);
   1029 
   1030 	mapping = &get_handle->mapping[get_handle->mapping_num];
   1031 	mapping->flag = 0;
   1032 	mapping->id1.idtype = IDMAP_SID;
   1033 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
   1034 	mapping->id1.idmap_id_u.sid.rid = rid;
   1035 	mapping->id2.idtype = IDMAP_POSIXID;
   1036 
   1037 	result = &get_handle->result[get_handle->mapping_num];
   1038 	result->idtype = IDMAP_POSIXID;
   1039 	result->uid = NULL;
   1040 	result->gid = NULL;
   1041 	result->pid = pid;
   1042 	result->sid_prefix = NULL;
   1043 	result->rid = NULL;
   1044 	result->is_user = is_user;
   1045 	result->stat = stat;
   1046 
   1047 	get_handle->mapping_num++;
   1048 
   1049 	return (IDMAP_SUCCESS);
   1050 }
   1051 
   1052 
   1053 /*
   1054  * Given UID, get SID and RID
   1055  *
   1056  * Input:
   1057  * uid  - POSIX UID
   1058  *
   1059  * Output:
   1060  * stat - status of the get request
   1061  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
   1062  * rid	- RID (if stat == IDMAP_SUCCESS)
   1063  *
   1064  * Note: The output parameters will be set by idmap_get_mappings()
   1065  */
   1066 idmap_stat
   1067 kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
   1068 		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
   1069 {
   1070 	idmap_mapping	*mapping;