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