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