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