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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * General Structures Layout 28 * ------------------------- 29 * 30 * This is a simplified diagram showing the relationship between most of the 31 * main structures. 32 * 33 * +-------------------+ 34 * | SMB_INFO | 35 * +-------------------+ 36 * | 37 * | 38 * v 39 * +-------------------+ +-------------------+ +-------------------+ 40 * | SESSION |<----->| SESSION |......| SESSION | 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | 43 * | 44 * v 45 * +-------------------+ +-------------------+ +-------------------+ 46 * | USER |<----->| USER |......| USER | 47 * +-------------------+ +-------------------+ +-------------------+ 48 * | 49 * | 50 * v 51 * +-------------------+ +-------------------+ +-------------------+ 52 * | TREE |<----->| TREE |......| TREE | 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | | 55 * | | 56 * | v 57 * | +-------+ +-------+ +-------+ 58 * | | OFILE |<----->| OFILE |......| OFILE | 59 * | +-------+ +-------+ +-------+ 60 * | 61 * | 62 * v 63 * +-------+ +------+ +------+ 64 * | ODIR |<----->| ODIR |......| ODIR | 65 * +-------+ +------+ +------+ 66 * 67 * 68 * Tree State Machine 69 * ------------------ 70 * 71 * +-----------------------------+ T0 72 * | SMB_TREE_STATE_CONNECTED |<----------- Creation/Allocation 73 * +-----------------------------+ 74 * | 75 * | T1 76 * | 77 * v 78 * +------------------------------+ 79 * | SMB_TREE_STATE_DISCONNECTING | 80 * +------------------------------+ 81 * | 82 * | T2 83 * | 84 * v 85 * +-----------------------------+ T3 86 * | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free 87 * +-----------------------------+ 88 * 89 * SMB_TREE_STATE_CONNECTED 90 * 91 * While in this state: 92 * - The tree is queued in the list of trees of its user. 93 * - References will be given out if the tree is looked up. 94 * - Files under that tree can be accessed. 95 * 96 * SMB_TREE_STATE_DISCONNECTING 97 * 98 * While in this state: 99 * - The tree is queued in the list of trees of its user. 100 * - References will not be given out if the tree is looked up. 101 * - The files and directories open under the tree are being closed. 102 * - The resources associated with the tree remain. 103 * 104 * SMB_TREE_STATE_DISCONNECTED 105 * 106 * While in this state: 107 * - The tree is queued in the list of trees of its user. 108 * - References will not be given out if the tree is looked up. 109 * - The tree has no more files and directories opened. 110 * - The resources associated with the tree remain. 111 * 112 * Transition T0 113 * 114 * This transition occurs in smb_tree_connect(). A new tree is created and 115 * added to the list of trees of a user. 116 * 117 * Transition T1 118 * 119 * This transition occurs in smb_tree_disconnect(). 120 * 121 * Transition T2 122 * 123 * This transition occurs in smb_tree_release(). The resources associated 124 * with the tree are freed as well as the tree structure. For the transition 125 * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and 126 * the reference count be zero. 127 * 128 * Comments 129 * -------- 130 * 131 * The state machine of the tree structures is controlled by 3 elements: 132 * - The list of trees of the user it belongs to. 133 * - The mutex embedded in the structure itself. 134 * - The reference count. 135 * 136 * There's a mutex embedded in the tree structure used to protect its fields 137 * and there's a lock embedded in the list of trees of a user. To 138 * increment or to decrement the reference count the mutex must be entered. 139 * To insert the tree into the list of trees of the user and to remove 140 * the tree from it, the lock must be entered in RW_WRITER mode. 141 * 142 * Rules of access to a tree structure: 143 * 144 * 1) In order to avoid deadlocks, when both (mutex and lock of the user 145 * list) have to be entered, the lock must be entered first. 146 * 147 * 2) All actions applied to a tree require a reference count. 148 * 149 * 3) There are 2 ways of getting a reference count: when a tree is 150 * connected and when a tree is looked up. 151 * 152 * It should be noted that the reference count of a tree registers the 153 * number of references to the tree in other structures (such as an smb 154 * request). The reference count is not incremented in these 2 instances: 155 * 156 * 1) The tree is connected. An tree is anchored by his state. If there's 157 * no activity involving a tree currently connected, the reference 158 * count of that tree is zero. 159 * 160 * 2) The tree is queued in the list of trees of the user. The fact of 161 * being queued in that list is NOT registered by incrementing the 162 * reference count. 163 */ 164 #include <sys/types.h> 165 #include <sys/refstr_impl.h> 166 #include <sys/feature_tests.h> 167 #include <sys/sunddi.h> 168 #include <sys/fsid.h> 169 #include <sys/vfs.h> 170 #include <sys/stat.h> 171 #include <sys/varargs.h> 172 #include <smbsrv/smb_incl.h> 173 #include <smbsrv/lmerr.h> 174 #include <smbsrv/smb_fsops.h> 175 #include <smbsrv/smb_door_svc.h> 176 #include <smbsrv/smb_share.h> 177 178 int smb_tcon_mute = 0; 179 180 static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *); 181 static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *); 182 static smb_tree_t *smb_tree_alloc(smb_user_t *, const char *, const char *, 183 int32_t, smb_node_t *); 184 static void smb_tree_dealloc(smb_tree_t *); 185 static boolean_t smb_tree_is_connected(smb_tree_t *); 186 static boolean_t smb_tree_is_disconnected(smb_tree_t *); 187 static const char *smb_tree_get_sharename(const char *); 188 static int smb_tree_get_stype(const char *, const char *, int32_t *); 189 static int smb_tree_getattr(smb_node_t *, smb_tree_t *); 190 static void smb_tree_get_volname(vfs_t *, smb_tree_t *); 191 static void smb_tree_get_flags(vfs_t *, smb_tree_t *); 192 static void smb_tree_log(smb_request_t *, const char *, const char *, ...); 193 194 /* 195 * Extract the share name and share type and connect as appropriate. 196 * Share names are case insensitive so we map the share name to 197 * lower-case as a convenience for internal processing. 198 */ 199 smb_tree_t * 200 smb_tree_connect(smb_request_t *sr) 201 { 202 char *unc_path = sr->arg.tcon.path; 203 char *service = sr->arg.tcon.service; 204 smb_tree_t *tree = NULL; 205 const char *name; 206 int32_t stype; 207 208 (void) utf8_strlwr(unc_path); 209 210 if ((name = smb_tree_get_sharename(unc_path)) == NULL) { 211 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 212 return (NULL); 213 } 214 215 if (smb_tree_get_stype(name, service, &stype) != 0) { 216 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, 217 ERRDOS, ERROR_BAD_DEV_TYPE); 218 return (NULL); 219 } 220 221 switch (stype & STYPE_MASK) { 222 case STYPE_DISKTREE: 223 tree = smb_tree_connect_disk(sr, name); 224 break; 225 226 case STYPE_IPC: 227 tree = smb_tree_connect_ipc(sr, name); 228 break; 229 230 default: 231 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, 232 ERRDOS, ERROR_BAD_DEV_TYPE); 233 break; 234 } 235 236 return (tree); 237 } 238 239 /* 240 * Disconnect a tree. 241 */ 242 void 243 smb_tree_disconnect( 244 smb_tree_t *tree) 245 { 246 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 247 248 mutex_enter(&tree->t_mutex); 249 ASSERT(tree->t_refcnt); 250 251 if (smb_tree_is_connected(tree)) { 252 /* 253 * Indicate that the disconnect process has started. 254 */ 255 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 256 mutex_exit(&tree->t_mutex); 257 atomic_dec_32(&tree->t_server->sv_open_trees); 258 259 /* 260 * The files opened under this tree are closed. 261 */ 262 smb_ofile_close_all(tree); 263 /* 264 * The directories opened under this tree are closed. 265 */ 266 smb_odir_close_all(tree); 267 mutex_enter(&tree->t_mutex); 268 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 269 } 270 271 mutex_exit(&tree->t_mutex); 272 } 273 274 /* 275 * Take a reference on a tree. 276 */ 277 boolean_t 278 smb_tree_hold( 279 smb_tree_t *tree) 280 { 281 ASSERT(tree); 282 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 283 284 mutex_enter(&tree->t_mutex); 285 286 if (smb_tree_is_connected(tree)) { 287 tree->t_refcnt++; 288 mutex_exit(&tree->t_mutex); 289 return (B_TRUE); 290 } 291 292 mutex_exit(&tree->t_mutex); 293 return (B_FALSE); 294 } 295 296 /* 297 * Release a reference on a tree. If the tree is disconnected and the 298 * reference count falls to zero, the tree will be deallocated. 299 */ 300 void 301 smb_tree_release( 302 smb_tree_t *tree) 303 { 304 ASSERT(tree); 305 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 306 307 mutex_enter(&tree->t_mutex); 308 ASSERT(tree->t_refcnt); 309 tree->t_refcnt--; 310 311 if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0)) { 312 mutex_exit(&tree->t_mutex); 313 smb_tree_dealloc(tree); 314 return; 315 } 316 317 mutex_exit(&tree->t_mutex); 318 } 319 320 /* 321 * Close ofiles and odirs that match pid. 322 */ 323 void 324 smb_tree_close_pid( 325 smb_tree_t *tree, 326 uint16_t pid) 327 { 328 ASSERT(tree); 329 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 330 331 smb_ofile_close_all_by_pid(tree, pid); 332 smb_odir_close_all_by_pid(tree, pid); 333 } 334 335 /* 336 * Check whether or not a tree supports the features identified by flags. 337 */ 338 boolean_t 339 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags) 340 { 341 ASSERT(tree); 342 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 343 344 return ((tree->t_flags & flags) == flags); 345 } 346 347 /* *************************** Static Functions ***************************** */ 348 349 /* 350 * Connect a share for use with files and directories. 351 */ 352 static smb_tree_t * 353 smb_tree_connect_disk(smb_request_t *sr, const char *sharename) 354 { 355 smb_user_t *user = sr->uid_user; 356 smb_node_t *dir_snode = NULL; 357 smb_node_t *snode = NULL; 358 char last_component[MAXNAMELEN]; 359 smb_tree_t *tree; 360 smb_share_t *si; 361 smb_attr_t attr; 362 cred_t *u_cred; 363 int rc; 364 uint32_t access = 0; /* read/write is assumed */ 365 uint32_t hostaccess; 366 367 ASSERT(user); 368 u_cred = user->u_cred; 369 ASSERT(u_cred); 370 371 if (user->u_flags & SMB_USER_FLAG_IPC) { 372 smb_tree_log(sr, sharename, "access denied: IPC only"); 373 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 374 return (NULL); 375 } 376 377 si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP); 378 379 if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si, 380 sr->session->ipaddr) != NERR_Success) { 381 smb_tree_log(sr, sharename, "share not found"); 382 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 383 kmem_free(si, sizeof (smb_share_t)); 384 return (NULL); 385 } 386 387 /* 388 * Handle the default administration shares: C$, D$ etc. 389 * Only a user with admin rights is allowed to map these 390 * shares. 391 */ 392 if (si->shr_flags & SMB_SHRF_ADMIN) { 393 if (!smb_user_is_admin(user)) { 394 smb_tree_log(sr, sharename, "access denied: not admin"); 395 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 396 ERRSRV, ERRaccess); 397 kmem_free(si, sizeof (smb_share_t)); 398 return (NULL); 399 } 400 } 401 402 /* 403 * Set up the OptionalSupport for this share. 404 */ 405 sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS; 406 407 switch (si->shr_flags & SMB_SHRF_CSC_MASK) { 408 case SMB_SHRF_CSC_DISABLED: 409 sr->arg.tcon.optional_support |= SMB_CSC_CACHE_NONE; 410 break; 411 case SMB_SHRF_CSC_AUTO: 412 sr->arg.tcon.optional_support |= SMB_CSC_CACHE_AUTO_REINT; 413 break; 414 case SMB_SHRF_CSC_VDO: 415 sr->arg.tcon.optional_support |= SMB_CSC_CACHE_VDO; 416 break; 417 case SMB_SHRF_CSC_MANUAL: 418 default: 419 /* 420 * Default to SMB_CSC_CACHE_MANUAL_REINT. 421 */ 422 break; 423 } 424 425 hostaccess = si->shr_access_value & SMB_SHRF_ACC_ALL; 426 427 if (hostaccess == SMB_SHRF_ACC_RO) { 428 access = SMB_TREE_READONLY; 429 } else if (hostaccess == SMB_SHRF_ACC_NONE) { 430 kmem_free(si, sizeof (smb_share_t)); 431 smb_tree_log(sr, sharename, "access denied: host access"); 432 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 433 return (NULL); 434 } 435 436 /* 437 * Check that the shared directory exists. 438 */ 439 rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode, 440 last_component); 441 442 if (rc == 0) { 443 rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS, 0, 444 dir_snode, last_component, &snode, &attr, 0, 0); 445 446 smb_node_release(dir_snode); 447 } 448 449 if (rc) { 450 if (snode) 451 smb_node_release(snode); 452 453 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); 454 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 455 kmem_free(si, sizeof (smb_share_t)); 456 return (NULL); 457 } 458 459 tree = smb_tree_alloc(user, sharename, si->shr_path, STYPE_DISKTREE, 460 snode); 461 462 if (tree == NULL) 463 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 464 else 465 tree->t_flags |= access; 466 467 smb_node_release(snode); 468 kmem_free(si, sizeof (smb_share_t)); 469 return (tree); 470 } 471 472 /* 473 * Connect an IPC share for use with named pipes. 474 */ 475 static smb_tree_t * 476 smb_tree_connect_ipc(smb_request_t *sr, const char *name) 477 { 478 smb_user_t *user = sr->uid_user; 479 smb_tree_t *tree; 480 481 ASSERT(user); 482 483 if ((user->u_flags & SMB_USER_FLAG_IPC) && 484 sr->sr_cfg->skc_restrict_anon) { 485 smb_tree_log(sr, name, "access denied: restrict anonymous"); 486 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 487 return (NULL); 488 } 489 490 sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS; 491 492 tree = smb_tree_alloc(user, name, name, STYPE_IPC, NULL); 493 if (tree == NULL) { 494 smb_tree_log(sr, name, "access denied"); 495 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 496 } 497 498 return (tree); 499 } 500 501 /* 502 * Allocate a tree. 503 */ 504 static smb_tree_t * 505 smb_tree_alloc( 506 smb_user_t *user, 507 const char *sharename, 508 const char *resource, 509 int32_t stype, 510 smb_node_t *snode) 511 { 512 smb_tree_t *tree; 513 uint16_t tid; 514 515 if (smb_idpool_alloc(&user->u_tid_pool, &tid)) 516 return (NULL); 517 518 tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP); 519 bzero(tree, sizeof (smb_tree_t)); 520 521 if (STYPE_ISDSK(stype)) { 522 if (smb_tree_getattr(snode, tree) != 0) { 523 smb_idpool_free(&user->u_tid_pool, tid); 524 kmem_cache_free(user->u_server->si_cache_tree, tree); 525 return (NULL); 526 } 527 } 528 529 if (smb_idpool_constructor(&tree->t_fid_pool)) { 530 smb_idpool_free(&user->u_tid_pool, tid); 531 kmem_cache_free(user->u_server->si_cache_tree, tree); 532 return (NULL); 533 } 534 535 if (smb_idpool_constructor(&tree->t_sid_pool)) { 536 smb_idpool_destructor(&tree->t_fid_pool); 537 smb_idpool_free(&user->u_tid_pool, tid); 538 kmem_cache_free(user->u_server->si_cache_tree, tree); 539 return (NULL); 540 } 541 542 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), 543 offsetof(smb_ofile_t, f_lnd)); 544 545 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), 546 offsetof(smb_odir_t, d_lnd)); 547 548 (void) strlcpy(tree->t_sharename, sharename, 549 sizeof (tree->t_sharename)); 550 (void) strlcpy(tree->t_resource, resource, sizeof (tree->t_resource)); 551 552 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); 553 554 tree->t_user = user; 555 tree->t_session = user->u_session; 556 tree->t_server = user->u_server; 557 tree->t_refcnt = 1; 558 tree->t_tid = tid; 559 tree->t_res_type = stype; 560 tree->t_state = SMB_TREE_STATE_CONNECTED; 561 tree->t_magic = SMB_TREE_MAGIC; 562 563 if (STYPE_ISDSK(stype)) { 564 smb_node_ref(snode); 565 tree->t_snode = snode; 566 tree->t_acltype = smb_fsop_acltype(snode); 567 } 568 569 smb_llist_enter(&user->u_tree_list, RW_WRITER); 570 smb_llist_insert_head(&user->u_tree_list, tree); 571 smb_llist_exit(&user->u_tree_list); 572 atomic_inc_32(&user->u_session->s_tree_cnt); 573 atomic_inc_32(&user->u_server->sv_open_trees); 574 575 return (tree); 576 } 577 578 /* 579 * Deallocate a tree: release all resources associated with a tree and 580 * remove the tree from the user's tree list. 581 * 582 * The tree being destroyed must be in the "destroying" state and the 583 * reference count must be zero. This function assumes it's single threaded 584 * i.e. only one thread will attempt to destroy a specific tree, which 585 * should be the case if the tree is in disconnected and has a reference 586 * count of zero. 587 */ 588 static void 589 smb_tree_dealloc(smb_tree_t *tree) 590 { 591 ASSERT(tree); 592 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 593 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 594 ASSERT(tree->t_refcnt == 0); 595 596 /* 597 * Remove the tree from the user's tree list. This must be done 598 * before any resources associated with the tree are released. 599 */ 600 smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER); 601 smb_llist_remove(&tree->t_user->u_tree_list, tree); 602 smb_llist_exit(&tree->t_user->u_tree_list); 603 604 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; 605 smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid); 606 atomic_dec_32(&tree->t_session->s_tree_cnt); 607 608 if (tree->t_snode) 609 smb_node_release(tree->t_snode); 610 611 mutex_destroy(&tree->t_mutex); 612 613 /* 614 * The list of open files and open directories should be empty. 615 */ 616 smb_llist_destructor(&tree->t_ofile_list); 617 smb_llist_destructor(&tree->t_odir_list); 618 smb_idpool_destructor(&tree->t_fid_pool); 619 smb_idpool_destructor(&tree->t_sid_pool); 620 kmem_cache_free(tree->t_server->si_cache_tree, tree); 621 } 622 623 /* 624 * Determine whether or not a tree is connected. 625 * This function must be called with the tree mutex held. 626 */ 627 static boolean_t 628 smb_tree_is_connected(smb_tree_t *tree) 629 { 630 switch (tree->t_state) { 631 case SMB_TREE_STATE_CONNECTED: 632 return (B_TRUE); 633 634 case SMB_TREE_STATE_DISCONNECTING: 635 case SMB_TREE_STATE_DISCONNECTED: 636 /* 637 * The tree exists but being diconnected or destroyed. 638 */ 639 return (B_FALSE); 640 641 default: 642 ASSERT(0); 643 return (B_FALSE); 644 } 645 } 646 647 /* 648 * Determine whether or not a tree is disconnected. 649 * This function must be called with the tree mutex held. 650 */ 651 static boolean_t 652 smb_tree_is_disconnected(smb_tree_t *tree) 653 { 654 switch (tree->t_state) { 655 case SMB_TREE_STATE_DISCONNECTED: 656 return (B_TRUE); 657 658 case SMB_TREE_STATE_CONNECTED: 659 case SMB_TREE_STATE_DISCONNECTING: 660 return (B_FALSE); 661 662 default: 663 ASSERT(0); 664 return (B_FALSE); 665 } 666 } 667 668 /* 669 * Return a pointer to the share name within a share resource path. 670 * 671 * The share path may be a Uniform Naming Convention (UNC) string 672 * (\\server\share) or simply the share name. We validate the UNC 673 * format but we don't look at the server name. 674 */ 675 static const char * 676 smb_tree_get_sharename(const char *unc_path) 677 { 678 const char *sharename = unc_path; 679 680 if (sharename[0] == '\\') { 681 /* 682 * Looks like a UNC path, validate the format. 683 */ 684 if (sharename[1] != '\\') 685 return (NULL); 686 687 if ((sharename = strchr(sharename+2, '\\')) == NULL) 688 return (NULL); 689 690 ++sharename; 691 } else if (strchr(sharename, '\\') != NULL) { 692 /* 693 * This should be a share name (no embedded \'s). 694 */ 695 return (NULL); 696 } 697 698 return (sharename); 699 } 700 701 /* 702 * Map the service to a resource type. Valid values for service are: 703 * 704 * A: Disk share 705 * LPT1: Printer 706 * IPC Named pipe 707 * COMM Communications device 708 * ????? Any type of device (wildcard) 709 * 710 * We support IPC and disk shares; anything else is currently treated 711 * as an error. IPC$ is reserved as the named pipe share. 712 */ 713 static int 714 smb_tree_get_stype(const char *sharename, const char *service, 715 int32_t *stype_ret) 716 { 717 const char *any = "?????"; 718 719 if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) { 720 if (strcasecmp(sharename, "IPC$") == 0) { 721 *stype_ret = STYPE_IPC; 722 return (0); 723 } 724 } 725 726 if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) { 727 if (strcasecmp(sharename, "IPC$") == 0) 728 return (-1); 729 730 *stype_ret = STYPE_DISKTREE; 731 return (0); 732 } 733 734 return (-1); 735 } 736 737 /* 738 * Obtain the tree attributes: volume name, typename and flags. 739 */ 740 static int 741 smb_tree_getattr(smb_node_t *node, smb_tree_t *tree) 742 { 743 vfs_t *vfsp = SMB_NODE_VFS(node); 744 745 ASSERT(vfsp); 746 747 if (getvfs(&vfsp->vfs_fsid) != vfsp) 748 return (ESTALE); 749 750 smb_tree_get_volname(vfsp, tree); 751 smb_tree_get_flags(vfsp, tree); 752 753 VFS_RELE(vfsp); 754 return (0); 755 } 756 757 /* 758 * Extract the volume name. 759 */ 760 static void 761 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree) 762 { 763 refstr_t *vfs_mntpoint; 764 const char *s; 765 char *name; 766 767 vfs_mntpoint = vfs_getmntpoint(vfsp); 768 769 s = vfs_mntpoint->rs_string; 770 s += strspn(s, "/"); 771 (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN); 772 773 refstr_rele(vfs_mntpoint); 774 775 name = tree->t_volume; 776 (void) strsep((char **)&name, "/"); 777 } 778 779 /* 780 * Always set ACL support because the VFS will fake ACLs for file systems 781 * that don't support them. 782 * 783 * Some flags are dependent on the typename, which is also set up here. 784 * File system types are hardcoded in uts/common/os/vfs_conf.c. 785 */ 786 static void 787 smb_tree_get_flags(vfs_t *vfsp, smb_tree_t *tree) 788 { 789 uint32_t flags = SMB_TREE_SUPPORTS_ACLS; 790 char *name; 791 792 if (vfsp->vfs_flag & VFS_RDONLY) 793 flags |= SMB_TREE_READONLY; 794 795 if (vfsp->vfs_flag & VFS_XATTR) 796 flags |= SMB_TREE_STREAMS; 797 798 if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) 799 flags |= SMB_TREE_NO_ATIME; 800 801 name = vfssw[vfsp->vfs_fstype].vsw_name; 802 803 if (strcmp(name, "tmpfs") == 0) 804 flags |= SMB_TREE_NO_EXPORT; 805 806 if (strncasecmp(name, NFS, sizeof (NFS)) == 0) 807 flags |= SMB_TREE_NFS_MOUNTED; 808 809 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 810 (void) utf8_strupr((char *)tree->t_typename); 811 812 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 813 flags |= SMB_TREE_XVATTR; 814 815 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 816 flags |= SMB_TREE_CASEINSENSITIVE; 817 818 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 819 flags |= SMB_TREE_NO_CASESENSITIVE; 820 821 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 822 flags |= SMB_TREE_DIRENTFLAGS; 823 824 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 825 flags |= SMB_TREE_ACLONCREATE; 826 827 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 828 flags |= SMB_TREE_ACEMASKONACCESS; 829 830 DTRACE_PROBE1(smb__tree__flags, uint32_t, flags); 831 832 tree->t_flags = flags; 833 } 834 835 /* 836 * Report share access result to syslog. 837 */ 838 static void 839 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 840 { 841 va_list ap; 842 char buf[128]; 843 smb_user_t *user = sr->uid_user; 844 845 ASSERT(user); 846 847 if (smb_tcon_mute) 848 return; 849 850 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 851 /* 852 * Only report normal users, i.e. ignore W2K misuse 853 * of the IPC connection by filtering out internal 854 * names such as nobody and root. 855 */ 856 if ((strcmp(user->u_name, "root") == 0) || 857 (strcmp(user->u_name, "nobody") == 0)) { 858 return; 859 } 860 } 861 862 va_start(ap, fmt); 863 (void) vsnprintf(buf, 128, fmt, ap); 864 va_end(ap); 865 866 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 867 user->u_domain, user->u_name, sharename, buf); 868 } 869