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