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 the kernel cache.
     30  */
     31 
     32 
     33 #include <sys/types.h>
     34 #include <sys/avl.h>
     35 #include <sys/systm.h>
     36 #include <sys/sysmacros.h>
     37 #include <sys/ksynch.h>
     38 #include <sys/kidmap.h>
     39 #include "idmap_prot.h"
     40 #include "kidmap_priv.h"
     41 
     42 
     43 /*
     44  * External functions
     45  */
     46 extern	uintptr_t	space_fetch(char *key);
     47 extern	int		space_store(char *key, uintptr_t ptr);
     48 
     49 
     50 /*
     51  * Internal definitions and functions
     52  */
     53 
     54 #define	CACHE_UID_TRIGGER_SIZE	4096
     55 #define	CACHE_GID_TRIGGER_SIZE	2048
     56 #define	CACHE_PID_TRIGGER_SIZE \
     57 	(CACHE_UID_TRIGGER_SIZE + CACHE_GID_TRIGGER_SIZE)
     58 
     59 
     60 #define	UNDEF_UID	((uid_t)-1)
     61 #define	UNDEF_GID	((gid_t)-1)
     62 #define	UNDEF_ISUSER	(-1)
     63 
     64 #define	CACHE_PURGE_INTERVAL	(60 * 3)
     65 #define	CACHE_TTL		(60 * 10)
     66 
     67 
     68 
     69 #define	list_insert(head, ele)\
     70 	do {\
     71 		(ele)->flink = (head)->flink;\
     72 		(head)->flink = (ele);\
     73 		(ele)->blink = (ele)->flink->blink;\
     74 		(ele)->flink->blink = (ele);\
     75 	} while (0)
     76 
     77 
     78 
     79 #define	list_remove(ele)\
     80 	do {\
     81 		(ele)->flink->blink = (ele)->blink;\
     82 		(ele)->blink->flink = (ele)->flink;\
     83 	} while (0)
     84 
     85 
     86 #define	list_move(head, ele) \
     87 	do {\
     88 		if ((head)->flink != (ele)) {\
     89 			list_remove(ele);\
     90 			list_insert(head, ele);\
     91 		}\
     92 	} while (0)
     93 
     94 
     95 typedef struct sid_prefix_node {
     96 	avl_node_t	avl_link;
     97 	const char 	*sid_prefix;
     98 } sid_prefix_node_t;
     99 
    100 
    101 typedef int (*avl_comp_fn)(const void*, const void*);
    102 
    103 
    104 struct sid_prefix_store {
    105 	struct avl_tree	tree;
    106 	krwlock_t	lock;
    107 };
    108 
    109 struct sid_prefix_store *kidmap_sid_prefix_store = NULL;
    110 
    111 
    112 
    113 static void
    114 kidmap_purge_sid2pid_cache(idmap_sid2pid_cache_t *cache, size_t limit);
    115 
    116 static void
    117 kidmap_purge_pid2sid_cache(idmap_pid2sid_cache_t *cache, size_t limit);
    118 
    119 
    120 /*
    121  * kidmap_strdup() copied from uts/common/fs/sockfs/nl7c.c
    122  */
    123 static char *
    124 kidmap_strdup(const char *s)
    125 {
    126 	int	len = strlen(s) + 1;
    127 	char	*ret = kmem_alloc(len, KM_SLEEP);
    128 
    129 	bcopy(s, ret, len);
    130 	return (ret);
    131 }
    132 
    133 
    134 static int
    135 kidmap_compare_sid(const sid2pid_t *entry1, const sid2pid_t *entry2)
    136 {
    137 	int64_t comp = ((int64_t)entry2->rid) - ((int64_t)entry1->rid);
    138 
    139 	if (comp == 0)
    140 		comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
    141 
    142 	if (comp < 0)
    143 		comp = -1;
    144 	else if (comp > 0)
    145 		comp = 1;
    146 
    147 	return ((int)comp);
    148 }
    149 
    150 
    151 static int
    152 kidmap_compare_pid(const pid2sid_t *entry1, const pid2sid_t *entry2)
    153 {
    154 	if (entry2->pid > entry1->pid)
    155 		return (1);
    156 	if (entry2->pid < entry1->pid)
    157 		return (-1);
    158 	return (0);
    159 }
    160 
    161 
    162 static int
    163 kidmap_compare_sid_prefix(const sid_prefix_node_t *entry1,
    164 			const sid_prefix_node_t *entry2)
    165 {
    166 	int comp;
    167 
    168 	comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
    169 
    170 	if (comp < 0)
    171 		comp = -1;
    172 	else if (comp > 0)
    173 		comp = 1;
    174 
    175 	return (comp);
    176 }
    177 
    178 
    179 void
    180 kidmap_cache_create(idmap_cache_t *cache)
    181 {
    182 	avl_create(&cache->sid2pid.tree, (avl_comp_fn)kidmap_compare_sid,
    183 	    sizeof (sid2pid_t), offsetof(sid2pid_t, avl_link));
    184 	mutex_init(&cache->sid2pid.mutex, NULL, MUTEX_DEFAULT, NULL);
    185 	cache->sid2pid.purge_time = 0;
    186 	cache->sid2pid.head.flink = &cache->sid2pid.head;
    187 	cache->sid2pid.head.blink = &cache->sid2pid.head;
    188 	cache->sid2pid.uid_num = 0;
    189 	cache->sid2pid.gid_num = 0;
    190 	cache->sid2pid.pid_num = 0;
    191 
    192 	avl_create(&cache->uid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
    193 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
    194 	mutex_init(&cache->uid2sid.mutex, NULL, MUTEX_DEFAULT, NULL);
    195 	cache->uid2sid.purge_time = 0;
    196 	cache->uid2sid.head.flink = &cache->uid2sid.head;
    197 	cache->uid2sid.head.blink = &cache->uid2sid.head;
    198 
    199 	avl_create(&cache->gid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
    200 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
    201 	mutex_init(&cache->gid2sid.mutex, NULL, MUTEX_DEFAULT, NULL);
    202 	cache->gid2sid.purge_time = 0;
    203 	cache->gid2sid.head.flink = &cache->gid2sid.head;
    204 	cache->gid2sid.head.blink = &cache->gid2sid.head;
    205 }
    206 
    207 
    208 void
    209 kidmap_cache_delete(idmap_cache_t *cache)
    210 {
    211 	sid2pid_t *sid2pid;
    212 	pid2sid_t *pid2sid;
    213 	void *cookie;
    214 
    215 	cookie = NULL;
    216 	while ((sid2pid = avl_destroy_nodes(&cache->sid2pid.tree, &cookie))
    217 	    != NULL) {
    218 		kmem_free(sid2pid, sizeof (sid2pid_t));
    219 	}
    220 	avl_destroy(&cache->sid2pid.tree);
    221 	mutex_destroy(&cache->sid2pid.mutex);
    222 
    223 
    224 	cookie = NULL;
    225 	while ((pid2sid = avl_destroy_nodes(&cache->uid2sid.tree, &cookie))
    226 	    != NULL) {
    227 		kmem_free(pid2sid, sizeof (pid2sid_t));
    228 	}
    229 	avl_destroy(&cache->uid2sid.tree);
    230 	mutex_destroy(&cache->uid2sid.mutex);
    231 
    232 
    233 	cookie = NULL;
    234 	while ((pid2sid = avl_destroy_nodes(&cache->gid2sid.tree, &cookie))
    235 	    != NULL) {
    236 		kmem_free(pid2sid, sizeof (pid2sid_t));
    237 	}
    238 	avl_destroy(&cache->gid2sid.tree);
    239 	mutex_destroy(&cache->gid2sid.mutex);
    240 }
    241 
    242 
    243 void
    244 kidmap_cache_get_data(idmap_cache_t *cache, size_t *uidbysid, size_t *gidbysid,
    245 	size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid)
    246 {
    247 	mutex_enter(&cache->sid2pid.mutex);
    248 	*uidbysid = cache->sid2pid.uid_num;
    249 	*gidbysid = cache->sid2pid.gid_num;
    250 	*pidbysid = cache->sid2pid.pid_num;
    251 	mutex_exit(&cache->sid2pid.mutex);
    252 
    253 	mutex_enter(&cache->uid2sid.mutex);
    254 	*sidbyuid = avl_numnodes(&cache->uid2sid.tree);
    255 	mutex_exit(&cache->uid2sid.mutex);
    256 
    257 	mutex_enter(&cache->gid2sid.mutex);
    258 	*sidbygid = avl_numnodes(&cache->gid2sid.tree);
    259 	mutex_exit(&cache->gid2sid.mutex);
    260 }
    261 
    262 
    263 void
    264 kidmap_cache_purge(idmap_cache_t *cache)
    265 {
    266 	sid2pid_t *sid2pid;
    267 	pid2sid_t *pid2sid;
    268 	void *cookie;
    269 
    270 	mutex_enter(&cache->sid2pid.mutex);
    271 	cookie = NULL;
    272 	while ((sid2pid = avl_destroy_nodes(&cache->sid2pid.tree, &cookie))
    273 	    != NULL) {
    274 		kmem_free(sid2pid, sizeof (sid2pid_t));
    275 	}
    276 	avl_destroy(&cache->sid2pid.tree);
    277 	avl_create(&cache->sid2pid.tree, (avl_comp_fn)kidmap_compare_sid,
    278 	    sizeof (sid2pid_t), offsetof(sid2pid_t, avl_link));
    279 	cache->sid2pid.purge_time = 0;
    280 	cache->sid2pid.head.flink = &cache->sid2pid.head;
    281 	cache->sid2pid.head.blink = &cache->sid2pid.head;
    282 	cache->sid2pid.uid_num = 0;
    283 	cache->sid2pid.gid_num = 0;
    284 	cache->sid2pid.pid_num = 0;
    285 	mutex_exit(&cache->sid2pid.mutex);
    286 
    287 
    288 	mutex_enter(&cache->uid2sid.mutex);
    289 	cookie = NULL;
    290 	while ((pid2sid = avl_destroy_nodes(&cache->uid2sid.tree, &cookie))
    291 	    != NULL) {
    292 		kmem_free(pid2sid, sizeof (pid2sid_t));
    293 	}
    294 	avl_destroy(&cache->uid2sid.tree);
    295 	avl_create(&cache->uid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
    296 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
    297 	cache->uid2sid.purge_time = 0;
    298 	cache->uid2sid.head.flink = &cache->uid2sid.head;
    299 	cache->uid2sid.head.blink = &cache->uid2sid.head;
    300 	mutex_exit(&cache->uid2sid.mutex);
    301 
    302 
    303 	mutex_enter(&cache->gid2sid.mutex);
    304 	cookie = NULL;
    305 	while ((pid2sid = avl_destroy_nodes(&cache->gid2sid.tree, &cookie))
    306 	    != NULL) {
    307 		kmem_free(pid2sid, sizeof (pid2sid_t));
    308 	}
    309 	avl_destroy(&cache->gid2sid.tree);
    310 	avl_create(&cache->gid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
    311 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
    312 	cache->gid2sid.purge_time = 0;
    313 	cache->gid2sid.head.flink = &cache->gid2sid.head;
    314 	cache->gid2sid.head.blink = &cache->gid2sid.head;
    315 	mutex_exit(&cache->gid2sid.mutex);
    316 }
    317 
    318 
    319 int
    320 kidmap_cache_lookup_uidbysid(idmap_cache_t *cache, const char *sid_prefix,
    321 			uint32_t rid, uid_t *uid)
    322 {
    323 	sid2pid_t	entry;
    324 	sid2pid_t	*result;
    325 	avl_index_t	where;
    326 	int		status = IDMAP_ERR_NOMAPPING;
    327 	time_t		now = gethrestime_sec();
    328 
    329 	entry.sid_prefix = sid_prefix;
    330 	entry.rid = rid;
    331 
    332 	mutex_enter(&cache->sid2pid.mutex);
    333 
    334 	result = avl_find(&cache->sid2pid.tree, &entry, &where);
    335 	if (result != NULL) {
    336 		list_move(&cache->sid2pid.head, result);
    337 		if (result->uid != UNDEF_UID && result->uid_ttl > now) {
    338 			*uid = result->uid;
    339 			status = IDMAP_SUCCESS;
    340 		}
    341 	}
    342 
    343 	mutex_exit(&cache->sid2pid.mutex);
    344 
    345 	return (status);
    346 }
    347 
    348 
    349 int
    350 kidmap_cache_lookup_gidbysid(idmap_cache_t *cache, const char *sid_prefix,
    351 			uint32_t rid, gid_t *gid)
    352 {
    353 	sid2pid_t	entry;
    354 	sid2pid_t	*result;
    355 	avl_index_t	where;
    356 	int		status = IDMAP_ERR_NOMAPPING;
    357 	time_t		now = gethrestime_sec();
    358 
    359 	entry.sid_prefix = sid_prefix;
    360 	entry.rid = rid;
    361 
    362 	mutex_enter(&cache->sid2pid.mutex);
    363 
    364 	result = avl_find(&cache->sid2pid.tree, &entry, &where);
    365 	if (result != NULL) {
    366 		list_move(&cache->sid2pid.head, result);
    367 		if (result->gid != UNDEF_GID && result->gid_ttl > now) {
    368 			*gid = result->gid;
    369 			status = IDMAP_SUCCESS;
    370 		}
    371 	}
    372 
    373 	mutex_exit(&cache->sid2pid.mutex);
    374 
    375 	return (status);
    376 }
    377 
    378 
    379 int
    380 kidmap_cache_lookup_pidbysid(idmap_cache_t *cache, const char *sid_prefix,
    381 			uint32_t rid, uid_t *pid, int *is_user)
    382 {
    383 	sid2pid_t	entry;
    384 	sid2pid_t	*result;
    385 	avl_index_t	where;
    386 	int		status = IDMAP_ERR_NOMAPPING;
    387 	time_t		now = gethrestime_sec();
    388 
    389 	entry.sid_prefix = sid_prefix;
    390 	entry.rid = rid;
    391 
    392 	mutex_enter(&cache->sid2pid.mutex);
    393 
    394 	result = avl_find(&cache->sid2pid.tree, &entry, &where);
    395 	if (result != NULL) {
    396 		list_move(&cache->sid2pid.head, result);
    397 		if (result->is_user != UNDEF_ISUSER) {
    398 			if (result->is_user && result->uid_ttl > now) {
    399 				*pid = result->uid;
    400 				*is_user = result->is_user;
    401 				status = IDMAP_SUCCESS;
    402 			} else if (!result->is_user && result->gid_ttl > now) {
    403 				*pid = result->gid;
    404 				*is_user = result->is_user;
    405 				status = IDMAP_SUCCESS;
    406 			}
    407 		}
    408 	}
    409 
    410 	mutex_exit(&cache->sid2pid.mutex);
    411 
    412 	return (status);
    413 }
    414 
    415 
    416 
    417 int
    418 kidmap_cache_lookup_sidbyuid(idmap_cache_t *cache, const char **sid_prefix,
    419 			uint32_t *rid, uid_t uid)
    420 {
    421 	pid2sid_t	entry;
    422 	pid2sid_t	*result;
    423 	avl_index_t	where;
    424 	int		status = IDMAP_ERR_NOMAPPING;
    425 	time_t		now = gethrestime_sec();
    426 
    427 	entry.pid = uid;
    428 
    429 	mutex_enter(&cache->uid2sid.mutex);
    430 
    431 	result = avl_find(&cache->uid2sid.tree, &entry, &where);
    432 	if (result != NULL) {
    433 		list_move(&cache->uid2sid.head, result);
    434 		if (result->ttl > now) {
    435 			*sid_prefix = result->sid_prefix;
    436 			*rid = result->rid;
    437 			status = IDMAP_SUCCESS;
    438 		}
    439 	}
    440 
    441 	mutex_exit(&cache->uid2sid.mutex);
    442 
    443 	return (status);
    444 }
    445 
    446 
    447 int
    448 kidmap_cache_lookup_sidbygid(idmap_cache_t *cache, const char **sid_prefix,
    449 			uint32_t *rid, gid_t gid)
    450 {
    451 	pid2sid_t	entry;
    452 	pid2sid_t	*result;
    453 	avl_index_t	where;
    454 	int		status = IDMAP_ERR_NOMAPPING;
    455 	time_t		now = gethrestime_sec();
    456 
    457 	entry.pid = gid;
    458 
    459 	mutex_enter(&cache->gid2sid.mutex);
    460 
    461 	result = avl_find(&cache->gid2sid.tree, &entry, &where);
    462 	if (result != NULL) {
    463 		list_move(&cache->gid2sid.head, result);
    464 		if (result->ttl > now) {
    465 			*sid_prefix = result->sid_prefix;
    466 			*rid = result->rid;
    467 			status = IDMAP_SUCCESS;
    468 		}
    469 	}
    470 
    471 	mutex_exit(&cache->gid2sid.mutex);
    472 
    473 	return (status);
    474 }
    475 
    476 
    477 void
    478 kidmap_cache_add_sid2uid(idmap_cache_t *cache, const char *sid_prefix,
    479 			uint32_t rid, uid_t uid, int direction)
    480 
    481 {
    482 	avl_index_t	where;
    483 	time_t		ttl = CACHE_TTL + gethrestime_sec();
    484 
    485 
    486 	if (direction == IDMAP_DIRECTION_BI ||
    487 	    direction == IDMAP_DIRECTION_W2U) {
    488 		sid2pid_t	find;
    489 		sid2pid_t	*result;
    490 		sid2pid_t	*new;
    491 
    492 		find.sid_prefix = sid_prefix;
    493 		find.rid = rid;
    494 
    495 		mutex_enter(&cache->sid2pid.mutex);
    496 
    497 		result = avl_find(&cache->sid2pid.tree, &find, &where);
    498 		if (result) {
    499 			if (result->uid == UNDEF_UID)
    500 				cache->sid2pid.uid_num++;
    501 			result->uid = uid;
    502 			result->uid_ttl = ttl;
    503 		} else {
    504 			new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
    505 			new->sid_prefix = sid_prefix;
    506 			new->rid = rid;
    507 			new->uid = uid;
    508 			new->uid_ttl = ttl;
    509 			new->gid = UNDEF_GID;
    510 			new->gid_ttl = 0;
    511 			new->is_user = UNDEF_ISUSER; /* Unknown */
    512 			cache->sid2pid.uid_num++;
    513 
    514 			list_insert(&cache->sid2pid.head, new);
    515 			avl_insert(&cache->sid2pid.tree, new, where);
    516 		}
    517 
    518 		if ((avl_numnodes(&cache->sid2pid.tree) >
    519 		    CACHE_PID_TRIGGER_SIZE) &&
    520 		    (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
    521 		    gethrestime_sec()))
    522 			kidmap_purge_sid2pid_cache(&cache->sid2pid,
    523 			    CACHE_PID_TRIGGER_SIZE);
    524 
    525 		mutex_exit(&cache->sid2pid.mutex);
    526 	}
    527 
    528 	if (direction == IDMAP_DIRECTION_BI ||
    529 	    direction == IDMAP_DIRECTION_U2W) {
    530 		pid2sid_t	find;
    531 		pid2sid_t	*result;
    532 		pid2sid_t	*new;
    533 
    534 		find.pid = uid;
    535 
    536 		mutex_enter(&cache->uid2sid.mutex);
    537 
    538 		result = avl_find(&cache->uid2sid.tree, &find, &where);
    539 		if (result) {
    540 			result->sid_prefix = sid_prefix;
    541 			result->rid = rid;
    542 			result->ttl = ttl;
    543 		} else {
    544 			new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
    545 			new->sid_prefix = sid_prefix;
    546 			new->rid = rid;
    547 			new->pid = uid;
    548 			new->ttl = ttl;
    549 
    550 			list_insert(&cache->uid2sid.head, new);
    551 			avl_insert(&cache->uid2sid.tree, new, where);
    552 		}
    553 
    554 		if ((avl_numnodes(&cache->uid2sid.tree) >
    555 		    CACHE_UID_TRIGGER_SIZE) &&
    556 		    (cache->uid2sid.purge_time + CACHE_PURGE_INTERVAL <
    557 		    gethrestime_sec()))
    558 			kidmap_purge_pid2sid_cache(&cache->uid2sid,
    559 			    CACHE_UID_TRIGGER_SIZE);
    560 
    561 		mutex_exit(&cache->uid2sid.mutex);
    562 	}
    563 }
    564 
    565 
    566 
    567 void
    568 kidmap_cache_add_sid2gid(idmap_cache_t *cache, const char *sid_prefix,
    569 			uint32_t rid, gid_t gid, int direction)
    570 {
    571 	avl_index_t	where;
    572 	time_t		ttl = CACHE_TTL + gethrestime_sec();
    573 
    574 
    575 	if (direction == IDMAP_DIRECTION_BI ||
    576 	    direction == IDMAP_DIRECTION_W2U) {
    577 		sid2pid_t	find;
    578 		sid2pid_t	*result;
    579 		sid2pid_t	*new;
    580 
    581 		find.sid_prefix = sid_prefix;
    582 		find.rid = rid;
    583 
    584 		mutex_enter(&cache->sid2pid.mutex);
    585 
    586 		result = avl_find(&cache->sid2pid.tree, &find, &where);
    587 		if (result) {
    588 			if (result->gid == UNDEF_GID)
    589 				cache->sid2pid.gid_num++;
    590 			result->gid = gid;
    591 			result->gid_ttl = ttl;
    592 		} else {
    593 			new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
    594 			new->sid_prefix = sid_prefix;
    595 			new->rid = rid;
    596 			new->uid = UNDEF_UID;
    597 			new->uid_ttl = 0;
    598 			new->gid = gid;
    599 			new->gid_ttl = ttl;
    600 			new->is_user = UNDEF_ISUSER; /* Unknown */
    601 			cache->sid2pid.gid_num++;
    602 
    603 			list_insert(&cache->sid2pid.head, new);
    604 			avl_insert(&cache->sid2pid.tree, new, where);
    605 		}
    606 
    607 		if ((avl_numnodes(&cache->sid2pid.tree) >
    608 		    CACHE_PID_TRIGGER_SIZE) &&
    609 		    (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
    610 		    gethrestime_sec()))
    611 			kidmap_purge_sid2pid_cache(&cache->sid2pid,
    612 			    CACHE_PID_TRIGGER_SIZE);
    613 
    614 		mutex_exit(&cache->sid2pid.mutex);
    615 	}
    616 
    617 	if (direction == IDMAP_DIRECTION_BI ||
    618 	    direction == IDMAP_DIRECTION_U2W) {
    619 		pid2sid_t	find;
    620 		pid2sid_t	*result;
    621 		pid2sid_t	*new;
    622 
    623 		find.pid = gid;
    624 
    625 		mutex_enter(&cache->gid2sid.mutex);
    626 
    627 		result = avl_find(&cache->gid2sid.tree, &find, &where);
    628 		if (result) {
    629 			result->sid_prefix = sid_prefix;
    630 			result->rid = rid;
    631 			result->ttl = ttl;
    632 		} else {
    633 			new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
    634 			new->sid_prefix = sid_prefix;
    635 			new->rid = rid;
    636 			new->pid = gid;
    637 			new->ttl = ttl;
    638 
    639 			list_insert(&cache->gid2sid.head, new);
    640 			avl_insert(&cache->gid2sid.tree, new, where);
    641 		}
    642 
    643 		if ((avl_numnodes(&cache->gid2sid.tree) >
    644 		    CACHE_GID_TRIGGER_SIZE) &&
    645 		    (cache->gid2sid.purge_time + CACHE_PURGE_INTERVAL <
    646 		    gethrestime_sec()))
    647 			kidmap_purge_pid2sid_cache(&cache->gid2sid,
    648 			    CACHE_GID_TRIGGER_SIZE);
    649 
    650 		mutex_exit(&cache->gid2sid.mutex);
    651 	}
    652 }
    653 
    654 
    655 void
    656 kidmap_cache_add_sid2pid(idmap_cache_t *cache, const char *sid_prefix,
    657 			uint32_t rid, uid_t pid, int is_user, int direction)
    658 {
    659 	avl_index_t	where;
    660 	time_t		ttl = CACHE_TTL + gethrestime_sec();
    661 
    662 
    663 	if (direction == IDMAP_DIRECTION_BI ||
    664 	    direction == IDMAP_DIRECTION_W2U) {
    665 		sid2pid_t	find;
    666 		sid2pid_t	*result;
    667 		sid2pid_t	*new;
    668 
    669 		find.sid_prefix = sid_prefix;
    670 		find.rid = rid;
    671 
    672 		mutex_enter(&cache->sid2pid.mutex);
    673 
    674 		result = avl_find(&cache->sid2pid.tree, &find, &where);
    675 		if (result) {
    676 			if (result->is_user == UNDEF_ISUSER)
    677 				cache->sid2pid.pid_num++;
    678 			result->is_user = is_user;
    679 			if (is_user) {
    680 				if (result->uid == UNDEF_UID)
    681 					cache->sid2pid.uid_num++;
    682 				result->uid = pid;
    683 				result->uid_ttl = ttl;
    684 			} else {
    685 				if (result->gid == UNDEF_GID)
    686 					cache->sid2pid.gid_num++;
    687 				result->gid = pid;
    688 				result->gid_ttl = ttl;
    689 			}
    690 		} else {
    691 			new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
    692 			new->sid_prefix = sid_prefix;
    693 			new->rid = rid;
    694 			new->is_user = is_user;
    695 			if (is_user) {
    696 				new->uid = pid;
    697 				new->uid_ttl = ttl;
    698 				new->gid = UNDEF_GID;
    699 				new->gid_ttl = 0;
    700 				cache->sid2pid.uid_num++;
    701 			} else {
    702 				new->uid = UNDEF_UID;
    703 				new->uid_ttl = 0;
    704 				new->gid = pid;
    705 				new->gid_ttl = ttl;
    706 				cache->sid2pid.gid_num++;
    707 			}
    708 			cache->sid2pid.pid_num++;
    709 
    710 			list_insert(&cache->sid2pid.head, new);
    711 			avl_insert(&cache->sid2pid.tree, new, where);
    712 		}
    713 
    714 		if ((avl_numnodes(&cache->sid2pid.tree) >
    715 		    CACHE_PID_TRIGGER_SIZE) &&
    716 		    (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
    717 		    gethrestime_sec()))
    718 			kidmap_purge_sid2pid_cache(&cache->sid2pid,
    719 			    CACHE_PID_TRIGGER_SIZE);
    720 
    721 		mutex_exit(&cache->sid2pid.mutex);
    722 	}
    723 
    724 	if (direction == IDMAP_DIRECTION_BI ||
    725 	    direction == IDMAP_DIRECTION_U2W) {
    726 		pid2sid_t	find;
    727 		pid2sid_t	*result;
    728 		pid2sid_t	*new;
    729 
    730 		find.pid = pid;
    731 		if (is_user) {
    732 			mutex_enter(&cache->uid2sid.mutex);
    733 
    734 			result = avl_find(&cache->uid2sid.tree, &find, &where);
    735 			if (result) {
    736 				result->sid_prefix = sid_prefix;
    737 				result->rid = rid;
    738 				result->ttl = ttl;
    739 			} else {
    740 				new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
    741 				new->sid_prefix = sid_prefix;
    742 				new->rid = rid;
    743 				new->pid = pid;
    744 				new->ttl = ttl;
    745 
    746 				list_insert(&cache->uid2sid.head, new);
    747 				avl_insert(&cache->uid2sid.tree, new, where);
    748 			}
    749 
    750 			if ((avl_numnodes(&cache->uid2sid.tree) >
    751 			    CACHE_UID_TRIGGER_SIZE) &&
    752 			    (cache->uid2sid.purge_time +
    753 			    CACHE_PURGE_INTERVAL <
    754 			    gethrestime_sec()))
    755 				kidmap_purge_pid2sid_cache(&cache->uid2sid,
    756 				    CACHE_UID_TRIGGER_SIZE);
    757 
    758 			mutex_exit(&cache->uid2sid.mutex);
    759 		} else {
    760 			mutex_enter(&cache->gid2sid.mutex);
    761 
    762 			result = avl_find(&cache->gid2sid.tree, &find, &where);
    763 			if (result) {
    764 				result->sid_prefix = sid_prefix;
    765 				result->rid = rid;
    766 				result->ttl = ttl;
    767 			} else {
    768 				new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
    769 				new->sid_prefix = sid_prefix;
    770 				new->rid = rid;
    771 				new->pid = pid;
    772 				new->ttl = ttl;
    773 
    774 				list_insert(&cache->gid2sid.head, new);
    775 				avl_insert(&cache->gid2sid.tree, new, where);
    776 			}
    777 
    778 			if ((avl_numnodes(&cache->gid2sid.tree) >
    779 			    CACHE_GID_TRIGGER_SIZE) &&
    780 			    (cache->gid2sid.purge_time +
    781 			    CACHE_PURGE_INTERVAL < gethrestime_sec()))
    782 				kidmap_purge_pid2sid_cache(&cache->gid2sid,
    783 				    CACHE_GID_TRIGGER_SIZE);
    784 
    785 			mutex_exit(&cache->gid2sid.mutex);
    786 		}
    787 	}
    788 }
    789 
    790 
    791 
    792 
    793 
    794 static void
    795 kidmap_purge_sid2pid_cache(idmap_sid2pid_cache_t *cache, size_t limit)
    796 {
    797 	time_t		now = gethrestime_sec();
    798 	sid2pid_t	*item;
    799 
    800 	while (avl_numnodes(&cache->tree) > limit) {
    801 		/* Remove least recently used */
    802 		item = cache->head.blink;
    803 		list_remove(item);
    804 		avl_remove(&cache->tree, item);
    805 		if (item->uid != UNDEF_UID)
    806 			cache->uid_num--;
    807 		if (item->gid != UNDEF_GID)
    808 			cache->gid_num--;
    809 		if (item->is_user != UNDEF_ISUSER)
    810 			cache->pid_num--;
    811 		kmem_free(item, sizeof (sid2pid_t));
    812 	}
    813 	cache->purge_time = now;
    814 }
    815 
    816 
    817 static void
    818 kidmap_purge_pid2sid_cache(idmap_pid2sid_cache_t *cache, size_t limit)
    819 {
    820 	time_t		now = gethrestime_sec();
    821 	pid2sid_t	*item;
    822 
    823 	while (avl_numnodes(&cache->tree) > limit) {
    824 		/* Remove least recently used */
    825 		item = cache->head.blink;
    826 		list_remove(item);
    827 		avl_remove(&cache->tree, item);
    828 		kmem_free(item, sizeof (pid2sid_t));
    829 	}
    830 	cache->purge_time = now;
    831 }
    832 
    833 
    834 void
    835 kidmap_sid_prefix_store_init(void)
    836 {
    837 	kidmap_sid_prefix_store = (struct sid_prefix_store *)
    838 	    space_fetch("SUNW,idmap_sid_prefix");
    839 	if (kidmap_sid_prefix_store == NULL) {
    840 		kidmap_sid_prefix_store = kmem_alloc(
    841 		    sizeof (struct sid_prefix_store), KM_SLEEP);
    842 		rw_init(&kidmap_sid_prefix_store->lock, NULL, RW_DRIVER, NULL);
    843 		avl_create(&kidmap_sid_prefix_store->tree,
    844 		    (avl_comp_fn)kidmap_compare_sid_prefix,
    845 		    sizeof (sid_prefix_node_t),
    846 		    offsetof(sid_prefix_node_t, avl_link));
    847 		(void) space_store("SUNW,idmap_sid_prefix",
    848 		    (uintptr_t)kidmap_sid_prefix_store);
    849 	} else {
    850 		/*
    851 		 * The AVL comparison function must be re-initialised on
    852 		 * re-load because may not be loaded into the same
    853 		 * address space.
    854 		 */
    855 		kidmap_sid_prefix_store->tree.avl_compar =
    856 		    (avl_comp_fn)kidmap_compare_sid_prefix;
    857 	}
    858 }
    859 
    860 
    861 const char *
    862 kidmap_find_sid_prefix(const char *sid_prefix) {
    863 	sid_prefix_node_t 	find;
    864 	sid_prefix_node_t	*result;
    865 	sid_prefix_node_t 	*new;
    866 	avl_index_t		where;
    867 
    868 	if (sid_prefix == NULL || *sid_prefix == '\0')
    869 		return (NULL);
    870 
    871 	find.sid_prefix = sid_prefix;
    872 
    873 	rw_enter(&kidmap_sid_prefix_store->lock, RW_READER);
    874 
    875 	result = avl_find(&kidmap_sid_prefix_store->tree, &find, &where);
    876 
    877 	if (result) {
    878 		rw_exit(&kidmap_sid_prefix_store->lock);
    879 		return (result->sid_prefix);
    880 	}
    881 
    882 	if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
    883 		/*
    884 		 * Could not upgrade lock so release lock
    885 		 * and acquire the write lock
    886 		 */
    887 		rw_exit(&kidmap_sid_prefix_store->lock);
    888 		rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
    889 
    890 		result = avl_find(&kidmap_sid_prefix_store->tree,
    891 			&find, &where);
    892 		if (result) {
    893 			rw_exit(&kidmap_sid_prefix_store->lock);
    894 			return (result->sid_prefix);
    895 		}
    896 	}
    897 
    898 	new = kmem_alloc(sizeof (sid_prefix_node_t), KM_SLEEP);
    899 	new->sid_prefix = kidmap_strdup(sid_prefix);
    900 	avl_insert(&kidmap_sid_prefix_store->tree, new, where);
    901 	rw_exit(&kidmap_sid_prefix_store->lock);
    902 
    903 	return (new->sid_prefix);
    904 }
    905