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