xref: /illumos-gate/usr/src/lib/libidmap/common/idmap_cache.c (revision 6446bd46ed1b4e9f69da153665f82181ccaedad5)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright 2020 Nexenta by DDN, Inc. All rights reserved.
29  */
30 
31 /*
32  * Windows to Solaris Identity Mapping
33  * This module provides the libidmap idmap_cache.
34  */
35 
36 
37 #include <sys/types.h>
38 #include <sys/avl.h>
39 #include <assert.h>
40 #include <pthread.h>
41 #include <strings.h>
42 #include <sys/idmap.h>
43 #include <stddef.h>
44 #include <stdlib.h>
45 #include <rpcsvc/idmap_prot.h>
46 #include "idmap_cache.h"
47 
48 
49 /*
50  * Internal definitions and functions
51  */
52 
53 #define	CACHE_UID_TRIGGER_SIZE	4096
54 #define	CACHE_GID_TRIGGER_SIZE	2048
55 #define	CACHE_UID_GID_TRIGGER_SIZE \
56 	(CACHE_UID_TRIGGER_SIZE + CACHE_GID_TRIGGER_SIZE)
57 
58 
59 #define	UNDEF_UID	((uid_t)-1)
60 #define	UNDEF_GID	((gid_t)-1)
61 #define	UNDEF_ISUSER	(-1)
62 
63 #define	CACHE_PURGE_INTERVAL	(60 * 3)
64 #define	CACHE_TTL		(60 * 10)
65 
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 typedef struct sid2uid_gid {
95 	avl_node_t		avl_link;
96 	struct sid2uid_gid	*flink;
97 	struct sid2uid_gid	*blink;
98 	const char		*sid_prefix;
99 	idmap_rid_t		rid;
100 	uid_t			uid;
101 	time_t			uid_ttl;
102 	gid_t			gid;
103 	time_t			gid_ttl;
104 	int			is_user;
105 } sid2uid_gid_t;
106 
107 
108 typedef struct pid2sid_winname {
109 	avl_node_t		avl_link;
110 	struct pid2sid_winname	*flink;
111 	struct pid2sid_winname	*blink;
112 	uid_t			pid;
113 	const char		*sid_prefix;
114 	idmap_rid_t		rid;
115 	time_t			sid_ttl;
116 	const char		*winname;
117 	const char		*windomain;
118 	time_t			winname_ttl;
119 } pid2sid_winname_t;
120 
121 
122 typedef struct winname2uid_gid {
123 	avl_node_t		avl_link;
124 	struct winname2uid_gid	*flink;
125 	struct winname2uid_gid	*blink;
126 	const char		*winname;
127 	const char		*windomain;
128 	uid_t			uid;
129 	time_t			uid_ttl;
130 	gid_t			gid;
131 	time_t			gid_ttl;
132 } winname2uid_gid_t;
133 
134 
135 typedef struct sid2uid_gid_cache {
136 	avl_tree_t		tree;
137 	pthread_mutex_t		mutex;
138 	sid2uid_gid_t		head;
139 	sid2uid_gid_t		*prev;
140 	time_t			purge_time;
141 	int			uid_num;
142 	int			gid_num;
143 	int			pid_num;
144 } sid2uid_gid_cache_t;
145 
146 
147 typedef struct pid2sid_winname_cache {
148 	avl_tree_t		tree;
149 	pthread_mutex_t		mutex;
150 	pid2sid_winname_t	head;
151 	pid2sid_winname_t	*prev;
152 	time_t			purge_time;
153 	int			sid_num;
154 	int			winname_num;
155 } pid2sid_winname_cache_t;
156 
157 
158 
159 typedef struct winname2uid_gid_cache {
160 	avl_tree_t		tree;
161 	pthread_mutex_t		mutex;
162 	winname2uid_gid_t	head;
163 	winname2uid_gid_t	*prev;
164 	time_t			purge_time;
165 	int			uid_num;
166 	int			gid_num;
167 } winname2uid_gid_cache_t;
168 
169 
170 typedef struct idmap_cache {
171 	sid2uid_gid_cache_t	sid2uid_gid;
172 	pid2sid_winname_cache_t	uid2sid_winname;
173 	pid2sid_winname_cache_t	gid2sid_winname;
174 	winname2uid_gid_cache_t	winname2uid_gid;
175 } idmap_cache_t;
176 
177 
178 
179 typedef int (*avl_comp_fn)(const void*, const void*);
180 
181 static void
182 idmap_purge_sid2uid_gid_cache(sid2uid_gid_cache_t *cache, size_t limit);
183 
184 static void
185 idmap_purge_pid2sid_winname_cache(pid2sid_winname_cache_t *cache, size_t limit);
186 
187 static void
188 idmap_purge_winname2uid_gid_cache(winname2uid_gid_cache_t *avl, size_t limit);
189 
190 /*
191  * Global structures
192  */
193 
194 static idmap_cache_t idmap_cache;
195 
196 
197 
198 
199 static int
200 idmap_compare_sid(const sid2uid_gid_t *entry1, const sid2uid_gid_t *entry2)
201 {
202 	int64_t comp = ((int64_t)entry2->rid) - ((int64_t)entry1->rid);
203 
204 	if (comp == 0)
205 		comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
206 
207 	if (comp < 0)
208 		comp = -1;
209 	else if (comp > 0)
210 		comp = 1;
211 
212 	return ((int)comp);
213 }
214 
215 
216 static int
217 idmap_compare_pid(const pid2sid_winname_t *entry1,
218     const pid2sid_winname_t *entry2)
219 {
220 	if (entry2->pid > entry1->pid)
221 		return (1);
222 	if (entry2->pid < entry1->pid)
223 		return (-1);
224 	return (0);
225 }
226 
227 
228 static int
229 idmap_compare_winname(const winname2uid_gid_t *entry1,
230     const winname2uid_gid_t *entry2)
231 {
232 	int comp;
233 
234 	comp = strcasecmp(entry2->winname, entry1->winname);
235 	if (comp == 0) {
236 		if (entry2->windomain == NULL && entry1->windomain == NULL)
237 			return (0);
238 		if (entry1->windomain == NULL)
239 			return (1);
240 		if (entry2->windomain == NULL)
241 			return (-1);
242 
243 		comp = strcasecmp(entry2->windomain, entry1->windomain);
244 	}
245 
246 	if (comp < 0)
247 		comp = -1;
248 	else if (comp > 0)
249 		comp = 1;
250 
251 	return (comp);
252 }
253 
254 /*
255  * Routine to update item
256  *
257  * Returns:	0 Success
258  *		-1 Error
259  */
260 static int
261 update_str(const char **item, const char *str)
262 {
263 	char *tmp;
264 
265 	if (*item != NULL && str != NULL) {
266 		if (strcmp(*item, str) != 0) {
267 			if ((tmp = strdup(str)) == NULL)
268 				return (-1);
269 			free((char *)*item);
270 			*item = tmp;
271 		}
272 	} else if (str != NULL) {
273 		/* *item is NULL */
274 		if ((*item = strdup(str)) == NULL)
275 			return (-1);
276 	} else if (*item != NULL) {
277 		/* str is NULL */
278 		free((char *)*item);
279 		*item = NULL;
280 	}
281 
282 	return (0);
283 }
284 
285 /*
286  * The Cache is initialized on loading libidmap.so
287  */
288 #pragma	init(idmap_cache_create)
289 
290 void
291 idmap_cache_create(void)
292 {
293 	avl_create(&idmap_cache.sid2uid_gid.tree,
294 	    (avl_comp_fn)idmap_compare_sid, sizeof (sid2uid_gid_t),
295 	    offsetof(sid2uid_gid_t, avl_link));
296 	(void) pthread_mutex_init(&idmap_cache.sid2uid_gid.mutex, NULL);
297 	idmap_cache.sid2uid_gid.head.flink = &idmap_cache.sid2uid_gid.head;
298 	idmap_cache.sid2uid_gid.head.blink = &idmap_cache.sid2uid_gid.head;
299 	idmap_cache.sid2uid_gid.prev = NULL;
300 	idmap_cache.sid2uid_gid.purge_time = 0;
301 	idmap_cache.sid2uid_gid.uid_num = 0;
302 	idmap_cache.sid2uid_gid.gid_num = 0;
303 	idmap_cache.sid2uid_gid.pid_num = 0;
304 
305 	avl_create(&idmap_cache.uid2sid_winname.tree,
306 	    (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t),
307 	    offsetof(pid2sid_winname_t, avl_link));
308 	(void) pthread_mutex_init(&idmap_cache.uid2sid_winname.mutex, NULL);
309 	idmap_cache.uid2sid_winname.head.flink =
310 	    &idmap_cache.uid2sid_winname.head;
311 	idmap_cache.uid2sid_winname.head.blink =
312 	    &idmap_cache.uid2sid_winname.head;
313 	idmap_cache.uid2sid_winname.prev = NULL;
314 	idmap_cache.uid2sid_winname.purge_time = 0;
315 	idmap_cache.uid2sid_winname.sid_num = 0;
316 	idmap_cache.uid2sid_winname.winname_num = 0;
317 
318 	avl_create(&idmap_cache.gid2sid_winname.tree,
319 	    (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t),
320 	    offsetof(pid2sid_winname_t, avl_link));
321 	(void) pthread_mutex_init(&idmap_cache.gid2sid_winname.mutex, NULL);
322 	idmap_cache.gid2sid_winname.head.flink =
323 	    &idmap_cache.gid2sid_winname.head;
324 	idmap_cache.gid2sid_winname.head.blink =
325 	    &idmap_cache.gid2sid_winname.head;
326 	idmap_cache.gid2sid_winname.prev = NULL;
327 	idmap_cache.gid2sid_winname.purge_time = 0;
328 	idmap_cache.gid2sid_winname.sid_num = 0;
329 	idmap_cache.gid2sid_winname.winname_num = 0;
330 
331 	avl_create(&idmap_cache.winname2uid_gid.tree,
332 	    (avl_comp_fn)idmap_compare_winname, sizeof (winname2uid_gid_t),
333 	    offsetof(winname2uid_gid_t, avl_link));
334 	(void) pthread_mutex_init(&idmap_cache.winname2uid_gid.mutex, NULL);
335 	idmap_cache.winname2uid_gid.head.flink =
336 	    &idmap_cache.winname2uid_gid.head;
337 	idmap_cache.winname2uid_gid.head.blink =
338 	    &idmap_cache.winname2uid_gid.head;
339 	idmap_cache.winname2uid_gid.prev = NULL;
340 	idmap_cache.winname2uid_gid.purge_time = 0;
341 	idmap_cache.winname2uid_gid.uid_num = 0;
342 	idmap_cache.winname2uid_gid.gid_num = 0;
343 }
344 
345 
346 void
347 idmap_cache_purge(void)
348 {
349 	sid2uid_gid_t		*sid2uid_gid;
350 	pid2sid_winname_t	*uid2sid_winname;
351 	pid2sid_winname_t	*gid2sid_winname;
352 	winname2uid_gid_t	*winname2uid_gid;
353 	void			*cookie;
354 
355 	(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
356 	cookie = NULL;
357 	while ((sid2uid_gid = avl_destroy_nodes(
358 	    &idmap_cache.sid2uid_gid.tree, &cookie)) != NULL) {
359 		free((char *)sid2uid_gid->sid_prefix);
360 		free(sid2uid_gid);
361 	}
362 	avl_destroy(&idmap_cache.sid2uid_gid.tree);
363 	avl_create(&idmap_cache.sid2uid_gid.tree,
364 	    (avl_comp_fn)idmap_compare_sid, sizeof (sid2uid_gid_t),
365 	    offsetof(sid2uid_gid_t, avl_link));
366 	idmap_cache.sid2uid_gid.head.flink = &idmap_cache.sid2uid_gid.head;
367 	idmap_cache.sid2uid_gid.head.blink = &idmap_cache.sid2uid_gid.head;
368 	idmap_cache.sid2uid_gid.prev = NULL;
369 	idmap_cache.sid2uid_gid.purge_time = 0;
370 	idmap_cache.sid2uid_gid.uid_num = 0;
371 	idmap_cache.sid2uid_gid.gid_num = 0;
372 	idmap_cache.sid2uid_gid.pid_num = 0;
373 	(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
374 
375 
376 	(void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex);
377 	cookie = NULL;
378 	while ((uid2sid_winname = avl_destroy_nodes(
379 	    &idmap_cache.uid2sid_winname.tree, &cookie)) != NULL) {
380 		free((char *)uid2sid_winname->sid_prefix);
381 		free((char *)uid2sid_winname->winname);
382 		if (uid2sid_winname->windomain != NULL)
383 			free((char *)uid2sid_winname->windomain);
384 		free(uid2sid_winname);
385 	}
386 	avl_destroy(&idmap_cache.uid2sid_winname.tree);
387 	avl_create(&idmap_cache.uid2sid_winname.tree,
388 	    (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t),
389 	    offsetof(pid2sid_winname_t, avl_link));
390 	idmap_cache.uid2sid_winname.head.flink =
391 	    &idmap_cache.uid2sid_winname.head;
392 	idmap_cache.uid2sid_winname.head.blink =
393 	    &idmap_cache.uid2sid_winname.head;
394 	idmap_cache.uid2sid_winname.prev = NULL;
395 	idmap_cache.uid2sid_winname.purge_time = 0;
396 	idmap_cache.uid2sid_winname.sid_num = 0;
397 	idmap_cache.uid2sid_winname.winname_num = 0;
398 	(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
399 
400 
401 	(void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex);
402 	cookie = NULL;
403 	while ((gid2sid_winname = avl_destroy_nodes(
404 	    &idmap_cache.gid2sid_winname.tree, &cookie)) != NULL) {
405 		free((char *)gid2sid_winname->sid_prefix);
406 		free((char *)gid2sid_winname->winname);
407 		if (gid2sid_winname->windomain != NULL)
408 			free((char *)gid2sid_winname->windomain);
409 		free(gid2sid_winname);
410 	}
411 	avl_destroy(&idmap_cache.gid2sid_winname.tree);
412 	avl_create(&idmap_cache.gid2sid_winname.tree,
413 	    (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t),
414 	    offsetof(pid2sid_winname_t, avl_link));
415 	idmap_cache.gid2sid_winname.head.flink =
416 	    &idmap_cache.gid2sid_winname.head;
417 	idmap_cache.gid2sid_winname.head.blink =
418 	    &idmap_cache.gid2sid_winname.head;
419 	idmap_cache.gid2sid_winname.prev = NULL;
420 	idmap_cache.gid2sid_winname.purge_time = 0;
421 	idmap_cache.gid2sid_winname.sid_num = 0;
422 	idmap_cache.gid2sid_winname.winname_num = 0;
423 	(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
424 
425 	(void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex);
426 	cookie = NULL;
427 	while ((winname2uid_gid = avl_destroy_nodes(
428 	    &idmap_cache.winname2uid_gid.tree, &cookie)) != NULL) {
429 		free((char *)winname2uid_gid->winname);
430 		if (winname2uid_gid->windomain)
431 			free((char *)winname2uid_gid->windomain);
432 		free(winname2uid_gid);
433 	}
434 	avl_destroy(&idmap_cache.winname2uid_gid.tree);
435 	avl_create(&idmap_cache.winname2uid_gid.tree,
436 	    (avl_comp_fn)idmap_compare_winname, sizeof (winname2uid_gid_t),
437 	    offsetof(winname2uid_gid_t, avl_link));
438 	idmap_cache.winname2uid_gid.head.flink =
439 	    &idmap_cache.winname2uid_gid.head;
440 	idmap_cache.winname2uid_gid.head.blink =
441 	    &idmap_cache.winname2uid_gid.head;
442 	idmap_cache.winname2uid_gid.prev = NULL;
443 	idmap_cache.winname2uid_gid.purge_time = 0;
444 	idmap_cache.winname2uid_gid.uid_num = 0;
445 	idmap_cache.winname2uid_gid.gid_num = 0;
446 	(void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex);
447 
448 }
449 
450 
451 void
452 idmap_cache_get_data(size_t *uidbysid, size_t *gidbysid,
453     size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid,
454     size_t *winnamebyuid, size_t *winnamebygid,
455     size_t *uidbywinname, size_t *gidbywinname)
456 {
457 	(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
458 	*uidbysid = idmap_cache.sid2uid_gid.uid_num;
459 	*gidbysid = idmap_cache.sid2uid_gid.gid_num;
460 	*pidbysid = idmap_cache.sid2uid_gid.pid_num;
461 	(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
462 
463 	(void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex);
464 	*sidbyuid = idmap_cache.uid2sid_winname.sid_num;
465 	*winnamebyuid = idmap_cache.uid2sid_winname.winname_num;
466 	(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
467 
468 	(void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex);
469 	*sidbygid = idmap_cache.gid2sid_winname.sid_num;
470 	*winnamebygid = idmap_cache.gid2sid_winname.winname_num;
471 	(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
472 
473 	(void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex);
474 	*uidbywinname = idmap_cache.winname2uid_gid.uid_num;
475 	*gidbywinname = idmap_cache.winname2uid_gid.gid_num;
476 	(void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex);
477 }
478 
479 
480 idmap_stat
481 idmap_cache_lookup_uidbysid(const char *sid_prefix,
482     idmap_rid_t rid, uid_t *uid)
483 {
484 	sid2uid_gid_t	entry;
485 	sid2uid_gid_t	*result;
486 	avl_index_t	where;
487 	int		status = IDMAP_ERR_NOMAPPING;
488 	time_t		now = time(NULL);
489 
490 	entry.sid_prefix = sid_prefix;
491 	entry.rid = rid;
492 
493 	(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
494 
495 	result = avl_find(&idmap_cache.sid2uid_gid.tree, &entry, &where);
496 	if (result != NULL) {
497 		list_move(&idmap_cache.sid2uid_gid.head, result);
498 		if (result->uid != UNDEF_UID && result->uid_ttl > now) {
499 			*uid = result->uid;
500 			status = IDMAP_SUCCESS;
501 		}
502 	}
503 
504 	(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
505 
506 	return (status);
507 }
508 
509 
510 
511 idmap_stat
512 idmap_cache_lookup_gidbysid(const char *sid_prefix,
513     idmap_rid_t rid, gid_t *gid)
514 {
515 	sid2uid_gid_t	entry;
516 	sid2uid_gid_t	*result;
517 	avl_index_t	where;
518 	int		status = IDMAP_ERR_NOMAPPING;
519 	time_t		now = time(NULL);
520 
521 	entry.sid_prefix = sid_prefix;
522 	entry.rid = rid;
523 
524 	(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
525 
526 	result = avl_find(&idmap_cache.sid2uid_gid.tree, &entry, &where);
527 	if (result != NULL) {
528 		list_move(&idmap_cache.sid2uid_gid.head, result);
529 		if (result->gid != UNDEF_GID && result->gid_ttl > now) {
530 			*gid = result->gid;
531 			status = IDMAP_SUCCESS;
532 		}
533 	}
534 
535 	(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
536 
537 	return (status);
538 }
539 
540 
541 
542 
543 idmap_stat
544 idmap_cache_lookup_pidbysid(const char *sid_prefix,
545     idmap_rid_t rid, uid_t *pid, int *is_user)
546 {
547 	sid2uid_gid_t	entry;
548 	sid2uid_gid_t	*result;
549 	avl_index_t	where;
550 	int		status = IDMAP_ERR_NOMAPPING;
551 	time_t		now = time(NULL);
552 
553 	entry.sid_prefix = sid_prefix;
554 	entry.rid = rid;
555 
556 	(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
557 
558 	result = avl_find(&idmap_cache.sid2uid_gid.tree, &entry, &where);
559 	if (result != NULL) {
560 		list_move(&idmap_cache.sid2uid_gid.head, result);
561 		if (result->is_user != UNDEF_ISUSER) {
562 			*is_user = result->is_user;
563 			if (result->is_user && result->uid_ttl > now) {
564 				*pid = result->uid;
565 				status = IDMAP_SUCCESS;
566 			} else if (!result->is_user && result->gid_ttl > now) {
567 				*pid = result->gid;
568 				status = IDMAP_SUCCESS;
569 			}
570 		}
571 	}
572 
573 	(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
574 
575 	return (status);
576 }
577 
578 
579 
580 idmap_stat
581 idmap_cache_lookup_sidbyuid(char **sid_prefix,
582     idmap_rid_t *rid, uid_t uid)
583 {
584 	pid2sid_winname_t	entry;
585 	pid2sid_winname_t	*result;
586 	avl_index_t	where;
587 	int		status = IDMAP_ERR_NOMAPPING;
588 	time_t		now = time(NULL);
589 
590 	entry.pid = uid;
591 
592 	(void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex);
593 
594 	result = avl_find(&idmap_cache.uid2sid_winname.tree, &entry, &where);
595 	if (result != NULL) {
596 		list_move(&idmap_cache.uid2sid_winname.head, result);
597 		if (result->sid_ttl > now) {
598 			*rid = result->rid;
599 			*sid_prefix = strdup(result->sid_prefix);
600 			if (*sid_prefix != NULL)
601 				status = IDMAP_SUCCESS;
602 			else
603 				status = IDMAP_ERR_MEMORY;
604 		}
605 	}
606 
607 	(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
608 
609 	return (status);
610 }
611 
612 idmap_stat
613 idmap_cache_lookup_sidbygid(char **sid_prefix,
614     idmap_rid_t *rid, gid_t gid)
615 {
616 	pid2sid_winname_t	entry;
617 	pid2sid_winname_t	*result;
618 	avl_index_t	where;
619 	int		status = IDMAP_ERR_NOMAPPING;
620 	time_t		now = time(NULL);
621 
622 	entry.pid = gid;
623 
624 	(void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex);
625 
626 	result = avl_find(&idmap_cache.gid2sid_winname.tree, &entry, &where);
627 	if (result != NULL) {
628 		list_move(&idmap_cache.gid2sid_winname.head, result);
629 		if (result->sid_ttl > now) {
630 			*rid = result->rid;
631 			*sid_prefix = strdup(result->sid_prefix);
632 			if (*sid_prefix != NULL)
633 				status = IDMAP_SUCCESS;
634 			else
635 				status = IDMAP_ERR_MEMORY;
636 		}
637 	}
638 
639 	(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
640 
641 	return (status);
642 }
643 
644 
645 idmap_stat
646 idmap_cache_lookup_winnamebyuid(char **name, char **domain, uid_t uid)
647 {
648 	pid2sid_winname_t	entry;
649 	pid2sid_winname_t	*result;
650 	avl_index_t	where;
651 	int		status = IDMAP_ERR_NOMAPPING;
652 	time_t		now = time(NULL);
653 
654 	entry.pid = uid;
655 
656 	(void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex);
657 
658 	result = avl_find(&idmap_cache.uid2sid_winname.tree, &entry, &where);
659 	if (result != NULL) {
660 		list_move(&idmap_cache.uid2sid_winname.head, result);
661 		if (result->winname_ttl > now) {
662 			*name = strdup(result->winname);
663 			if (*name != NULL) {
664 				if (domain != NULL) {
665 					if (result->windomain != NULL) {
666 						*domain =
667 						    strdup(result->windomain);
668 						if (*domain != NULL)
669 							status = IDMAP_SUCCESS;
670 						else
671 							status =
672 							    IDMAP_ERR_MEMORY;
673 					} else {
674 						*domain = NULL;
675 						status = IDMAP_SUCCESS;
676 					}
677 				} else
678 					status = IDMAP_SUCCESS;
679 			} else
680 				status = IDMAP_ERR_MEMORY;
681 		}
682 	}
683 
684 	(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
685 
686 	return (status);
687 }
688 
689 
690 idmap_stat
691 idmap_cache_lookup_winnamebygid(char **name, char **domain, gid_t gid)
692 {
693 	pid2sid_winname_t	entry;
694 	pid2sid_winname_t	*result;
695 	avl_index_t	where;
696 	int		status = IDMAP_ERR_NOMAPPING;
697 	time_t		now = time(NULL);
698 
699 	entry.pid = gid;
700 
701 	(void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex);
702 
703 	result = avl_find(&idmap_cache.gid2sid_winname.tree, &entry, &where);
704 	if (result != NULL) {
705 		list_move(&idmap_cache.gid2sid_winname.head, result);
706 		if (result->winname_ttl > now) {
707 			*name = strdup(result->winname);
708 			if (*name != NULL) {
709 				if (domain != NULL) {
710 					if (result->windomain != NULL) {
711 						*domain =
712 						    strdup(result->windomain);
713 						if (*domain != NULL)
714 							status = IDMAP_SUCCESS;
715 						else
716 							status =
717 							    IDMAP_ERR_MEMORY;
718 					} else {
719 						*domain = NULL;
720 						status = IDMAP_SUCCESS;
721 					}
722 				} else
723 					status = IDMAP_SUCCESS;
724 			} else
725 				status = IDMAP_ERR_MEMORY;
726 		}
727 	}
728 
729 	(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
730 
731 	return (status);
732 }
733 
734 
735 idmap_stat
736 idmap_cache_lookup_uidbywinname(const char *name, const char *domain,
737     uid_t *uid)
738 {
739 	winname2uid_gid_t	entry;
740 	winname2uid_gid_t	*result;
741 	avl_index_t	where;
742 	int		status = IDMAP_ERR_NOMAPPING;
743 	time_t		now = time(NULL);
744 
745 	entry.winname = name;
746 	entry.windomain = domain;
747 
748 	(void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex);
749 
750 	result = avl_find(&idmap_cache.winname2uid_gid.tree, &entry, &where);
751 	if (result != NULL) {
752 		list_move(&idmap_cache.winname2uid_gid.head, result);
753 		if (result->uid != UNDEF_UID && result->uid_ttl > now) {
754 			*uid = result->uid;
755 			status = IDMAP_SUCCESS;
756 		}
757 	}
758 
759 	(void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex);
760 
761 	return (status);
762 }
763 
764 
765 idmap_stat
766 idmap_cache_lookup_gidbywinname(const char *name, const char *domain,
767     gid_t *gid)
768 {
769 	winname2uid_gid_t	entry;
770 	winname2uid_gid_t	*result;
771 	avl_index_t	where;
772 	int		status = IDMAP_ERR_NOMAPPING;
773 	time_t		now = time(NULL);
774 
775 	entry.winname = name;
776 	entry.windomain = domain;
777 
778 	(void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex);
779 
780 	result = avl_find(&idmap_cache.winname2uid_gid.tree, &entry, &where);
781 	if (result != NULL) {
782 		list_move(&idmap_cache.winname2uid_gid.head, result);
783 		if (result->gid != UNDEF_GID && result->gid_ttl > now) {
784 			*gid = result->gid;
785 			status = IDMAP_SUCCESS;
786 		}
787 	}
788 
789 	(void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex);
790 
791 	return (status);
792 }
793 
794 
795 void
796 idmap_cache_add_sid2uid(const char *sid_prefix,
797     idmap_rid_t rid, uid_t uid, int direction)
798 {
799 	avl_index_t	where;
800 	time_t		ttl = CACHE_TTL + time(NULL);
801 
802 
803 	if (direction == IDMAP_DIRECTION_BI ||
804 	    direction == IDMAP_DIRECTION_W2U) {
805 		sid2uid_gid_t	find;
806 		sid2uid_gid_t	*result;
807 		sid2uid_gid_t	*new;
808 
809 		find.sid_prefix = sid_prefix;
810 		find.rid = rid;
811 
812 		(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
813 		result = avl_find(&idmap_cache.sid2uid_gid.tree, &find, &where);
814 
815 		if (result) {
816 			if (result->uid_ttl == 0)
817 				idmap_cache.sid2uid_gid.uid_num++;
818 			result->uid = uid;
819 			result->uid_ttl = ttl;
820 		} else {
821 			new = malloc(sizeof (sid2uid_gid_t));
822 			if (new == NULL)
823 				goto exit_sid2uid_gid;
824 			new->sid_prefix = strdup(sid_prefix);
825 			if (new->sid_prefix == NULL) {
826 				free(new);
827 				goto exit_sid2uid_gid;
828 			}
829 			new->rid = rid;
830 			new->uid = uid;
831 			new->uid_ttl = ttl;
832 			new->gid = UNDEF_GID;
833 			new->gid_ttl = 0;
834 			new->is_user = UNDEF_ISUSER; /* Unknown */
835 			idmap_cache.sid2uid_gid.uid_num++;
836 
837 			list_insert(&idmap_cache.sid2uid_gid.head, new);
838 			avl_insert(&idmap_cache.sid2uid_gid.tree, new, where);
839 		}
840 		if ((avl_numnodes(&idmap_cache.sid2uid_gid.tree) >
841 		    CACHE_UID_GID_TRIGGER_SIZE) &&
842 		    (idmap_cache.sid2uid_gid.purge_time + CACHE_PURGE_INTERVAL <
843 		    time(NULL)))
844 			idmap_purge_sid2uid_gid_cache(&idmap_cache.sid2uid_gid,
845 			    CACHE_UID_GID_TRIGGER_SIZE);
846 
847 exit_sid2uid_gid:
848 		(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
849 	}
850 
851 	if (direction == IDMAP_DIRECTION_BI ||
852 	    direction == IDMAP_DIRECTION_U2W) {
853 		pid2sid_winname_t	find;
854 		pid2sid_winname_t	*result;
855 		pid2sid_winname_t	*new;
856 
857 		find.pid = uid;
858 
859 		(void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex);
860 		result = avl_find(&idmap_cache.uid2sid_winname.tree, &find,
861 		    &where);
862 
863 		if (result) {
864 			if (update_str(&result->sid_prefix, sid_prefix) != 0)
865 				goto exit_pid2sid_winname;
866 			if (result->sid_ttl == 0)
867 					idmap_cache.uid2sid_winname.sid_num++;
868 			result->rid = rid;
869 			result->sid_ttl = ttl;
870 		} else {
871 			new = malloc(sizeof (pid2sid_winname_t));
872 			if (new == NULL)
873 				goto exit_pid2sid_winname;
874 			new->pid = uid;
875 			new->sid_prefix = strdup(sid_prefix);
876 			if (new->sid_prefix == NULL) {
877 				free(new);
878 				goto exit_pid2sid_winname;
879 			}
880 			new->rid = rid;
881 			new->sid_ttl = ttl;
882 			new->winname = NULL;
883 			new->windomain = NULL;
884 			new->winname_ttl = 0;
885 			idmap_cache.uid2sid_winname.sid_num ++;
886 
887 			list_insert(&idmap_cache.uid2sid_winname.head, new);
888 			avl_insert(&idmap_cache.uid2sid_winname.tree, new,
889 			    where);
890 		}
891 		if ((avl_numnodes(&idmap_cache.uid2sid_winname.tree) >
892 		    CACHE_UID_TRIGGER_SIZE) &&
893 		    (idmap_cache.uid2sid_winname.purge_time +
894 		    CACHE_PURGE_INTERVAL < time(NULL)))
895 			idmap_purge_pid2sid_winname_cache(
896 			    &idmap_cache.uid2sid_winname,
897 			    CACHE_UID_TRIGGER_SIZE);
898 
899 
900 exit_pid2sid_winname:
901 		(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
902 	}
903 }
904 
905 
906 
907 void
908 idmap_cache_add_sid2gid(const char *sid_prefix,
909     idmap_rid_t rid, gid_t gid, int direction)
910 {
911 	avl_index_t	where;
912 	time_t		ttl = CACHE_TTL + time(NULL);
913 
914 
915 	if (direction == IDMAP_DIRECTION_BI ||
916 	    direction == IDMAP_DIRECTION_W2U) {
917 		sid2uid_gid_t	find;
918 		sid2uid_gid_t	*result;
919 		sid2uid_gid_t	*new;
920 
921 		find.sid_prefix = sid_prefix;
922 		find.rid = rid;
923 
924 		(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
925 		result = avl_find(&idmap_cache.sid2uid_gid.tree, &find, &where);
926 
927 		if (result) {
928 			if (result->gid_ttl == 0)
929 				idmap_cache.sid2uid_gid.gid_num++;
930 			result->gid = gid;
931 			result->gid_ttl = ttl;
932 		} else {
933 			new = malloc(sizeof (sid2uid_gid_t));
934 			if (new == NULL)
935 				goto exit_sid2uid_gid;
936 			new->sid_prefix = strdup(sid_prefix);
937 			if (new->sid_prefix == NULL) {
938 				free(new);
939 				goto exit_sid2uid_gid;
940 			}
941 			new->rid = rid;
942 			new->uid = UNDEF_UID;
943 			new->uid_ttl = 0;
944 			new->gid = gid;
945 			new->gid_ttl = ttl;
946 			new->is_user = UNDEF_ISUSER; /* Unknown */
947 			idmap_cache.sid2uid_gid.gid_num++;
948 
949 			list_insert(&idmap_cache.sid2uid_gid.head, new);
950 			avl_insert(&idmap_cache.sid2uid_gid.tree, new, where);
951 		}
952 		if ((avl_numnodes(&idmap_cache.sid2uid_gid.tree) >
953 		    CACHE_UID_GID_TRIGGER_SIZE) &&
954 		    (idmap_cache.sid2uid_gid.purge_time + CACHE_PURGE_INTERVAL <
955 		    time(NULL)))
956 			idmap_purge_sid2uid_gid_cache(&idmap_cache.sid2uid_gid,
957 			    CACHE_UID_GID_TRIGGER_SIZE);
958 
959 exit_sid2uid_gid:
960 		(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
961 	}
962 
963 	if (direction == IDMAP_DIRECTION_BI ||
964 	    direction == IDMAP_DIRECTION_U2W) {
965 		pid2sid_winname_t	find;
966 		pid2sid_winname_t	*result;
967 		pid2sid_winname_t	*new;
968 
969 		find.pid = gid;
970 
971 		(void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex);
972 		result = avl_find(&idmap_cache.gid2sid_winname.tree, &find,
973 		    &where);
974 
975 		if (result) {
976 			if (update_str(&result->sid_prefix, sid_prefix) != 0)
977 				goto  exit_gid2sid_winname;
978 			if (result->sid_ttl == 0)
979 				idmap_cache.gid2sid_winname.sid_num++;
980 			result->rid = rid;
981 			result->sid_ttl = ttl;
982 		} else {
983 			new = malloc(sizeof (pid2sid_winname_t));
984 			if (new == NULL)
985 				goto exit_gid2sid_winname;
986 			new->sid_prefix = strdup(sid_prefix);
987 			if (new->sid_prefix == NULL) {
988 				free(new);
989 				goto exit_gid2sid_winname;
990 			}
991 			new->rid = rid;
992 			new->pid = gid;
993 			new->sid_ttl = ttl;
994 			new->winname = NULL;
995 			new->windomain = NULL;
996 			new->winname_ttl = 0;
997 			idmap_cache.gid2sid_winname.sid_num++;
998 
999 			list_insert(&idmap_cache.gid2sid_winname.head, new);
1000 			avl_insert(&idmap_cache.gid2sid_winname.tree, new,
1001 			    where);
1002 		}
1003 		if ((avl_numnodes(&idmap_cache.gid2sid_winname.tree) >
1004 		    CACHE_GID_TRIGGER_SIZE) &&
1005 		    (idmap_cache.gid2sid_winname.purge_time +
1006 		    CACHE_PURGE_INTERVAL < time(NULL)))
1007 			idmap_purge_pid2sid_winname_cache(
1008 			    &idmap_cache.gid2sid_winname,
1009 			    CACHE_GID_TRIGGER_SIZE);
1010 
1011 exit_gid2sid_winname:
1012 		(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
1013 	}
1014 }
1015 
1016 
1017 void
1018 idmap_cache_add_sid2pid(const char *sid_prefix,
1019     idmap_rid_t rid, uid_t pid, int is_user, int direction)
1020 {
1021 	avl_index_t	where;
1022 	time_t		ttl = CACHE_TTL + time(NULL);
1023 
1024 
1025 	if (direction == IDMAP_DIRECTION_BI ||
1026 	    direction == IDMAP_DIRECTION_W2U) {
1027 		sid2uid_gid_t	find;
1028 		sid2uid_gid_t	*result;
1029 		sid2uid_gid_t	*new;
1030 
1031 		find.sid_prefix = sid_prefix;
1032 		find.rid = rid;
1033 
1034 		(void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex);
1035 		result = avl_find(&idmap_cache.sid2uid_gid.tree, &find, &where);
1036 
1037 		if (result) {
1038 			if (result->is_user == UNDEF_ISUSER)
1039 				idmap_cache.sid2uid_gid.pid_num++;
1040 			result->is_user = is_user;
1041 			if (is_user) {
1042 				if (result->uid_ttl == 0)
1043 					idmap_cache.sid2uid_gid.uid_num++;
1044 				result->uid = pid;
1045 				result->uid_ttl = ttl;
1046 			} else {
1047 				if (result->gid_ttl == 0)
1048 					idmap_cache.sid2uid_gid.gid_num++;
1049 				result->gid = pid;
1050 				result->gid_ttl = ttl;
1051 			}
1052 		} else {
1053 			new = malloc(sizeof (sid2uid_gid_t));
1054 			if (new == NULL)
1055 				goto exit_sid2uid_gid;
1056 			new->sid_prefix = strdup(sid_prefix);
1057 			if (new->sid_prefix == NULL) {
1058 				free(new);
1059 				goto exit_sid2uid_gid;
1060 			}
1061 			new->rid = rid;
1062 			new->is_user = is_user;
1063 			if (is_user) {
1064 				new->uid = pid;
1065 				new->uid_ttl = ttl;
1066 				new->gid = UNDEF_GID;
1067 				new->gid_ttl = 0;
1068 				idmap_cache.sid2uid_gid.uid_num++;
1069 			} else {
1070 				new->uid = UNDEF_UID;
1071 				new->uid_ttl = 0;
1072 				new->gid = pid;
1073 				new->gid_ttl = ttl;
1074 				idmap_cache.sid2uid_gid.gid_num++;
1075 			}
1076 			idmap_cache.sid2uid_gid.pid_num++;
1077 
1078 			list_insert(&idmap_cache.sid2uid_gid.head, new);
1079 			avl_insert(&idmap_cache.sid2uid_gid.tree, new, where);
1080 		}
1081 		if ((avl_numnodes(&idmap_cache.sid2uid_gid.tree) >
1082 		    CACHE_UID_GID_TRIGGER_SIZE) &&
1083 		    (idmap_cache.sid2uid_gid.purge_time + CACHE_PURGE_INTERVAL <
1084 		    time(NULL)))
1085 			idmap_purge_sid2uid_gid_cache(&idmap_cache.sid2uid_gid,
1086 			    CACHE_UID_GID_TRIGGER_SIZE);
1087 
1088 exit_sid2uid_gid:
1089 		(void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex);
1090 	}
1091 
1092 	if (direction == IDMAP_DIRECTION_BI ||
1093 	    direction == IDMAP_DIRECTION_U2W) {
1094 		pid2sid_winname_t	find;
1095 		pid2sid_winname_t	*result;
1096 		pid2sid_winname_t	*new;
1097 
1098 		find.pid = pid;
1099 		if (is_user) {
1100 			(void) pthread_mutex_lock(
1101 			    &idmap_cache.uid2sid_winname.mutex);
1102 			result = avl_find(&idmap_cache.uid2sid_winname.tree,
1103 			    &find, &where);
1104 
1105 			if (result) {
1106 				if (update_str(&result->sid_prefix, sid_prefix)
1107 				    != 0)
1108 					goto exit_uid2sid_winname;
1109 				if (result->sid_ttl == 0)
1110 					idmap_cache.uid2sid_winname.sid_num++;
1111 				result->rid = rid;
1112 				result->sid_ttl = ttl;
1113 			} else {
1114 				new = malloc(sizeof (pid2sid_winname_t));
1115 				if (new == NULL)
1116 					goto exit_uid2sid_winname;
1117 				new->sid_prefix = strdup(sid_prefix);
1118 				if (new->sid_prefix == NULL) {
1119 					free(new);
1120 					goto exit_uid2sid_winname;
1121 				}
1122 				new->rid = rid;
1123 				new->pid = pid;
1124 				new->sid_ttl = ttl;
1125 				new->winname = NULL;
1126 				new->windomain = NULL;
1127 				new->winname_ttl = 0;
1128 				idmap_cache.uid2sid_winname.sid_num++;
1129 
1130 				list_insert(&idmap_cache.uid2sid_winname.head,
1131 				    new);
1132 				avl_insert(&idmap_cache.uid2sid_winname.tree,
1133 				    new, where);
1134 			}
1135 			if ((avl_numnodes(&idmap_cache.uid2sid_winname.tree) >
1136 			    CACHE_UID_TRIGGER_SIZE) &&
1137 			    (idmap_cache.uid2sid_winname.purge_time +
1138 			    CACHE_PURGE_INTERVAL < time(NULL)))
1139 				idmap_purge_pid2sid_winname_cache(
1140 				    &idmap_cache.uid2sid_winname,
1141 				    CACHE_UID_TRIGGER_SIZE);
1142 
1143 exit_uid2sid_winname:
1144 			(void) pthread_mutex_unlock(
1145 			    &idmap_cache.uid2sid_winname.mutex);
1146 		} else {
1147 			(void) pthread_mutex_lock(
1148 			    &idmap_cache.gid2sid_winname.mutex);
1149 			result = avl_find(&idmap_cache.gid2sid_winname.tree,
1150 			    &find, &where);
1151 
1152 			if (result) {
1153 				if (update_str(&result->sid_prefix, sid_prefix)
1154 				    != 0)
1155 					goto exit_gid2sid_winname;
1156 				if (result->sid_ttl == 0)
1157 					idmap_cache.gid2sid_winname.sid_num++;
1158 				result->rid = rid;
1159 				result->sid_ttl = ttl;
1160 			} else {
1161 				new = malloc(sizeof (pid2sid_winname_t));
1162 				if (new == NULL)
1163 					goto exit_gid2sid_winname;
1164 				new->sid_prefix = strdup(sid_prefix);
1165 				if (new->sid_prefix == NULL) {
1166 					free(new);
1167 					goto exit_gid2sid_winname;
1168 				}
1169 				new->rid = rid;
1170 				new->pid = pid;
1171 				new->sid_ttl = ttl;
1172 				new->winname = NULL;
1173 				new->windomain = NULL;
1174 				new->winname_ttl = 0;
1175 				idmap_cache.gid2sid_winname.sid_num++;
1176 
1177 				list_insert(&idmap_cache.gid2sid_winname.head,
1178 				    new);
1179 				avl_insert(&idmap_cache.gid2sid_winname.tree,
1180 				    new, where);
1181 			}
1182 			if ((avl_numnodes(&idmap_cache.gid2sid_winname.tree) >
1183 			    CACHE_GID_TRIGGER_SIZE) &&
1184 			    (idmap_cache.gid2sid_winname.purge_time +
1185 			    CACHE_PURGE_INTERVAL < time(NULL)))
1186 				idmap_purge_pid2sid_winname_cache(
1187 				    &idmap_cache.gid2sid_winname,
1188 				    CACHE_GID_TRIGGER_SIZE);
1189 exit_gid2sid_winname:
1190 			(void) pthread_mutex_unlock(
1191 			    &idmap_cache.gid2sid_winname.mutex);
1192 		}
1193 	}
1194 }
1195 
1196 
1197 
1198 void
1199 idmap_cache_add_winname2uid(const char *name, const char *domain, uid_t uid,
1200     int direction)
1201 {
1202 	avl_index_t	where;
1203 	time_t		ttl = CACHE_TTL + time(NULL);
1204 
1205 
1206 	if (direction == IDMAP_DIRECTION_BI ||
1207 	    direction == IDMAP_DIRECTION_W2U) {
1208 		winname2uid_gid_t	find;
1209 		winname2uid_gid_t	*result;
1210 		winname2uid_gid_t	*new;
1211 
1212 		find.winname = name;
1213 		find.windomain = domain;
1214 
1215 		(void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex);
1216 		result = avl_find(&idmap_cache.winname2uid_gid.tree, &find,
1217 		    &where);
1218 
1219 		if (result) {
1220 			if (result->uid_ttl == 0)
1221 				idmap_cache.winname2uid_gid.uid_num++;
1222 			result->uid = uid;
1223 			result->uid_ttl = ttl;
1224 		} else {
1225 			new = malloc(sizeof (winname2uid_gid_t));
1226 			if (new == NULL)
1227 				goto exit_winname2uid_gid;
1228 			new->winname = strdup(name);
1229 			if (new->winname == NULL) {
1230 				free(new);
1231 				goto exit_winname2uid_gid;
1232 			}
1233 			if (domain != NULL) {
1234 				new->windomain = strdup(domain);
1235 				if (new->winname == NULL) {
1236 					free((char *)new->winname);
1237 					free(new);
1238 					goto exit_winname2uid_gid;
1239 				}
1240 			} else
1241 				new->windomain = NULL;
1242 			new->uid = uid;
1243 			new->uid_ttl = ttl;
1244 			new->gid = UNDEF_GID;
1245 			new->gid_ttl = 0;
1246 			idmap_cache.winname2uid_gid.uid_num++;
1247 
1248 			list_insert(&idmap_cache.winname2uid_gid.head, new);
1249 			avl_insert(&idmap_cache.winname2uid_gid.tree, new,
1250 			    where);
1251 		}
1252 		if ((avl_numnodes(&idmap_cache.winname2uid_gid.tree) >
1253 		    CACHE_UID_GID_TRIGGER_SIZE) &&
1254 		    (idmap_cache.winname2uid_gid.purge_time +
1255 		    CACHE_PURGE_INTERVAL < time(NULL)))
1256 			idmap_purge_winname2uid_gid_cache(
1257 			    &idmap_cache.winname2uid_gid,
1258 			    CACHE_UID_GID_TRIGGER_SIZE);
1259 exit_winname2uid_gid:
1260 		(void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex);
1261 	}
1262 
1263 	if (direction == IDMAP_DIRECTION_BI ||
1264 	    direction == IDMAP_DIRECTION_U2W) {
1265 		pid2sid_winname_t	find;
1266 		pid2sid_winname_t	*result;
1267 		pid2sid_winname_t	*new;
1268 
1269 		find.pid = uid;
1270 
1271 		(void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex);
1272 		result = avl_find(&idmap_cache.uid2sid_winname.tree, &find,
1273 		    &where);
1274 
1275 		if (result) {
1276 			if (update_str(&result->winname, name) != 0)
1277 				goto exit_uid2sid_winname;
1278 			if (update_str(&result->windomain, domain) != 0)
1279 				goto exit_uid2sid_winname;
1280 			if (result->winname_ttl == 0)
1281 				idmap_cache.uid2sid_winname.winname_num++;
1282 			result->winname_ttl = ttl;
1283 		} else {
1284 			new = malloc(sizeof (pid2sid_winname_t));
1285 			if (new == NULL)
1286 				goto exit_uid2sid_winname;
1287 			new->pid = uid;
1288 			new->winname = strdup(name);
1289 			if (new->winname == NULL) {
1290 				free(new);
1291 				goto exit_uid2sid_winname;
1292 			}
1293 			if (domain != NULL) {
1294 				new->windomain = strdup(domain);
1295 				if (new->windomain == NULL) {
1296 					free((char *)new->winname);
1297 					free(new);
1298 					goto exit_uid2sid_winname;
1299 				}
1300 			} else
1301 				new->windomain = NULL;
1302 			new->winname_ttl = ttl;
1303 			new->sid_prefix = NULL;
1304 			new->rid = 0;
1305 			new->sid_ttl = 0;
1306 			idmap_cache.uid2sid_winname.winname_num ++;
1307 
1308 			list_insert(&idmap_cache.uid2sid_winname.head, new);
1309 			avl_insert(&idmap_cache.uid2sid_winname.tree, new,
1310 			    where);
1311 		}
1312 		if ((avl_numnodes(&idmap_cache.uid2sid_winname.tree) >
1313 		    CACHE_UID_TRIGGER_SIZE) &&
1314 		    (idmap_cache.uid2sid_winname.purge_time +
1315 		    CACHE_PURGE_INTERVAL < time(NULL)))
1316 			idmap_purge_pid2sid_winname_cache(
1317 			    &idmap_cache.uid2sid_winname,
1318 			    CACHE_UID_TRIGGER_SIZE);
1319 exit_uid2sid_winname:
1320 		(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
1321 	}
1322 }
1323 
1324 
1325 
1326 
1327 
1328 void
1329 idmap_cache_add_winname2gid(const char *name, const char *domain, gid_t gid,
1330     int direction)
1331 {
1332 	avl_index_t	where;
1333 	time_t		ttl = CACHE_TTL + time(NULL);
1334 
1335 
1336 	if (direction == IDMAP_DIRECTION_BI ||
1337 	    direction == IDMAP_DIRECTION_W2U) {
1338 		winname2uid_gid_t	find;
1339 		winname2uid_gid_t	*result;
1340 		winname2uid_gid_t	*new;
1341 
1342 		find.winname = name;
1343 		find.windomain = domain;
1344 
1345 		(void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex);
1346 		result = avl_find(&idmap_cache.winname2uid_gid.tree, &find,
1347 		    &where);
1348 
1349 		if (result) {
1350 			if (result->uid_ttl == 0)
1351 				idmap_cache.winname2uid_gid.gid_num++;
1352 			result->gid = gid;
1353 			result->gid_ttl = ttl;
1354 		} else {
1355 			new = malloc(sizeof (winname2uid_gid_t));
1356 			if (new == NULL)
1357 				goto exit_winname2uid_gid;
1358 			new->winname = strdup(name);
1359 			if (new->winname == NULL) {
1360 				free(new);
1361 				goto exit_winname2uid_gid;
1362 			}
1363 			if (domain != NULL) {
1364 				new->windomain = strdup(domain);
1365 				if (new->windomain == NULL) {
1366 					free((char *)new->winname);
1367 					free(new);
1368 					goto exit_winname2uid_gid;
1369 				}
1370 			}
1371 			else
1372 				new->windomain = NULL;
1373 			new->uid = UNDEF_UID;
1374 			new->uid_ttl = 0;
1375 			new->gid = gid;
1376 			new->gid_ttl = ttl;
1377 			idmap_cache.winname2uid_gid.gid_num++;
1378 
1379 			list_insert(&idmap_cache.winname2uid_gid.head, new);
1380 			avl_insert(&idmap_cache.winname2uid_gid.tree, new,
1381 			    where);
1382 		}
1383 		if ((avl_numnodes(&idmap_cache.winname2uid_gid.tree) >
1384 		    CACHE_UID_GID_TRIGGER_SIZE) &&
1385 		    (idmap_cache.winname2uid_gid.purge_time +
1386 		    CACHE_PURGE_INTERVAL < time(NULL)))
1387 			idmap_purge_winname2uid_gid_cache(
1388 			    &idmap_cache.winname2uid_gid,
1389 			    CACHE_UID_GID_TRIGGER_SIZE);
1390 exit_winname2uid_gid:
1391 		(void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex);
1392 	}
1393 
1394 	if (direction == IDMAP_DIRECTION_BI ||
1395 	    direction == IDMAP_DIRECTION_U2W) {
1396 		pid2sid_winname_t	find;
1397 		pid2sid_winname_t	*result;
1398 		pid2sid_winname_t	*new;
1399 
1400 		find.pid = gid;
1401 
1402 		(void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex);
1403 		result = avl_find(&idmap_cache.gid2sid_winname.tree, &find,
1404 		    &where);
1405 
1406 		if (result) {
1407 			if (update_str(&result->winname, name) != 0)
1408 				goto exit_gid2sid_winname;
1409 			if (update_str(&result->windomain, domain) != 0)
1410 				goto exit_gid2sid_winname;
1411 			if (result->winname_ttl == 0)
1412 				idmap_cache.gid2sid_winname.winname_num++;
1413 			result->winname_ttl = ttl;
1414 		} else {
1415 			new = malloc(sizeof (pid2sid_winname_t));
1416 			if (new == NULL)
1417 				goto exit_gid2sid_winname;
1418 			new->pid = gid;
1419 			new->winname = strdup(name);
1420 			if (new->winname == NULL) {
1421 				free(new);
1422 				goto exit_gid2sid_winname;
1423 			}
1424 			if (domain != NULL) {
1425 				new->windomain = strdup(domain);
1426 				if (new->windomain == NULL) {
1427 					free((char *)new->winname);
1428 					free(new);
1429 					goto exit_gid2sid_winname;
1430 				}
1431 			}
1432 			else
1433 				new->windomain = NULL;
1434 			new->winname_ttl = ttl;
1435 			new->sid_prefix = NULL;
1436 			new->rid = 0;
1437 			new->sid_ttl = 0;
1438 			idmap_cache.gid2sid_winname.winname_num ++;
1439 
1440 			list_insert(&idmap_cache.gid2sid_winname.head, new);
1441 			avl_insert(&idmap_cache.gid2sid_winname.tree, new,
1442 			    where);
1443 		}
1444 		if ((avl_numnodes(&idmap_cache.gid2sid_winname.tree) >
1445 		    CACHE_UID_TRIGGER_SIZE) &&
1446 		    (idmap_cache.gid2sid_winname.purge_time +
1447 		    CACHE_PURGE_INTERVAL < time(NULL)))
1448 			idmap_purge_pid2sid_winname_cache(
1449 			    &idmap_cache.gid2sid_winname,
1450 			    CACHE_UID_TRIGGER_SIZE);
1451 exit_gid2sid_winname:
1452 		(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
1453 	}
1454 }
1455 
1456 
1457 static void
1458 idmap_purge_sid2uid_gid_cache(sid2uid_gid_cache_t *cache, size_t limit)
1459 {
1460 	time_t		now = time(NULL);
1461 	sid2uid_gid_t	*item;
1462 
1463 	while (avl_numnodes(&cache->tree) > limit) {
1464 		/* Remove least recently used */
1465 		item = cache->head.blink;
1466 		list_remove(item);
1467 		avl_remove(&cache->tree, item);
1468 		if (item->uid_ttl != 0)
1469 			cache->uid_num--;
1470 		if (item->gid_ttl != 0)
1471 			cache->gid_num--;
1472 		if (item->is_user != UNDEF_ISUSER)
1473 			cache->pid_num--;
1474 
1475 		if (item->sid_prefix)
1476 			free((char *)item->sid_prefix);
1477 		free(item);
1478 	}
1479 	cache->purge_time = now;
1480 }
1481 
1482 
1483 static void
1484 idmap_purge_winname2uid_gid_cache(winname2uid_gid_cache_t *cache, size_t limit)
1485 {
1486 	time_t		now = time(NULL);
1487 	winname2uid_gid_t	*item;
1488 
1489 	while (avl_numnodes(&cache->tree) > limit) {
1490 		/* Remove least recently used */
1491 		item = cache->head.blink;
1492 		list_remove(item);
1493 		avl_remove(&cache->tree, item);
1494 		if (item->uid_ttl != 0)
1495 			cache->uid_num--;
1496 		if (item->gid_ttl != 0)
1497 			cache->gid_num--;
1498 
1499 		if (item->winname)
1500 			free((char *)item->winname);
1501 		if (item->windomain)
1502 			free((char *)item->windomain);
1503 		free(item);
1504 	}
1505 	cache->purge_time = now;
1506 }
1507 
1508 
1509 static void
1510 idmap_purge_pid2sid_winname_cache(pid2sid_winname_cache_t *cache, size_t limit)
1511 {
1512 	time_t		now = time(NULL);
1513 	pid2sid_winname_t	*item;
1514 
1515 	while (avl_numnodes(&cache->tree) > limit) {
1516 		/* Remove least recently used */
1517 		item = cache->head.blink;
1518 		list_remove(item);
1519 		avl_remove(&cache->tree, item);
1520 		if (item->winname_ttl != 0)
1521 			cache->winname_num--;
1522 		if (item->sid_ttl != 0)
1523 			cache->sid_num--;
1524 
1525 		if (item->winname)
1526 			free((char *)item->winname);
1527 		if (item->windomain)
1528 			free((char *)item->windomain);
1529 		if (item->sid_prefix)
1530 			free((char *)item->sid_prefix);
1531 		free(item);
1532 	}
1533 	cache->purge_time = now;
1534 }
1535