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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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