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
90typedef 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
104typedef 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
118typedef 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
131typedef 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
143typedef 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
155typedef 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
166typedef 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
175typedef int (*avl_comp_fn)(const void*, const void*);
176
177static void
178idmap_purge_sid2uid_gid_cache(sid2uid_gid_cache_t *cache, size_t limit);
179
180static void
181idmap_purge_pid2sid_winname_cache(pid2sid_winname_cache_t *cache, size_t limit);
182
183static void
184idmap_purge_winname2uid_gid_cache(winname2uid_gid_cache_t *avl, size_t limit);
185
186/*
187 * Global structures
188 */
189
190static idmap_cache_t idmap_cache;
191
192
193
194
195static int
196idmap_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
212static int
213idmap_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
224static int
225idmap_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 */
256static int
257update_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
286void
287idmap_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
342void
343idmap_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
447void
448idmap_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
476idmap_stat
477idmap_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
507idmap_stat
508idmap_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
539idmap_stat
540idmap_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
576idmap_stat
577idmap_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
608idmap_stat
609idmap_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
641idmap_stat
642idmap_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
686idmap_stat
687idmap_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
731idmap_stat
732idmap_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
761idmap_stat
762idmap_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
791void
792idmap_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
844exit_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
897exit_pid2sid_winname:
898		(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
899	}
900}
901
902
903
904void
905idmap_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
956exit_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
1008exit_gid2sid_winname:
1009		(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
1010	}
1011}
1012
1013
1014void
1015idmap_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
1085exit_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
1139exit_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);
1184exit_gid2sid_winname:
1185			(void) pthread_mutex_unlock(
1186			    &idmap_cache.gid2sid_winname.mutex);
1187		}
1188	}
1189}
1190
1191
1192
1193void
1194idmap_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);
1254exit_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);
1314exit_uid2sid_winname:
1315		(void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex);
1316	}
1317}
1318
1319
1320
1321
1322
1323void
1324idmap_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);
1385exit_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);
1446exit_gid2sid_winname:
1447		(void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex);
1448	}
1449}
1450
1451
1452static void
1453idmap_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
1478static void
1479idmap_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
1504static void
1505idmap_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