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