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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/types.h> 28 #include <sys/tzfile.h> 29 #include <sys/atomic.h> 30 #include <sys/kidmap.h> 31 #include <sys/time.h> 32 #include <sys/cpuvar.h> 33 #include <smbsrv/smb_kproto.h> 34 #include <smbsrv/smb_fsops.h> 35 #include <smbsrv/smbinfo.h> 36 #include <smbsrv/smb_xdr.h> 37 #include <smbsrv/smb_vops.h> 38 #include <smbsrv/smb_idmap.h> 39 40 #include <sys/sid.h> 41 #include <sys/priv_names.h> 42 43 static kmem_cache_t *smb_dtor_cache; 44 static boolean_t smb_llist_initialized = B_FALSE; 45 46 static void smb_llist_flush(smb_llist_t *); 47 static boolean_t smb_thread_continue_timedwait_locked(smb_thread_t *, int); 48 49 time_t tzh_leapcnt = 0; 50 51 struct tm 52 *smb_gmtime_r(time_t *clock, struct tm *result); 53 54 time_t 55 smb_timegm(struct tm *tm); 56 57 struct tm { 58 int tm_sec; 59 int tm_min; 60 int tm_hour; 61 int tm_mday; 62 int tm_mon; 63 int tm_year; 64 int tm_wday; 65 int tm_yday; 66 int tm_isdst; 67 }; 68 69 static int days_in_month[] = { 70 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 71 }; 72 73 int 74 smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str) 75 { 76 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 77 return (smb_wcequiv_strlen(str)); 78 return (strlen(str)); 79 } 80 81 int 82 smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str) 83 { 84 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 85 return (smb_wcequiv_strlen(str) + 2); 86 return (strlen(str) + 1); 87 } 88 89 int 90 smb_ascii_or_unicode_null_len(struct smb_request *sr) 91 { 92 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 93 return (2); 94 return (1); 95 } 96 97 /* 98 * Return B_TRUE if pattern contains wildcards 99 */ 100 boolean_t 101 smb_contains_wildcards(const char *pattern) 102 { 103 static const char *wildcards = "*?"; 104 105 return (strpbrk(pattern, wildcards) != NULL); 106 } 107 108 /* 109 * When converting wildcards a '.' in a name is treated as a base and 110 * extension separator even if the name is longer than 8.3. 111 * 112 * The '*' character matches an entire part of the name. For example, 113 * "*.abc" matches any name with an extension of "abc". 114 * 115 * The '?' character matches a single character. 116 * If the base contains all ? (8 or more) then it is treated as *. 117 * If the extension contains all ? (3 or more) then it is treated as *. 118 * 119 * Clients convert ASCII wildcards to Unicode wildcards as follows: 120 * 121 * ? is converted to > 122 * . is converted to " if it is followed by ? or * 123 * * is converted to < if it is followed by . 124 * 125 * Note that clients convert "*." to '< and drop the '.' but "*.txt" 126 * is sent as "<.TXT", i.e. 127 * 128 * dir *. -> dir < 129 * dir *.txt -> dir <.TXT 130 * 131 * Since " and < are illegal in Windows file names, we always convert 132 * these Unicode wildcards without checking the following character. 133 */ 134 void 135 smb_convert_wildcards(char *pattern) 136 { 137 static char *match_all[] = { 138 "*.", 139 "*.*" 140 }; 141 char *extension; 142 char *p; 143 int len; 144 int i; 145 146 /* 147 * Special case "<" for "dir *.", and fast-track for "*". 148 */ 149 if ((*pattern == '<') || (*pattern == '*')) { 150 if (*(pattern + 1) == '\0') { 151 *pattern = '*'; 152 return; 153 } 154 } 155 156 for (p = pattern; *p != '\0'; ++p) { 157 switch (*p) { 158 case '<': 159 *p = '*'; 160 break; 161 case '>': 162 *p = '?'; 163 break; 164 case '\"': 165 *p = '.'; 166 break; 167 default: 168 break; 169 } 170 } 171 172 /* 173 * Replace "????????.ext" with "*.ext". 174 */ 175 p = pattern; 176 p += strspn(p, "?"); 177 if (*p == '.') { 178 *p = '\0'; 179 len = strlen(pattern); 180 *p = '.'; 181 if (len >= SMB_NAME83_BASELEN) { 182 *pattern = '*'; 183 (void) strlcpy(pattern + 1, p, MAXPATHLEN - 1); 184 } 185 } 186 187 /* 188 * Replace "base.???" with 'base.*'. 189 */ 190 if ((extension = strrchr(pattern, '.')) != NULL) { 191 p = ++extension; 192 p += strspn(p, "?"); 193 if (*p == '\0') { 194 len = strlen(extension); 195 if (len >= SMB_NAME83_EXTLEN) { 196 *extension = '\0'; 197 (void) strlcat(pattern, "*", MAXPATHLEN); 198 } 199 } 200 } 201 202 /* 203 * Replace anything that matches an entry in match_all with "*". 204 */ 205 for (i = 0; i < sizeof (match_all) / sizeof (match_all[0]); ++i) { 206 if (strcmp(pattern, match_all[i]) == 0) { 207 (void) strlcpy(pattern, "*", MAXPATHLEN); 208 break; 209 } 210 } 211 } 212 213 /* 214 * smb_sattr_check 215 * 216 * Check file attributes against a search attribute (sattr) mask. 217 * 218 * Normal files, which includes READONLY and ARCHIVE, always pass 219 * this check. If the DIRECTORY, HIDDEN or SYSTEM special attributes 220 * are set then they must appear in the search mask. The special 221 * attributes are inclusive, i.e. all special attributes that appear 222 * in sattr must also appear in the file attributes for the check to 223 * pass. 224 * 225 * The following examples show how this works: 226 * 227 * fileA: READONLY 228 * fileB: 0 (no attributes = normal file) 229 * fileC: READONLY, ARCHIVE 230 * fileD: HIDDEN 231 * fileE: READONLY, HIDDEN, SYSTEM 232 * dirA: DIRECTORY 233 * 234 * search attribute: 0 235 * Returns: fileA, fileB and fileC. 236 * search attribute: HIDDEN 237 * Returns: fileA, fileB, fileC and fileD. 238 * search attribute: SYSTEM 239 * Returns: fileA, fileB and fileC. 240 * search attribute: DIRECTORY 241 * Returns: fileA, fileB, fileC and dirA. 242 * search attribute: HIDDEN and SYSTEM 243 * Returns: fileA, fileB, fileC, fileD and fileE. 244 * 245 * Returns true if the file and sattr match; otherwise, returns false. 246 */ 247 boolean_t 248 smb_sattr_check(uint16_t dosattr, uint16_t sattr) 249 { 250 if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) && 251 !(sattr & FILE_ATTRIBUTE_DIRECTORY)) 252 return (B_FALSE); 253 254 if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && 255 !(sattr & FILE_ATTRIBUTE_HIDDEN)) 256 return (B_FALSE); 257 258 if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && 259 !(sattr & FILE_ATTRIBUTE_SYSTEM)) 260 return (B_FALSE); 261 262 return (B_TRUE); 263 } 264 265 int 266 microtime(timestruc_t *tvp) 267 { 268 tvp->tv_sec = gethrestime_sec(); 269 tvp->tv_nsec = 0; 270 return (0); 271 } 272 273 int32_t 274 clock_get_milli_uptime() 275 { 276 return (TICK_TO_MSEC(ddi_get_lbolt())); 277 } 278 279 int /*ARGSUSED*/ 280 smb_noop(void *p, size_t size, int foo) 281 { 282 return (0); 283 } 284 285 /* 286 * smb_idpool_increment 287 * 288 * This function increments the ID pool by doubling the current size. This 289 * function assumes the caller entered the mutex of the pool. 290 */ 291 static int 292 smb_idpool_increment( 293 smb_idpool_t *pool) 294 { 295 uint8_t *new_pool; 296 uint32_t new_size; 297 298 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 299 300 new_size = pool->id_size * 2; 301 if (new_size <= SMB_IDPOOL_MAX_SIZE) { 302 new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP); 303 if (new_pool) { 304 bzero(new_pool, new_size / 8); 305 bcopy(pool->id_pool, new_pool, pool->id_size / 8); 306 kmem_free(pool->id_pool, pool->id_size / 8); 307 pool->id_pool = new_pool; 308 pool->id_free_counter += new_size - pool->id_size; 309 pool->id_max_free_counter += new_size - pool->id_size; 310 pool->id_size = new_size; 311 pool->id_idx_msk = (new_size / 8) - 1; 312 if (new_size >= SMB_IDPOOL_MAX_SIZE) { 313 /* id -1 made unavailable */ 314 pool->id_pool[pool->id_idx_msk] = 0x80; 315 pool->id_free_counter--; 316 pool->id_max_free_counter--; 317 } 318 return (0); 319 } 320 } 321 return (-1); 322 } 323 324 /* 325 * smb_idpool_constructor 326 * 327 * This function initializes the pool structure provided. 328 */ 329 int 330 smb_idpool_constructor( 331 smb_idpool_t *pool) 332 { 333 334 ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC); 335 336 pool->id_size = SMB_IDPOOL_MIN_SIZE; 337 pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1; 338 pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1; 339 pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1; 340 pool->id_bit = 0x02; 341 pool->id_bit_idx = 1; 342 pool->id_idx = 0; 343 pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8), 344 KM_SLEEP); 345 bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8)); 346 /* -1 id made unavailable */ 347 pool->id_pool[0] = 0x01; /* id 0 made unavailable */ 348 mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL); 349 pool->id_magic = SMB_IDPOOL_MAGIC; 350 return (0); 351 } 352 353 /* 354 * smb_idpool_destructor 355 * 356 * This function tears down and frees the resources associated with the 357 * pool provided. 358 */ 359 void 360 smb_idpool_destructor( 361 smb_idpool_t *pool) 362 { 363 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 364 ASSERT(pool->id_free_counter == pool->id_max_free_counter); 365 pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC; 366 mutex_destroy(&pool->id_mutex); 367 kmem_free(pool->id_pool, (size_t)(pool->id_size / 8)); 368 } 369 370 /* 371 * smb_idpool_alloc 372 * 373 * This function allocates an ID from the pool provided. 374 */ 375 int 376 smb_idpool_alloc( 377 smb_idpool_t *pool, 378 uint16_t *id) 379 { 380 uint32_t i; 381 uint8_t bit; 382 uint8_t bit_idx; 383 uint8_t byte; 384 385 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 386 387 mutex_enter(&pool->id_mutex); 388 if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) { 389 mutex_exit(&pool->id_mutex); 390 return (-1); 391 } 392 393 i = pool->id_size; 394 while (i) { 395 bit = pool->id_bit; 396 bit_idx = pool->id_bit_idx; 397 byte = pool->id_pool[pool->id_idx]; 398 while (bit) { 399 if (byte & bit) { 400 bit = bit << 1; 401 bit_idx++; 402 continue; 403 } 404 pool->id_pool[pool->id_idx] |= bit; 405 *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx); 406 pool->id_free_counter--; 407 pool->id_bit = bit; 408 pool->id_bit_idx = bit_idx; 409 mutex_exit(&pool->id_mutex); 410 return (0); 411 } 412 pool->id_bit = 1; 413 pool->id_bit_idx = 0; 414 pool->id_idx++; 415 pool->id_idx &= pool->id_idx_msk; 416 --i; 417 } 418 /* 419 * This section of code shouldn't be reached. If there are IDs 420 * available and none could be found there's a problem. 421 */ 422 ASSERT(0); 423 mutex_exit(&pool->id_mutex); 424 return (-1); 425 } 426 427 /* 428 * smb_idpool_free 429 * 430 * This function frees the ID provided. 431 */ 432 void 433 smb_idpool_free( 434 smb_idpool_t *pool, 435 uint16_t id) 436 { 437 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 438 ASSERT(id != 0); 439 ASSERT(id != 0xFFFF); 440 441 mutex_enter(&pool->id_mutex); 442 if (pool->id_pool[id >> 3] & (1 << (id & 7))) { 443 pool->id_pool[id >> 3] &= ~(1 << (id & 7)); 444 pool->id_free_counter++; 445 ASSERT(pool->id_free_counter <= pool->id_max_free_counter); 446 mutex_exit(&pool->id_mutex); 447 return; 448 } 449 /* Freeing a free ID. */ 450 ASSERT(0); 451 mutex_exit(&pool->id_mutex); 452 } 453 454 /* 455 * Initialize the llist delete queue object cache. 456 */ 457 void 458 smb_llist_init(void) 459 { 460 if (smb_llist_initialized) 461 return; 462 463 smb_dtor_cache = kmem_cache_create("smb_dtor_cache", 464 sizeof (smb_dtor_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 465 466 smb_llist_initialized = B_TRUE; 467 } 468 469 /* 470 * Destroy the llist delete queue object cache. 471 */ 472 void 473 smb_llist_fini(void) 474 { 475 if (!smb_llist_initialized) 476 return; 477 478 kmem_cache_destroy(smb_dtor_cache); 479 smb_llist_initialized = B_FALSE; 480 } 481 482 /* 483 * smb_llist_constructor 484 * 485 * This function initializes a locked list. 486 */ 487 void 488 smb_llist_constructor( 489 smb_llist_t *ll, 490 size_t size, 491 size_t offset) 492 { 493 rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL); 494 mutex_init(&ll->ll_mutex, NULL, MUTEX_DEFAULT, NULL); 495 list_create(&ll->ll_list, size, offset); 496 list_create(&ll->ll_deleteq, sizeof (smb_dtor_t), 497 offsetof(smb_dtor_t, dt_lnd)); 498 ll->ll_count = 0; 499 ll->ll_wrop = 0; 500 ll->ll_deleteq_count = 0; 501 } 502 503 /* 504 * Flush the delete queue and destroy a locked list. 505 */ 506 void 507 smb_llist_destructor( 508 smb_llist_t *ll) 509 { 510 smb_llist_flush(ll); 511 512 ASSERT(ll->ll_count == 0); 513 ASSERT(ll->ll_deleteq_count == 0); 514 515 rw_destroy(&ll->ll_lock); 516 list_destroy(&ll->ll_list); 517 list_destroy(&ll->ll_deleteq); 518 mutex_destroy(&ll->ll_mutex); 519 } 520 521 /* 522 * Post an object to the delete queue. The delete queue will be processed 523 * during list exit or list destruction. Objects are often posted for 524 * deletion during list iteration (while the list is locked) but that is 525 * not required, and an object can be posted at any time. 526 */ 527 void 528 smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc) 529 { 530 smb_dtor_t *dtor; 531 532 ASSERT((object != NULL) && (dtorproc != NULL)); 533 534 dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP); 535 bzero(dtor, sizeof (smb_dtor_t)); 536 dtor->dt_magic = SMB_DTOR_MAGIC; 537 dtor->dt_object = object; 538 dtor->dt_proc = dtorproc; 539 540 mutex_enter(&ll->ll_mutex); 541 list_insert_tail(&ll->ll_deleteq, dtor); 542 ++ll->ll_deleteq_count; 543 mutex_exit(&ll->ll_mutex); 544 } 545 546 /* 547 * Exit the list lock and process the delete queue. 548 */ 549 void 550 smb_llist_exit(smb_llist_t *ll) 551 { 552 rw_exit(&ll->ll_lock); 553 smb_llist_flush(ll); 554 } 555 556 /* 557 * Flush the list delete queue. The mutex is dropped across the destructor 558 * call in case this leads to additional objects being posted to the delete 559 * queue. 560 */ 561 static void 562 smb_llist_flush(smb_llist_t *ll) 563 { 564 smb_dtor_t *dtor; 565 566 mutex_enter(&ll->ll_mutex); 567 568 dtor = list_head(&ll->ll_deleteq); 569 while (dtor != NULL) { 570 SMB_DTOR_VALID(dtor); 571 ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL)); 572 list_remove(&ll->ll_deleteq, dtor); 573 --ll->ll_deleteq_count; 574 mutex_exit(&ll->ll_mutex); 575 576 dtor->dt_proc(dtor->dt_object); 577 578 dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC; 579 kmem_cache_free(smb_dtor_cache, dtor); 580 mutex_enter(&ll->ll_mutex); 581 dtor = list_head(&ll->ll_deleteq); 582 } 583 584 mutex_exit(&ll->ll_mutex); 585 } 586 587 /* 588 * smb_llist_upgrade 589 * 590 * This function tries to upgrade the lock of the locked list. It assumes the 591 * locked has already been entered in RW_READER mode. It first tries using the 592 * Solaris function rw_tryupgrade(). If that call fails the lock is released 593 * and reentered in RW_WRITER mode. In that last case a window is opened during 594 * which the contents of the list may have changed. The return code indicates 595 * whether or not the list was modified when the lock was exited. 596 */ 597 int smb_llist_upgrade( 598 smb_llist_t *ll) 599 { 600 uint64_t wrop; 601 602 if (rw_tryupgrade(&ll->ll_lock) != 0) { 603 return (0); 604 } 605 wrop = ll->ll_wrop; 606 rw_exit(&ll->ll_lock); 607 rw_enter(&ll->ll_lock, RW_WRITER); 608 return (wrop != ll->ll_wrop); 609 } 610 611 /* 612 * smb_llist_insert_head 613 * 614 * This function inserts the object passed a the beginning of the list. This 615 * function assumes the lock of the list has already been entered. 616 */ 617 void 618 smb_llist_insert_head( 619 smb_llist_t *ll, 620 void *obj) 621 { 622 list_insert_head(&ll->ll_list, obj); 623 ++ll->ll_wrop; 624 ++ll->ll_count; 625 } 626 627 /* 628 * smb_llist_insert_tail 629 * 630 * This function appends to the object passed to the list. This function assumes 631 * the lock of the list has already been entered. 632 * 633 */ 634 void 635 smb_llist_insert_tail( 636 smb_llist_t *ll, 637 void *obj) 638 { 639 list_insert_tail(&ll->ll_list, obj); 640 ++ll->ll_wrop; 641 ++ll->ll_count; 642 } 643 644 /* 645 * smb_llist_remove 646 * 647 * This function removes the object passed from the list. This function assumes 648 * the lock of the list has already been entered. 649 */ 650 void 651 smb_llist_remove( 652 smb_llist_t *ll, 653 void *obj) 654 { 655 list_remove(&ll->ll_list, obj); 656 ++ll->ll_wrop; 657 --ll->ll_count; 658 } 659 660 /* 661 * smb_llist_get_count 662 * 663 * This function returns the number of elements in the specified list. 664 */ 665 uint32_t 666 smb_llist_get_count( 667 smb_llist_t *ll) 668 { 669 return (ll->ll_count); 670 } 671 672 /* 673 * smb_slist_constructor 674 * 675 * Synchronized list constructor. 676 */ 677 void 678 smb_slist_constructor( 679 smb_slist_t *sl, 680 size_t size, 681 size_t offset) 682 { 683 mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL); 684 cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL); 685 list_create(&sl->sl_list, size, offset); 686 sl->sl_count = 0; 687 sl->sl_waiting = B_FALSE; 688 } 689 690 /* 691 * smb_slist_destructor 692 * 693 * Synchronized list destructor. 694 */ 695 void 696 smb_slist_destructor( 697 smb_slist_t *sl) 698 { 699 ASSERT(sl->sl_count == 0); 700 701 mutex_destroy(&sl->sl_mutex); 702 cv_destroy(&sl->sl_cv); 703 list_destroy(&sl->sl_list); 704 } 705 706 /* 707 * smb_slist_insert_head 708 * 709 * This function inserts the object passed a the beginning of the list. 710 */ 711 void 712 smb_slist_insert_head( 713 smb_slist_t *sl, 714 void *obj) 715 { 716 mutex_enter(&sl->sl_mutex); 717 list_insert_head(&sl->sl_list, obj); 718 ++sl->sl_count; 719 mutex_exit(&sl->sl_mutex); 720 } 721 722 /* 723 * smb_slist_insert_tail 724 * 725 * This function appends the object passed to the list. 726 */ 727 void 728 smb_slist_insert_tail( 729 smb_slist_t *sl, 730 void *obj) 731 { 732 mutex_enter(&sl->sl_mutex); 733 list_insert_tail(&sl->sl_list, obj); 734 ++sl->sl_count; 735 mutex_exit(&sl->sl_mutex); 736 } 737 738 /* 739 * smb_llist_remove 740 * 741 * This function removes the object passed by the caller from the list. 742 */ 743 void 744 smb_slist_remove( 745 smb_slist_t *sl, 746 void *obj) 747 { 748 mutex_enter(&sl->sl_mutex); 749 list_remove(&sl->sl_list, obj); 750 if ((--sl->sl_count == 0) && (sl->sl_waiting)) { 751 sl->sl_waiting = B_FALSE; 752 cv_broadcast(&sl->sl_cv); 753 } 754 mutex_exit(&sl->sl_mutex); 755 } 756 757 /* 758 * smb_slist_move_tail 759 * 760 * This function transfers all the contents of the synchronized list to the 761 * list_t provided. It returns the number of objects transferred. 762 */ 763 uint32_t 764 smb_slist_move_tail( 765 list_t *lst, 766 smb_slist_t *sl) 767 { 768 uint32_t rv; 769 770 mutex_enter(&sl->sl_mutex); 771 rv = sl->sl_count; 772 if (sl->sl_count) { 773 list_move_tail(lst, &sl->sl_list); 774 sl->sl_count = 0; 775 if (sl->sl_waiting) { 776 sl->sl_waiting = B_FALSE; 777 cv_broadcast(&sl->sl_cv); 778 } 779 } 780 mutex_exit(&sl->sl_mutex); 781 return (rv); 782 } 783 784 /* 785 * smb_slist_obj_move 786 * 787 * This function moves an object from one list to the end of the other list. It 788 * assumes the mutex of each list has been entered. 789 */ 790 void 791 smb_slist_obj_move( 792 smb_slist_t *dst, 793 smb_slist_t *src, 794 void *obj) 795 { 796 ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset); 797 ASSERT(dst->sl_list.list_size == src->sl_list.list_size); 798 799 list_remove(&src->sl_list, obj); 800 list_insert_tail(&dst->sl_list, obj); 801 dst->sl_count++; 802 src->sl_count--; 803 if ((src->sl_count == 0) && (src->sl_waiting)) { 804 src->sl_waiting = B_FALSE; 805 cv_broadcast(&src->sl_cv); 806 } 807 } 808 809 /* 810 * smb_slist_wait_for_empty 811 * 812 * This function waits for a list to be emptied. 813 */ 814 void 815 smb_slist_wait_for_empty( 816 smb_slist_t *sl) 817 { 818 mutex_enter(&sl->sl_mutex); 819 while (sl->sl_count) { 820 sl->sl_waiting = B_TRUE; 821 cv_wait(&sl->sl_cv, &sl->sl_mutex); 822 } 823 mutex_exit(&sl->sl_mutex); 824 } 825 826 /* 827 * smb_slist_exit 828 * 829 * This function exits the muetx of the list and signal the condition variable 830 * if the list is empty. 831 */ 832 void 833 smb_slist_exit(smb_slist_t *sl) 834 { 835 if ((sl->sl_count == 0) && (sl->sl_waiting)) { 836 sl->sl_waiting = B_FALSE; 837 cv_broadcast(&sl->sl_cv); 838 } 839 mutex_exit(&sl->sl_mutex); 840 } 841 842 /* 843 * smb_thread_entry_point 844 * 845 * Common entry point for all the threads created through smb_thread_start. 846 * The state of the thread is set to "running" at the beginning and moved to 847 * "exiting" just before calling thread_exit(). The condition variable is 848 * also signaled. 849 */ 850 static void 851 smb_thread_entry_point( 852 smb_thread_t *thread) 853 { 854 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 855 mutex_enter(&thread->sth_mtx); 856 ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING); 857 thread->sth_th = curthread; 858 thread->sth_did = thread->sth_th->t_did; 859 860 if (!thread->sth_kill) { 861 thread->sth_state = SMB_THREAD_STATE_RUNNING; 862 cv_signal(&thread->sth_cv); 863 mutex_exit(&thread->sth_mtx); 864 thread->sth_ep(thread, thread->sth_ep_arg); 865 mutex_enter(&thread->sth_mtx); 866 } 867 thread->sth_th = NULL; 868 thread->sth_state = SMB_THREAD_STATE_EXITING; 869 cv_broadcast(&thread->sth_cv); 870 mutex_exit(&thread->sth_mtx); 871 thread_exit(); 872 } 873 874 /* 875 * smb_thread_init 876 */ 877 void 878 smb_thread_init( 879 smb_thread_t *thread, 880 char *name, 881 smb_thread_ep_t ep, 882 void *ep_arg, 883 smb_thread_aw_t aw, 884 void *aw_arg) 885 { 886 ASSERT(thread->sth_magic != SMB_THREAD_MAGIC); 887 888 bzero(thread, sizeof (*thread)); 889 890 (void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name)); 891 thread->sth_ep = ep; 892 thread->sth_ep_arg = ep_arg; 893 thread->sth_aw = aw; 894 thread->sth_aw_arg = aw_arg; 895 thread->sth_state = SMB_THREAD_STATE_EXITED; 896 mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL); 897 cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL); 898 thread->sth_magic = SMB_THREAD_MAGIC; 899 } 900 901 /* 902 * smb_thread_destroy 903 */ 904 void 905 smb_thread_destroy( 906 smb_thread_t *thread) 907 { 908 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 909 ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED); 910 thread->sth_magic = 0; 911 mutex_destroy(&thread->sth_mtx); 912 cv_destroy(&thread->sth_cv); 913 } 914 915 /* 916 * smb_thread_start 917 * 918 * This function starts a thread with the parameters provided. It waits until 919 * the state of the thread has been moved to running. 920 */ 921 /*ARGSUSED*/ 922 int 923 smb_thread_start( 924 smb_thread_t *thread) 925 { 926 int rc = 0; 927 kthread_t *tmpthread; 928 929 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 930 931 mutex_enter(&thread->sth_mtx); 932 switch (thread->sth_state) { 933 case SMB_THREAD_STATE_EXITED: 934 thread->sth_state = SMB_THREAD_STATE_STARTING; 935 mutex_exit(&thread->sth_mtx); 936 tmpthread = thread_create(NULL, 0, smb_thread_entry_point, 937 thread, 0, &p0, TS_RUN, minclsyspri); 938 ASSERT(tmpthread != NULL); 939 mutex_enter(&thread->sth_mtx); 940 while (thread->sth_state == SMB_THREAD_STATE_STARTING) 941 cv_wait(&thread->sth_cv, &thread->sth_mtx); 942 if (thread->sth_state != SMB_THREAD_STATE_RUNNING) 943 rc = -1; 944 break; 945 default: 946 ASSERT(0); 947 rc = -1; 948 break; 949 } 950 mutex_exit(&thread->sth_mtx); 951 return (rc); 952 } 953 954 /* 955 * smb_thread_stop 956 * 957 * This function signals a thread to kill itself and waits until the "exiting" 958 * state has been reached. 959 */ 960 void 961 smb_thread_stop( 962 smb_thread_t *thread) 963 { 964 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 965 966 mutex_enter(&thread->sth_mtx); 967 switch (thread->sth_state) { 968 case SMB_THREAD_STATE_RUNNING: 969 case SMB_THREAD_STATE_STARTING: 970 if (!thread->sth_kill) { 971 thread->sth_kill = B_TRUE; 972 if (thread->sth_aw) 973 thread->sth_aw(thread, thread->sth_aw_arg); 974 cv_broadcast(&thread->sth_cv); 975 while (thread->sth_state != SMB_THREAD_STATE_EXITING) 976 cv_wait(&thread->sth_cv, &thread->sth_mtx); 977 mutex_exit(&thread->sth_mtx); 978 thread_join(thread->sth_did); 979 mutex_enter(&thread->sth_mtx); 980 thread->sth_state = SMB_THREAD_STATE_EXITED; 981 thread->sth_did = 0; 982 thread->sth_kill = B_FALSE; 983 cv_broadcast(&thread->sth_cv); 984 break; 985 } 986 /*FALLTHRU*/ 987 988 case SMB_THREAD_STATE_EXITING: 989 if (thread->sth_kill) { 990 while (thread->sth_state != SMB_THREAD_STATE_EXITED) 991 cv_wait(&thread->sth_cv, &thread->sth_mtx); 992 } else { 993 thread->sth_state = SMB_THREAD_STATE_EXITED; 994 thread->sth_did = 0; 995 } 996 break; 997 998 case SMB_THREAD_STATE_EXITED: 999 break; 1000 1001 default: 1002 ASSERT(0); 1003 break; 1004 } 1005 mutex_exit(&thread->sth_mtx); 1006 } 1007 1008 /* 1009 * smb_thread_signal 1010 * 1011 * This function signals a thread. 1012 */ 1013 void 1014 smb_thread_signal( 1015 smb_thread_t *thread) 1016 { 1017 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 1018 1019 mutex_enter(&thread->sth_mtx); 1020 switch (thread->sth_state) { 1021 case SMB_THREAD_STATE_RUNNING: 1022 if (thread->sth_aw) 1023 thread->sth_aw(thread, thread->sth_aw_arg); 1024 cv_signal(&thread->sth_cv); 1025 break; 1026 1027 default: 1028 break; 1029 } 1030 mutex_exit(&thread->sth_mtx); 1031 } 1032 1033 boolean_t 1034 smb_thread_continue(smb_thread_t *thread) 1035 { 1036 boolean_t result; 1037 1038 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 1039 1040 mutex_enter(&thread->sth_mtx); 1041 result = smb_thread_continue_timedwait_locked(thread, 0); 1042 mutex_exit(&thread->sth_mtx); 1043 1044 return (result); 1045 } 1046 1047 boolean_t 1048 smb_thread_continue_nowait(smb_thread_t *thread) 1049 { 1050 boolean_t result; 1051 1052 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 1053 1054 mutex_enter(&thread->sth_mtx); 1055 /* 1056 * Setting ticks=-1 requests a non-blocking check. We will 1057 * still block if the thread is in "suspend" state. 1058 */ 1059 result = smb_thread_continue_timedwait_locked(thread, -1); 1060 mutex_exit(&thread->sth_mtx); 1061 1062 return (result); 1063 } 1064 1065 boolean_t 1066 smb_thread_continue_timedwait(smb_thread_t *thread, int seconds) 1067 { 1068 boolean_t result; 1069 1070 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 1071 1072 mutex_enter(&thread->sth_mtx); 1073 result = smb_thread_continue_timedwait_locked(thread, 1074 SEC_TO_TICK(seconds)); 1075 mutex_exit(&thread->sth_mtx); 1076 1077 return (result); 1078 } 1079 1080 /* 1081 * smb_thread_continue_timedwait_locked 1082 * 1083 * Internal only. Ticks==-1 means don't block, Ticks == 0 means wait 1084 * indefinitely 1085 */ 1086 static boolean_t 1087 smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks) 1088 { 1089 boolean_t result; 1090 1091 /* -1 means don't block */ 1092 if (ticks != -1 && !thread->sth_kill) { 1093 if (ticks == 0) { 1094 cv_wait(&thread->sth_cv, &thread->sth_mtx); 1095 } else { 1096 (void) cv_reltimedwait(&thread->sth_cv, 1097 &thread->sth_mtx, (clock_t)ticks, TR_CLOCK_TICK); 1098 } 1099 } 1100 result = (thread->sth_kill == 0); 1101 1102 return (result); 1103 } 1104 1105 void 1106 smb_thread_set_awaken(smb_thread_t *thread, smb_thread_aw_t new_aw_fn, 1107 void *new_aw_arg) 1108 { 1109 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 1110 1111 mutex_enter(&thread->sth_mtx); 1112 thread->sth_aw = new_aw_fn; 1113 thread->sth_aw_arg = new_aw_arg; 1114 mutex_exit(&thread->sth_mtx); 1115 } 1116 1117 /* 1118 * smb_rwx_init 1119 */ 1120 void 1121 smb_rwx_init( 1122 smb_rwx_t *rwx) 1123 { 1124 bzero(rwx, sizeof (smb_rwx_t)); 1125 cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL); 1126 mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL); 1127 rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL); 1128 } 1129 1130 /* 1131 * smb_rwx_destroy 1132 */ 1133 void 1134 smb_rwx_destroy( 1135 smb_rwx_t *rwx) 1136 { 1137 mutex_destroy(&rwx->rwx_mutex); 1138 cv_destroy(&rwx->rwx_cv); 1139 rw_destroy(&rwx->rwx_lock); 1140 } 1141 1142 /* 1143 * smb_rwx_rwexit 1144 */ 1145 void 1146 smb_rwx_rwexit( 1147 smb_rwx_t *rwx) 1148 { 1149 if (rw_write_held(&rwx->rwx_lock)) { 1150 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1151 mutex_enter(&rwx->rwx_mutex); 1152 if (rwx->rwx_waiting) { 1153 rwx->rwx_waiting = B_FALSE; 1154 cv_broadcast(&rwx->rwx_cv); 1155 } 1156 mutex_exit(&rwx->rwx_mutex); 1157 } 1158 rw_exit(&rwx->rwx_lock); 1159 } 1160 1161 /* 1162 * smb_rwx_rwupgrade 1163 */ 1164 krw_t 1165 smb_rwx_rwupgrade( 1166 smb_rwx_t *rwx) 1167 { 1168 if (rw_write_held(&rwx->rwx_lock)) { 1169 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1170 return (RW_WRITER); 1171 } 1172 if (!rw_tryupgrade(&rwx->rwx_lock)) { 1173 rw_exit(&rwx->rwx_lock); 1174 rw_enter(&rwx->rwx_lock, RW_WRITER); 1175 } 1176 return (RW_READER); 1177 } 1178 1179 /* 1180 * smb_rwx_rwrestore 1181 */ 1182 void 1183 smb_rwx_rwdowngrade( 1184 smb_rwx_t *rwx, 1185 krw_t mode) 1186 { 1187 ASSERT(rw_write_held(&rwx->rwx_lock)); 1188 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1189 1190 if (mode == RW_WRITER) { 1191 return; 1192 } 1193 ASSERT(mode == RW_READER); 1194 mutex_enter(&rwx->rwx_mutex); 1195 if (rwx->rwx_waiting) { 1196 rwx->rwx_waiting = B_FALSE; 1197 cv_broadcast(&rwx->rwx_cv); 1198 } 1199 mutex_exit(&rwx->rwx_mutex); 1200 rw_downgrade(&rwx->rwx_lock); 1201 } 1202 1203 /* 1204 * smb_rwx_wait 1205 * 1206 * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER 1207 * mode. It will: 1208 * 1209 * 1) release the lock and save its current mode. 1210 * 2) wait until the condition variable is signaled. This can happen for 1211 * 2 reasons: When a writer releases the lock or when the time out (if 1212 * provided) expires. 1213 * 3) re-acquire the lock in the mode saved in (1). 1214 */ 1215 int 1216 smb_rwx_rwwait( 1217 smb_rwx_t *rwx, 1218 clock_t timeout) 1219 { 1220 int rc; 1221 krw_t mode; 1222 1223 mutex_enter(&rwx->rwx_mutex); 1224 rwx->rwx_waiting = B_TRUE; 1225 mutex_exit(&rwx->rwx_mutex); 1226 1227 if (rw_write_held(&rwx->rwx_lock)) { 1228 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1229 mode = RW_WRITER; 1230 } else { 1231 ASSERT(rw_read_held(&rwx->rwx_lock)); 1232 mode = RW_READER; 1233 } 1234 rw_exit(&rwx->rwx_lock); 1235 1236 mutex_enter(&rwx->rwx_mutex); 1237 if (rwx->rwx_waiting) { 1238 if (timeout == -1) { 1239 rc = 1; 1240 cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex); 1241 } else { 1242 rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex, 1243 timeout, TR_CLOCK_TICK); 1244 } 1245 } 1246 mutex_exit(&rwx->rwx_mutex); 1247 1248 rw_enter(&rwx->rwx_lock, mode); 1249 return (rc); 1250 } 1251 1252 /* 1253 * SMB ID mapping 1254 * 1255 * Solaris ID mapping service (aka Winchester) works with domain SIDs 1256 * and RIDs where domain SIDs are in string format. CIFS service works 1257 * with binary SIDs understandable by CIFS clients. A layer of SMB ID 1258 * mapping functions are implemeted to hide the SID conversion details 1259 * and also hide the handling of array of batch mapping requests. 1260 * 1261 * IMPORTANT NOTE The Winchester API requires a zone. Because CIFS server 1262 * currently only runs in the global zone the global zone is specified. 1263 * This needs to be fixed when the CIFS server supports zones. 1264 */ 1265 1266 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib); 1267 1268 /* 1269 * smb_idmap_getid 1270 * 1271 * Maps the given Windows SID to a Solaris ID using the 1272 * simple mapping API. 1273 */ 1274 idmap_stat 1275 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype) 1276 { 1277 smb_idmap_t sim; 1278 char sidstr[SMB_SID_STRSZ]; 1279 1280 smb_sid_tostr(sid, sidstr); 1281 if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0) 1282 return (IDMAP_ERR_SID); 1283 sim.sim_domsid = sidstr; 1284 sim.sim_id = id; 1285 1286 switch (*idtype) { 1287 case SMB_IDMAP_USER: 1288 sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid, 1289 sim.sim_rid, sim.sim_id); 1290 break; 1291 1292 case SMB_IDMAP_GROUP: 1293 sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid, 1294 sim.sim_rid, sim.sim_id); 1295 break; 1296 1297 case SMB_IDMAP_UNKNOWN: 1298 sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid, 1299 sim.sim_rid, sim.sim_id, &sim.sim_idtype); 1300 break; 1301 1302 default: 1303 ASSERT(0); 1304 return (IDMAP_ERR_ARG); 1305 } 1306 1307 *idtype = sim.sim_idtype; 1308 1309 return (sim.sim_stat); 1310 } 1311 1312 /* 1313 * smb_idmap_getsid 1314 * 1315 * Maps the given Solaris ID to a Windows SID using the 1316 * simple mapping API. 1317 */ 1318 idmap_stat 1319 smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid) 1320 { 1321 smb_idmap_t sim; 1322 1323 switch (idtype) { 1324 case SMB_IDMAP_USER: 1325 sim.sim_stat = kidmap_getsidbyuid(global_zone, id, 1326 (const char **)&sim.sim_domsid, &sim.sim_rid); 1327 break; 1328 1329 case SMB_IDMAP_GROUP: 1330 sim.sim_stat = kidmap_getsidbygid(global_zone, id, 1331 (const char **)&sim.sim_domsid, &sim.sim_rid); 1332 break; 1333 1334 case SMB_IDMAP_EVERYONE: 1335 /* Everyone S-1-1-0 */ 1336 sim.sim_domsid = "S-1-1"; 1337 sim.sim_rid = 0; 1338 sim.sim_stat = IDMAP_SUCCESS; 1339 break; 1340 1341 default: 1342 ASSERT(0); 1343 return (IDMAP_ERR_ARG); 1344 } 1345 1346 if (sim.sim_stat != IDMAP_SUCCESS) 1347 return (sim.sim_stat); 1348 1349 if (sim.sim_domsid == NULL) 1350 return (IDMAP_ERR_NOMAPPING); 1351 1352 sim.sim_sid = smb_sid_fromstr(sim.sim_domsid); 1353 if (sim.sim_sid == NULL) 1354 return (IDMAP_ERR_INTERNAL); 1355 1356 *sid = smb_sid_splice(sim.sim_sid, sim.sim_rid); 1357 smb_sid_free(sim.sim_sid); 1358 if (*sid == NULL) 1359 sim.sim_stat = IDMAP_ERR_INTERNAL; 1360 1361 return (sim.sim_stat); 1362 } 1363 1364 /* 1365 * smb_idmap_batch_create 1366 * 1367 * Creates and initializes the context for batch ID mapping. 1368 */ 1369 idmap_stat 1370 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags) 1371 { 1372 ASSERT(sib); 1373 1374 bzero(sib, sizeof (smb_idmap_batch_t)); 1375 1376 sib->sib_idmaph = kidmap_get_create(global_zone); 1377 1378 sib->sib_flags = flags; 1379 sib->sib_nmap = nmap; 1380 sib->sib_size = nmap * sizeof (smb_idmap_t); 1381 sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP); 1382 1383 return (IDMAP_SUCCESS); 1384 } 1385 1386 /* 1387 * smb_idmap_batch_destroy 1388 * 1389 * Frees the batch ID mapping context. 1390 * If ID mapping is Solaris -> Windows it frees memories 1391 * allocated for binary SIDs. 1392 */ 1393 void 1394 smb_idmap_batch_destroy(smb_idmap_batch_t *sib) 1395 { 1396 char *domsid; 1397 int i; 1398 1399 ASSERT(sib); 1400 ASSERT(sib->sib_maps); 1401 1402 if (sib->sib_idmaph) 1403 kidmap_get_destroy(sib->sib_idmaph); 1404 1405 if (sib->sib_flags & SMB_IDMAP_ID2SID) { 1406 /* 1407 * SIDs are allocated only when mapping 1408 * UID/GID to SIDs 1409 */ 1410 for (i = 0; i < sib->sib_nmap; i++) 1411 smb_sid_free(sib->sib_maps[i].sim_sid); 1412 } else if (sib->sib_flags & SMB_IDMAP_SID2ID) { 1413 /* 1414 * SID prefixes are allocated only when mapping 1415 * SIDs to UID/GID 1416 */ 1417 for (i = 0; i < sib->sib_nmap; i++) { 1418 domsid = sib->sib_maps[i].sim_domsid; 1419 if (domsid) 1420 smb_mem_free(domsid); 1421 } 1422 } 1423 1424 if (sib->sib_size && sib->sib_maps) 1425 kmem_free(sib->sib_maps, sib->sib_size); 1426 } 1427 1428 /* 1429 * smb_idmap_batch_getid 1430 * 1431 * Queue a request to map the given SID to a UID or GID. 1432 * 1433 * sim->sim_id should point to variable that's supposed to 1434 * hold the returned UID/GID. This needs to be setup by caller 1435 * of this function. 1436 * 1437 * If requested ID type is known, it's passed as 'idtype', 1438 * if it's unknown it'll be returned in sim->sim_idtype. 1439 */ 1440 idmap_stat 1441 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 1442 smb_sid_t *sid, int idtype) 1443 { 1444 char strsid[SMB_SID_STRSZ]; 1445 idmap_stat idm_stat; 1446 1447 ASSERT(idmaph); 1448 ASSERT(sim); 1449 ASSERT(sid); 1450 1451 smb_sid_tostr(sid, strsid); 1452 if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0) 1453 return (IDMAP_ERR_SID); 1454 sim->sim_domsid = smb_mem_strdup(strsid); 1455 1456 switch (idtype) { 1457 case SMB_IDMAP_USER: 1458 idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid, 1459 sim->sim_rid, sim->sim_id, &sim->sim_stat); 1460 break; 1461 1462 case SMB_IDMAP_GROUP: 1463 idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid, 1464 sim->sim_rid, sim->sim_id, &sim->sim_stat); 1465 break; 1466 1467 case SMB_IDMAP_UNKNOWN: 1468 idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid, 1469 sim->sim_rid, sim->sim_id, &sim->sim_idtype, 1470 &sim->sim_stat); 1471 break; 1472 1473 default: 1474 ASSERT(0); 1475 return (IDMAP_ERR_ARG); 1476 } 1477 1478 return (idm_stat); 1479 } 1480 1481 /* 1482 * smb_idmap_batch_getsid 1483 * 1484 * Queue a request to map the given UID/GID to a SID. 1485 * 1486 * sim->sim_domsid and sim->sim_rid will contain the mapping 1487 * result upon successful process of the batched request. 1488 */ 1489 idmap_stat 1490 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 1491 uid_t id, int idtype) 1492 { 1493 idmap_stat idm_stat; 1494 1495 switch (idtype) { 1496 case SMB_IDMAP_USER: 1497 idm_stat = kidmap_batch_getsidbyuid(idmaph, id, 1498 (const char **)&sim->sim_domsid, &sim->sim_rid, 1499 &sim->sim_stat); 1500 break; 1501 1502 case SMB_IDMAP_GROUP: 1503 idm_stat = kidmap_batch_getsidbygid(idmaph, id, 1504 (const char **)&sim->sim_domsid, &sim->sim_rid, 1505 &sim->sim_stat); 1506 break; 1507 1508 case SMB_IDMAP_OWNERAT: 1509 /* Current Owner S-1-5-32-766 */ 1510 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR; 1511 sim->sim_rid = SECURITY_CURRENT_OWNER_RID; 1512 sim->sim_stat = IDMAP_SUCCESS; 1513 idm_stat = IDMAP_SUCCESS; 1514 break; 1515 1516 case SMB_IDMAP_GROUPAT: 1517 /* Current Group S-1-5-32-767 */ 1518 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR; 1519 sim->sim_rid = SECURITY_CURRENT_GROUP_RID; 1520 sim->sim_stat = IDMAP_SUCCESS; 1521 idm_stat = IDMAP_SUCCESS; 1522 break; 1523 1524 case SMB_IDMAP_EVERYONE: 1525 /* Everyone S-1-1-0 */ 1526 sim->sim_domsid = NT_WORLD_AUTH_SIDSTR; 1527 sim->sim_rid = 0; 1528 sim->sim_stat = IDMAP_SUCCESS; 1529 idm_stat = IDMAP_SUCCESS; 1530 break; 1531 1532 default: 1533 ASSERT(0); 1534 return (IDMAP_ERR_ARG); 1535 } 1536 1537 return (idm_stat); 1538 } 1539 1540 /* 1541 * smb_idmap_batch_binsid 1542 * 1543 * Convert sidrids to binary sids 1544 * 1545 * Returns 0 if successful and non-zero upon failure. 1546 */ 1547 static int 1548 smb_idmap_batch_binsid(smb_idmap_batch_t *sib) 1549 { 1550 smb_sid_t *sid; 1551 smb_idmap_t *sim; 1552 int i; 1553 1554 if (sib->sib_flags & SMB_IDMAP_SID2ID) 1555 /* This operation is not required */ 1556 return (0); 1557 1558 sim = sib->sib_maps; 1559 for (i = 0; i < sib->sib_nmap; sim++, i++) { 1560 ASSERT(sim->sim_domsid); 1561 if (sim->sim_domsid == NULL) 1562 return (1); 1563 1564 if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL) 1565 return (1); 1566 1567 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid); 1568 smb_sid_free(sid); 1569 } 1570 1571 return (0); 1572 } 1573 1574 /* 1575 * smb_idmap_batch_getmappings 1576 * 1577 * trigger ID mapping service to get the mappings for queued 1578 * requests. 1579 * 1580 * Checks the result of all the queued requests. 1581 * If this is a Solaris -> Windows mapping it generates 1582 * binary SIDs from returned (domsid, rid) pairs. 1583 */ 1584 idmap_stat 1585 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib) 1586 { 1587 idmap_stat idm_stat = IDMAP_SUCCESS; 1588 int i; 1589 1590 idm_stat = kidmap_get_mappings(sib->sib_idmaph); 1591 if (idm_stat != IDMAP_SUCCESS) 1592 return (idm_stat); 1593 1594 /* 1595 * Check the status for all the queued requests 1596 */ 1597 for (i = 0; i < sib->sib_nmap; i++) { 1598 if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) 1599 return (sib->sib_maps[i].sim_stat); 1600 } 1601 1602 if (smb_idmap_batch_binsid(sib) != 0) 1603 idm_stat = IDMAP_ERR_OTHER; 1604 1605 return (idm_stat); 1606 } 1607 1608 uint64_t 1609 smb_time_unix_to_nt(timestruc_t *unix_time) 1610 { 1611 uint64_t nt_time; 1612 1613 if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0)) 1614 return (0); 1615 1616 nt_time = unix_time->tv_sec; 1617 nt_time *= 10000000; /* seconds to 100ns */ 1618 nt_time += unix_time->tv_nsec / 100; 1619 return (nt_time + NT_TIME_BIAS); 1620 } 1621 1622 void 1623 smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time) 1624 { 1625 uint32_t seconds; 1626 1627 ASSERT(unix_time); 1628 1629 if ((nt_time == 0) || (nt_time == -1)) { 1630 unix_time->tv_sec = 0; 1631 unix_time->tv_nsec = 0; 1632 return; 1633 } 1634 1635 nt_time -= NT_TIME_BIAS; 1636 seconds = nt_time / 10000000; 1637 unix_time->tv_sec = seconds; 1638 unix_time->tv_nsec = (nt_time % 10000000) * 100; 1639 } 1640 1641 /* 1642 * smb_time_gmt_to_local, smb_time_local_to_gmt 1643 * 1644 * Apply the gmt offset to convert between local time and gmt 1645 */ 1646 int32_t 1647 smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt) 1648 { 1649 if ((gmt == 0) || (gmt == -1)) 1650 return (0); 1651 1652 return (gmt - sr->sr_gmtoff); 1653 } 1654 1655 int32_t 1656 smb_time_local_to_gmt(smb_request_t *sr, int32_t local) 1657 { 1658 if ((local == 0) || (local == -1)) 1659 return (0); 1660 1661 return (local + sr->sr_gmtoff); 1662 } 1663 1664 1665 /* 1666 * smb_time_dos_to_unix 1667 * 1668 * Convert SMB_DATE & SMB_TIME values to a unix timestamp. 1669 * 1670 * A date/time field of 0 means that that server file system 1671 * assigned value need not be changed. The behaviour when the 1672 * date/time field is set to -1 is not documented but is 1673 * generally treated like 0. 1674 * If date or time is 0 or -1 the unix time is returned as 0 1675 * so that the caller can identify and handle this special case. 1676 */ 1677 int32_t 1678 smb_time_dos_to_unix(int16_t date, int16_t time) 1679 { 1680 struct tm atm; 1681 1682 if (((date == 0) || (time == 0)) || 1683 ((date == -1) || (time == -1))) { 1684 return (0); 1685 } 1686 1687 atm.tm_year = ((date >> 9) & 0x3F) + 80; 1688 atm.tm_mon = ((date >> 5) & 0x0F) - 1; 1689 atm.tm_mday = ((date >> 0) & 0x1F); 1690 atm.tm_hour = ((time >> 11) & 0x1F); 1691 atm.tm_min = ((time >> 5) & 0x3F); 1692 atm.tm_sec = ((time >> 0) & 0x1F) << 1; 1693 1694 return (smb_timegm(&atm)); 1695 } 1696 1697 void 1698 smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p) 1699 { 1700 struct tm atm; 1701 int i; 1702 time_t tmp_time; 1703 1704 if (ux_time == 0) { 1705 *date_p = 0; 1706 *time_p = 0; 1707 return; 1708 } 1709 1710 tmp_time = (time_t)ux_time; 1711 (void) smb_gmtime_r(&tmp_time, &atm); 1712 1713 if (date_p) { 1714 i = 0; 1715 i += atm.tm_year - 80; 1716 i <<= 4; 1717 i += atm.tm_mon + 1; 1718 i <<= 5; 1719 i += atm.tm_mday; 1720 1721 *date_p = (short)i; 1722 } 1723 if (time_p) { 1724 i = 0; 1725 i += atm.tm_hour; 1726 i <<= 6; 1727 i += atm.tm_min; 1728 i <<= 5; 1729 i += atm.tm_sec >> 1; 1730 1731 *time_p = (short)i; 1732 } 1733 } 1734 1735 1736 /* 1737 * smb_gmtime_r 1738 * 1739 * Thread-safe version of smb_gmtime. Returns a null pointer if either 1740 * input parameter is a null pointer. Otherwise returns a pointer 1741 * to result. 1742 * 1743 * Day of the week calculation: the Epoch was a thursday. 1744 * 1745 * There are no timezone corrections so tm_isdst and tm_gmtoff are 1746 * always zero, and the zone is always WET. 1747 */ 1748 struct tm * 1749 smb_gmtime_r(time_t *clock, struct tm *result) 1750 { 1751 time_t tsec; 1752 int year; 1753 int month; 1754 int sec_per_month; 1755 1756 if (clock == 0 || result == 0) 1757 return (0); 1758 1759 bzero(result, sizeof (struct tm)); 1760 tsec = *clock; 1761 tsec -= tzh_leapcnt; 1762 1763 result->tm_wday = tsec / SECSPERDAY; 1764 result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK; 1765 1766 year = EPOCH_YEAR; 1767 while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) : 1768 (SECSPERDAY * DAYSPERNYEAR))) { 1769 if (isleap(year)) 1770 tsec -= SECSPERDAY * DAYSPERLYEAR; 1771 else 1772 tsec -= SECSPERDAY * DAYSPERNYEAR; 1773 1774 ++year; 1775 } 1776 1777 result->tm_year = year - TM_YEAR_BASE; 1778 result->tm_yday = tsec / SECSPERDAY; 1779 1780 for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) { 1781 sec_per_month = days_in_month[month] * SECSPERDAY; 1782 1783 if (month == TM_FEBRUARY && isleap(year)) 1784 sec_per_month += SECSPERDAY; 1785 1786 if (tsec < sec_per_month) 1787 break; 1788 1789 tsec -= sec_per_month; 1790 } 1791 1792 result->tm_mon = month; 1793 result->tm_mday = (tsec / SECSPERDAY) + 1; 1794 tsec %= SECSPERDAY; 1795 result->tm_sec = tsec % 60; 1796 tsec /= 60; 1797 result->tm_min = tsec % 60; 1798 tsec /= 60; 1799 result->tm_hour = (int)tsec; 1800 1801 return (result); 1802 } 1803 1804 1805 /* 1806 * smb_timegm 1807 * 1808 * Converts the broken-down time in tm to a time value, i.e. the number 1809 * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is 1810 * not a POSIX or ANSI function. Per the man page, the input values of 1811 * tm_wday and tm_yday are ignored and, as the input data is assumed to 1812 * represent GMT, we force tm_isdst and tm_gmtoff to 0. 1813 * 1814 * Before returning the clock time, we use smb_gmtime_r to set up tm_wday 1815 * and tm_yday, and bring the other fields within normal range. I don't 1816 * think this is really how it should be done but it's convenient for 1817 * now. 1818 */ 1819 time_t 1820 smb_timegm(struct tm *tm) 1821 { 1822 time_t tsec; 1823 int dd; 1824 int mm; 1825 int yy; 1826 int year; 1827 1828 if (tm == 0) 1829 return (-1); 1830 1831 year = tm->tm_year + TM_YEAR_BASE; 1832 tsec = tzh_leapcnt; 1833 1834 for (yy = EPOCH_YEAR; yy < year; ++yy) { 1835 if (isleap(yy)) 1836 tsec += SECSPERDAY * DAYSPERLYEAR; 1837 else 1838 tsec += SECSPERDAY * DAYSPERNYEAR; 1839 } 1840 1841 for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) { 1842 dd = days_in_month[mm] * SECSPERDAY; 1843 1844 if (mm == TM_FEBRUARY && isleap(year)) 1845 dd += SECSPERDAY; 1846 1847 tsec += dd; 1848 } 1849 1850 tsec += (tm->tm_mday - 1) * SECSPERDAY; 1851 tsec += tm->tm_sec; 1852 tsec += tm->tm_min * SECSPERMIN; 1853 tsec += tm->tm_hour * SECSPERHOUR; 1854 1855 tm->tm_isdst = 0; 1856 (void) smb_gmtime_r(&tsec, tm); 1857 return (tsec); 1858 } 1859 1860 /* 1861 * smb_cred_set_sid 1862 * 1863 * Initialize the ksid based on the given smb_id_t. 1864 */ 1865 static void 1866 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid) 1867 { 1868 char sidstr[SMB_SID_STRSZ]; 1869 int rc; 1870 1871 ASSERT(id); 1872 ASSERT(id->i_sid); 1873 1874 ksid->ks_id = id->i_id; 1875 smb_sid_tostr(id->i_sid, sidstr); 1876 rc = smb_sid_splitstr(sidstr, &ksid->ks_rid); 1877 ASSERT(rc == 0); 1878 1879 ksid->ks_attr = id->i_attrs; 1880 ksid->ks_domain = ksid_lookupdomain(sidstr); 1881 } 1882 1883 /* 1884 * smb_cred_set_sidlist 1885 * 1886 * Allocate and initialize the ksidlist based on the Windows group list of the 1887 * access token. 1888 */ 1889 static ksidlist_t * 1890 smb_cred_set_sidlist(smb_ids_t *token_grps) 1891 { 1892 int i; 1893 ksidlist_t *lp; 1894 1895 lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP); 1896 lp->ksl_ref = 1; 1897 lp->ksl_nsid = token_grps->i_cnt; 1898 lp->ksl_neid = 0; 1899 1900 for (i = 0; i < lp->ksl_nsid; i++) { 1901 smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]); 1902 if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID) 1903 lp->ksl_neid++; 1904 } 1905 1906 return (lp); 1907 } 1908 1909 /* 1910 * A Solaris credential (cred_t structure) will be allocated and 1911 * initialized based on the given Windows style user access token. 1912 * 1913 * cred's gid is set to the primary group of the mapped Solaris user. 1914 * When there is no such mapped user (i.e. the mapped UID is ephemeral) 1915 * or his/her primary group could not be obtained, cred's gid is set to 1916 * the mapped Solaris group of token's primary group. 1917 */ 1918 cred_t * 1919 smb_cred_create(smb_token_t *token, uint32_t *privileges) 1920 { 1921 ksid_t ksid; 1922 ksidlist_t *ksidlist = NULL; 1923 smb_posix_grps_t *posix_grps; 1924 cred_t *cr; 1925 gid_t gid; 1926 1927 ASSERT(token); 1928 ASSERT(token->tkn_posix_grps); 1929 posix_grps = token->tkn_posix_grps; 1930 1931 ASSERT(privileges); 1932 1933 cr = crget(); 1934 ASSERT(cr != NULL); 1935 1936 if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) && 1937 (posix_grps->pg_ngrps != 0)) { 1938 gid = posix_grps->pg_grps[0]; 1939 } else { 1940 gid = token->tkn_primary_grp.i_id; 1941 } 1942 1943 if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) { 1944 crfree(cr); 1945 return (NULL); 1946 } 1947 1948 if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) { 1949 crfree(cr); 1950 return (NULL); 1951 } 1952 1953 smb_cred_set_sid(&token->tkn_user, &ksid); 1954 crsetsid(cr, &ksid, KSID_USER); 1955 smb_cred_set_sid(&token->tkn_primary_grp, &ksid); 1956 crsetsid(cr, &ksid, KSID_GROUP); 1957 smb_cred_set_sid(&token->tkn_owner, &ksid); 1958 crsetsid(cr, &ksid, KSID_OWNER); 1959 ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps); 1960 crsetsidlist(cr, ksidlist); 1961 1962 *privileges = 0; 1963 1964 if (smb_token_query_privilege(token, SE_BACKUP_LUID)) 1965 *privileges |= SMB_USER_PRIV_BACKUP; 1966 1967 if (smb_token_query_privilege(token, SE_RESTORE_LUID)) 1968 *privileges |= SMB_USER_PRIV_RESTORE; 1969 1970 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) { 1971 *privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP; 1972 (void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL); 1973 } 1974 1975 if (smb_token_query_privilege(token, SE_SECURITY_LUID)) 1976 *privileges |= SMB_USER_PRIV_SECURITY; 1977 1978 return (cr); 1979 } 1980 1981 /* 1982 * smb_cred_rele 1983 * 1984 * The reference count of the user's credential will get decremented if it 1985 * is non-zero. Otherwise, the credential will be freed. 1986 */ 1987 void 1988 smb_cred_rele(cred_t *cr) 1989 { 1990 ASSERT(cr); 1991 crfree(cr); 1992 } 1993 1994 /* 1995 * smb_cred_is_member 1996 * 1997 * Same as smb_token_is_member. The only difference is that 1998 * we compare the given SID against user SID and the ksidlist 1999 * of the user's cred. 2000 */ 2001 int 2002 smb_cred_is_member(cred_t *cr, smb_sid_t *sid) 2003 { 2004 ksidlist_t *ksidlist; 2005 ksid_t ksid1, *ksid2; 2006 smb_id_t id; 2007 int i, rc = 0; 2008 2009 ASSERT(cr); 2010 2011 bzero(&id, sizeof (smb_id_t)); 2012 id.i_sid = sid; 2013 smb_cred_set_sid(&id, &ksid1); 2014 2015 ksidlist = crgetsidlist(cr); 2016 ASSERT(ksidlist); 2017 ASSERT(ksid1.ks_domain); 2018 ASSERT(ksid1.ks_domain->kd_name); 2019 2020 i = 0; 2021 ksid2 = crgetsid(cr, KSID_USER); 2022 do { 2023 ASSERT(ksid2->ks_domain); 2024 ASSERT(ksid2->ks_domain->kd_name); 2025 2026 if (strcmp(ksid1.ks_domain->kd_name, 2027 ksid2->ks_domain->kd_name) == 0 && 2028 ksid1.ks_rid == ksid2->ks_rid) { 2029 rc = 1; 2030 break; 2031 } 2032 2033 ksid2 = &ksidlist->ksl_sids[i]; 2034 } while (i++ < ksidlist->ksl_nsid); 2035 2036 ksid_rele(&ksid1); 2037 return (rc); 2038 } 2039 2040 /* 2041 * smb_cred_create_privs 2042 * 2043 * Creates a duplicate credential that contains system privileges for 2044 * certain SMB privileges: Backup and Restore. 2045 * 2046 */ 2047 cred_t * 2048 smb_cred_create_privs(cred_t *user_cr, uint32_t privileges) 2049 { 2050 cred_t *cr = NULL; 2051 2052 ASSERT(user_cr != NULL); 2053 2054 if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE)) 2055 cr = crdup(user_cr); 2056 2057 if (cr == NULL) 2058 return (NULL); 2059 2060 if (privileges & SMB_USER_PRIV_BACKUP) { 2061 (void) crsetpriv(cr, PRIV_FILE_DAC_READ, 2062 PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL); 2063 } 2064 2065 if (privileges & SMB_USER_PRIV_RESTORE) { 2066 (void) crsetpriv(cr, PRIV_FILE_DAC_WRITE, 2067 PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF, 2068 PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY, 2069 PRIV_FILE_OWNER, PRIV_FILE_SETID, PRIV_SYS_LINKDIR, 2070 PRIV_SYS_MOUNT, NULL); 2071 } 2072 2073 return (cr); 2074 } 2075 2076 /* 2077 * smb_pad_align 2078 * 2079 * Returns the number of bytes required to pad an offset to the 2080 * specified alignment. 2081 */ 2082 uint32_t 2083 smb_pad_align(uint32_t offset, uint32_t align) 2084 { 2085 uint32_t pad = offset % align; 2086 2087 if (pad != 0) 2088 pad = align - pad; 2089 2090 return (pad); 2091 } 2092 2093 /* 2094 * smb_panic 2095 * 2096 * Logs the file name, function name and line number passed in and panics the 2097 * system. 2098 */ 2099 void 2100 smb_panic(char *file, const char *func, int line) 2101 { 2102 cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line); 2103 } 2104