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