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