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 /* 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 #include <sys/pathname.h> 178 179 int smb_tcon_mute = 0; 180 181 static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *); 182 static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *); 183 static smb_tree_t *smb_tree_alloc(smb_user_t *, const smb_share_t *, 184 int32_t, smb_node_t *, uint32_t); 185 static void smb_tree_dealloc(smb_tree_t *); 186 static boolean_t smb_tree_is_connected_locked(smb_tree_t *); 187 static boolean_t smb_tree_is_disconnected(smb_tree_t *); 188 static const char *smb_tree_get_sharename(const char *); 189 static int smb_tree_get_stype(const char *, const char *, int32_t *); 190 static int smb_tree_getattr(const smb_share_t *, smb_node_t *, smb_tree_t *); 191 static void smb_tree_get_volname(vfs_t *, smb_tree_t *); 192 static void smb_tree_get_flags(const smb_share_t *, vfs_t *, smb_tree_t *); 193 static void smb_tree_log(smb_request_t *, const char *, const char *, ...); 194 static void smb_tree_close_odirs(smb_tree_t *, uint16_t); 195 static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *); 196 197 /* 198 * Extract the share name and share type and connect as appropriate. 199 * Share names are case insensitive so we map the share name to 200 * lower-case as a convenience for internal processing. 201 */ 202 smb_tree_t * 203 smb_tree_connect(smb_request_t *sr) 204 { 205 char *unc_path = sr->arg.tcon.path; 206 char *service = sr->arg.tcon.service; 207 smb_tree_t *tree = NULL; 208 const char *name; 209 int32_t stype; 210 211 (void) utf8_strlwr(unc_path); 212 213 if ((name = smb_tree_get_sharename(unc_path)) == NULL) { 214 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 215 return (NULL); 216 } 217 218 if (smb_tree_get_stype(name, service, &stype) != 0) { 219 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, 220 ERRDOS, ERROR_BAD_DEV_TYPE); 221 return (NULL); 222 } 223 224 switch (stype & STYPE_MASK) { 225 case STYPE_DISKTREE: 226 tree = smb_tree_connect_disk(sr, name); 227 break; 228 229 case STYPE_IPC: 230 tree = smb_tree_connect_ipc(sr, name); 231 break; 232 233 default: 234 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, 235 ERRDOS, ERROR_BAD_DEV_TYPE); 236 break; 237 } 238 239 return (tree); 240 } 241 242 /* 243 * Disconnect a tree. 244 */ 245 void 246 smb_tree_disconnect( 247 smb_tree_t *tree) 248 { 249 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 250 251 mutex_enter(&tree->t_mutex); 252 ASSERT(tree->t_refcnt); 253 254 if (smb_tree_is_connected_locked(tree)) { 255 /* 256 * Indicate that the disconnect process has started. 257 */ 258 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 259 mutex_exit(&tree->t_mutex); 260 atomic_dec_32(&tree->t_server->sv_open_trees); 261 262 /* 263 * The files opened under this tree are closed. 264 */ 265 smb_ofile_close_all(tree); 266 /* 267 * The directories opened under this tree are closed. 268 */ 269 smb_tree_close_odirs(tree, 0); 270 mutex_enter(&tree->t_mutex); 271 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 272 } 273 274 mutex_exit(&tree->t_mutex); 275 } 276 277 /* 278 * Take a reference on a tree. 279 */ 280 boolean_t 281 smb_tree_hold( 282 smb_tree_t *tree) 283 { 284 ASSERT(tree); 285 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 286 287 mutex_enter(&tree->t_mutex); 288 289 if (smb_tree_is_connected_locked(tree)) { 290 tree->t_refcnt++; 291 mutex_exit(&tree->t_mutex); 292 return (B_TRUE); 293 } 294 295 mutex_exit(&tree->t_mutex); 296 return (B_FALSE); 297 } 298 299 /* 300 * Release a reference on a tree. If the tree is disconnected and the 301 * reference count falls to zero, the tree will be deallocated. 302 */ 303 void 304 smb_tree_release( 305 smb_tree_t *tree) 306 { 307 ASSERT(tree); 308 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 309 310 mutex_enter(&tree->t_mutex); 311 ASSERT(tree->t_refcnt); 312 tree->t_refcnt--; 313 314 if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0)) { 315 mutex_exit(&tree->t_mutex); 316 smb_tree_dealloc(tree); 317 return; 318 } 319 320 mutex_exit(&tree->t_mutex); 321 } 322 323 /* 324 * Close ofiles and odirs that match pid. 325 */ 326 void 327 smb_tree_close_pid( 328 smb_tree_t *tree, 329 uint16_t pid) 330 { 331 ASSERT(tree); 332 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 333 334 smb_ofile_close_all_by_pid(tree, pid); 335 smb_tree_close_odirs(tree, pid); 336 } 337 338 /* 339 * Check whether or not a tree supports the features identified by flags. 340 */ 341 boolean_t 342 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags) 343 { 344 ASSERT(tree); 345 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 346 347 return ((tree->t_flags & flags) == flags); 348 } 349 350 351 /* *************************** Static Functions ***************************** */ 352 #define SHARES_DIR ".zfs/shares/" 353 static void 354 smb_tree_acl_access(cred_t *cred, const char *sharename, vnode_t *pathvp, 355 uint32_t *access) 356 { 357 int rc; 358 vfs_t *vfsp; 359 vnode_t *root = NULL; 360 vnode_t *sharevp = NULL; 361 char *sharepath; 362 struct pathname pnp; 363 size_t size; 364 365 *access = ACE_ALL_PERMS; /* default to full "UNIX" access */ 366 367 /* 368 * Using the vnode of the share path, we then find the root 369 * directory of the mounted file system. We will then look to 370 * see if there is a .zfs/shares directory and if there is, 371 * get the access information from the ACL/ACES values and 372 * check against the cred. 373 */ 374 vfsp = pathvp->v_vfsp; 375 if (vfsp != NULL) 376 rc = VFS_ROOT(vfsp, &root); 377 else 378 rc = ENOENT; 379 380 if (rc != 0) 381 return; 382 383 384 /* 385 * Find the share object, if there is one. Need to construct 386 * the path to the .zfs/shares/<sharename> object and look it 387 * up. root is called held but will be released by 388 * lookuppnvp(). 389 */ 390 391 size = sizeof (SHARES_DIR) + strlen(sharename) + 1; 392 sharepath = kmem_alloc(size, KM_SLEEP); 393 (void) sprintf(sharepath, "%s%s", SHARES_DIR, sharename); 394 395 pn_alloc(&pnp); 396 (void) pn_set(&pnp, sharepath); 397 rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, 398 &sharevp, rootdir, root, kcred); 399 pn_free(&pnp); 400 401 kmem_free(sharepath, size); 402 403 /* 404 * Now get the effective access value based on cred and ACL 405 * values. 406 */ 407 408 if (rc == 0) 409 smb_vop_eaccess(sharevp, (int *)access, V_ACE_MASK, NULL, cred); 410 411 } 412 413 /* 414 * Connect a share for use with files and directories. 415 */ 416 417 static smb_tree_t * 418 smb_tree_connect_disk(smb_request_t *sr, const char *sharename) 419 { 420 smb_user_t *user = sr->uid_user; 421 smb_node_t *dir_snode = NULL; 422 smb_node_t *snode = NULL; 423 char last_component[MAXNAMELEN]; 424 smb_tree_t *tree; 425 smb_share_t *si; 426 smb_attr_t attr; 427 cred_t *u_cred; 428 int rc; 429 uint32_t access = 0; /* read/write is assumed */ 430 uint32_t hostaccess = ACE_ALL_PERMS; 431 uint32_t aclaccess; 432 433 ASSERT(user); 434 u_cred = user->u_cred; 435 ASSERT(u_cred); 436 437 if (user->u_flags & SMB_USER_FLAG_IPC) { 438 smb_tree_log(sr, sharename, "access denied: IPC only"); 439 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 440 return (NULL); 441 } 442 443 si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP); 444 445 if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si, 446 &sr->session->ipaddr) != NERR_Success) { 447 smb_tree_log(sr, sharename, "share not found"); 448 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 449 kmem_free(si, sizeof (smb_share_t)); 450 return (NULL); 451 } 452 453 /* 454 * Handle the default administration shares: C$, D$ etc. 455 * Only a user with admin rights is allowed to map these 456 * shares. 457 */ 458 if (si->shr_flags & SMB_SHRF_ADMIN) { 459 if (!smb_user_is_admin(user)) { 460 smb_tree_log(sr, sharename, "access denied: not admin"); 461 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 462 ERRSRV, ERRaccess); 463 kmem_free(si, sizeof (smb_share_t)); 464 return (NULL); 465 } 466 } 467 468 /* 469 * Set up the OptionalSupport for this share. 470 */ 471 sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS; 472 473 switch (si->shr_flags & SMB_SHRF_CSC_MASK) { 474 case SMB_SHRF_CSC_DISABLED: 475 sr->arg.tcon.optional_support |= SMB_CSC_CACHE_NONE; 476 break; 477 case SMB_SHRF_CSC_AUTO: 478 sr->arg.tcon.optional_support |= SMB_CSC_CACHE_AUTO_REINT; 479 break; 480 case SMB_SHRF_CSC_VDO: 481 sr->arg.tcon.optional_support |= SMB_CSC_CACHE_VDO; 482 break; 483 case SMB_SHRF_CSC_MANUAL: 484 default: 485 /* 486 * Default to SMB_CSC_CACHE_MANUAL_REINT. 487 */ 488 break; 489 } 490 491 access = si->shr_access_value & SMB_SHRF_ACC_ALL; 492 493 if (access == SMB_SHRF_ACC_RO) { 494 hostaccess &= ~ACE_ALL_WRITE_PERMS; 495 } else if (access == SMB_SHRF_ACC_NONE) { 496 kmem_free(si, sizeof (smb_share_t)); 497 smb_tree_log(sr, sharename, "access denied: host access"); 498 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 499 return (NULL); 500 } 501 502 /* 503 * Check that the shared directory exists. 504 */ 505 rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode, 506 last_component); 507 508 if (rc == 0) { 509 rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS, 510 sr->sr_server->si_root_smb_node, dir_snode, last_component, 511 &snode, &attr); 512 513 smb_node_release(dir_snode); 514 } 515 516 if (rc) { 517 if (snode) 518 smb_node_release(snode); 519 520 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); 521 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 522 kmem_free(si, sizeof (smb_share_t)); 523 return (NULL); 524 } 525 526 /* 527 * Find share level ACL if it exists in the designated 528 * location. Needs to be done after finding a valid path but 529 * before the tree is allocated. 530 */ 531 smb_tree_acl_access(u_cred, sharename, snode->vp, &aclaccess); 532 /* if an error, then no share file -- default to no ACL */ 533 if (rc == 0) { 534 /* 535 * There need to be some permissions in order to have 536 * any access. 537 */ 538 if ((aclaccess & ACE_ALL_PERMS) == 0) { 539 smb_tree_log(sr, sharename, "access denied: share ACL"); 540 smbsr_error(sr, 0, ERRSRV, ERRaccess); 541 kmem_free(si, sizeof (smb_share_t)); 542 smb_node_release(snode); 543 return (NULL); 544 } 545 } 546 547 /* 548 * Set tree ACL access to the minimum ACL permissions based on 549 * hostaccess (those allowed by host based access) and 550 * aclaccess (those from the ACL object for the share). This 551 * is done during the alloc. 552 */ 553 554 (void) strlcpy(si->shr_name, sharename, MAXNAMELEN); 555 tree = smb_tree_alloc(user, si, STYPE_DISKTREE, snode, 556 hostaccess & aclaccess); 557 558 if (tree == NULL) 559 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 560 561 smb_node_release(snode); 562 kmem_free(si, sizeof (smb_share_t)); 563 return (tree); 564 } 565 566 /* 567 * Connect an IPC share for use with named pipes. 568 */ 569 static smb_tree_t * 570 smb_tree_connect_ipc(smb_request_t *sr, const char *name) 571 { 572 smb_user_t *user = sr->uid_user; 573 smb_tree_t *tree; 574 smb_share_t *si; 575 576 ASSERT(user); 577 578 if ((user->u_flags & SMB_USER_FLAG_IPC) && 579 sr->sr_cfg->skc_restrict_anon) { 580 smb_tree_log(sr, name, "access denied: restrict anonymous"); 581 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 582 return (NULL); 583 } 584 585 sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS; 586 587 si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP); 588 (void) strlcpy(si->shr_name, name, MAXNAMELEN); 589 (void) strlcpy(si->shr_path, name, MAXPATHLEN); 590 si->shr_type = STYPE_IPC | STYPE_SPECIAL; 591 592 tree = smb_tree_alloc(user, si, STYPE_IPC, NULL, ACE_ALL_PERMS); 593 if (tree == NULL) { 594 smb_tree_log(sr, name, "access denied"); 595 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 596 } 597 598 kmem_free(si, sizeof (smb_share_t)); 599 return (tree); 600 } 601 602 /* 603 * Allocate a tree. 604 */ 605 static smb_tree_t * 606 smb_tree_alloc( 607 smb_user_t *user, 608 const smb_share_t *si, 609 int32_t stype, 610 smb_node_t *snode, 611 uint32_t access) 612 { 613 smb_tree_t *tree; 614 uint16_t tid; 615 616 if (smb_idpool_alloc(&user->u_tid_pool, &tid)) 617 return (NULL); 618 619 tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP); 620 bzero(tree, sizeof (smb_tree_t)); 621 622 if (STYPE_ISDSK(stype)) { 623 if (smb_tree_getattr(si, snode, tree) != 0) { 624 smb_idpool_free(&user->u_tid_pool, tid); 625 kmem_cache_free(user->u_server->si_cache_tree, tree); 626 return (NULL); 627 } 628 } 629 630 if (smb_idpool_constructor(&tree->t_fid_pool)) { 631 smb_idpool_free(&user->u_tid_pool, tid); 632 kmem_cache_free(user->u_server->si_cache_tree, tree); 633 return (NULL); 634 } 635 636 if (smb_idpool_constructor(&tree->t_odid_pool)) { 637 smb_idpool_destructor(&tree->t_fid_pool); 638 smb_idpool_free(&user->u_tid_pool, tid); 639 kmem_cache_free(user->u_server->si_cache_tree, tree); 640 return (NULL); 641 } 642 643 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), 644 offsetof(smb_ofile_t, f_lnd)); 645 646 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), 647 offsetof(smb_odir_t, d_lnd)); 648 649 (void) strlcpy(tree->t_sharename, si->shr_name, 650 sizeof (tree->t_sharename)); 651 (void) strlcpy(tree->t_resource, si->shr_path, 652 sizeof (tree->t_resource)); 653 654 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); 655 656 tree->t_user = user; 657 tree->t_session = user->u_session; 658 tree->t_server = user->u_server; 659 tree->t_refcnt = 1; 660 tree->t_tid = tid; 661 tree->t_res_type = stype; 662 tree->t_state = SMB_TREE_STATE_CONNECTED; 663 tree->t_magic = SMB_TREE_MAGIC; 664 tree->t_access = access; 665 666 /* if FS is readonly, enforce that here */ 667 if (tree->t_flags & SMB_TREE_READONLY) 668 tree->t_access &= ~ACE_ALL_WRITE_PERMS; 669 670 if (STYPE_ISDSK(stype)) { 671 smb_node_ref(snode); 672 tree->t_snode = snode; 673 tree->t_acltype = smb_fsop_acltype(snode); 674 } 675 676 smb_llist_enter(&user->u_tree_list, RW_WRITER); 677 smb_llist_insert_head(&user->u_tree_list, tree); 678 smb_llist_exit(&user->u_tree_list); 679 atomic_inc_32(&user->u_session->s_tree_cnt); 680 atomic_inc_32(&user->u_server->sv_open_trees); 681 682 return (tree); 683 } 684 685 /* 686 * Deallocate a tree: release all resources associated with a tree and 687 * remove the tree from the user's tree list. 688 * 689 * The tree being destroyed must be in the "destroying" state and the 690 * reference count must be zero. This function assumes it's single threaded 691 * i.e. only one thread will attempt to destroy a specific tree, which 692 * should be the case if the tree is in disconnected and has a reference 693 * count of zero. 694 */ 695 static void 696 smb_tree_dealloc(smb_tree_t *tree) 697 { 698 ASSERT(tree); 699 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 700 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 701 ASSERT(tree->t_refcnt == 0); 702 703 /* 704 * Remove the tree from the user's tree list. This must be done 705 * before any resources associated with the tree are released. 706 */ 707 smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER); 708 smb_llist_remove(&tree->t_user->u_tree_list, tree); 709 smb_llist_exit(&tree->t_user->u_tree_list); 710 711 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; 712 smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid); 713 atomic_dec_32(&tree->t_session->s_tree_cnt); 714 715 if (tree->t_snode) 716 smb_node_release(tree->t_snode); 717 718 mutex_destroy(&tree->t_mutex); 719 720 /* 721 * The list of open files and open directories should be empty. 722 */ 723 smb_llist_destructor(&tree->t_ofile_list); 724 smb_llist_destructor(&tree->t_odir_list); 725 smb_idpool_destructor(&tree->t_fid_pool); 726 smb_idpool_destructor(&tree->t_odid_pool); 727 kmem_cache_free(tree->t_server->si_cache_tree, tree); 728 } 729 730 /* 731 * Determine whether or not a tree is connected. 732 * This function must be called with the tree mutex held. 733 */ 734 static boolean_t 735 smb_tree_is_connected_locked(smb_tree_t *tree) 736 { 737 switch (tree->t_state) { 738 case SMB_TREE_STATE_CONNECTED: 739 return (B_TRUE); 740 741 case SMB_TREE_STATE_DISCONNECTING: 742 case SMB_TREE_STATE_DISCONNECTED: 743 /* 744 * The tree exists but being diconnected or destroyed. 745 */ 746 return (B_FALSE); 747 748 default: 749 ASSERT(0); 750 return (B_FALSE); 751 } 752 } 753 754 /* 755 * Determine whether or not a tree is disconnected. 756 * This function must be called with the tree mutex held. 757 */ 758 static boolean_t 759 smb_tree_is_disconnected(smb_tree_t *tree) 760 { 761 switch (tree->t_state) { 762 case SMB_TREE_STATE_DISCONNECTED: 763 return (B_TRUE); 764 765 case SMB_TREE_STATE_CONNECTED: 766 case SMB_TREE_STATE_DISCONNECTING: 767 return (B_FALSE); 768 769 default: 770 ASSERT(0); 771 return (B_FALSE); 772 } 773 } 774 775 /* 776 * Return a pointer to the share name within a share resource path. 777 * 778 * The share path may be a Uniform Naming Convention (UNC) string 779 * (\\server\share) or simply the share name. We validate the UNC 780 * format but we don't look at the server name. 781 */ 782 static const char * 783 smb_tree_get_sharename(const char *unc_path) 784 { 785 const char *sharename = unc_path; 786 787 if (sharename[0] == '\\') { 788 /* 789 * Looks like a UNC path, validate the format. 790 */ 791 if (sharename[1] != '\\') 792 return (NULL); 793 794 if ((sharename = strchr(sharename+2, '\\')) == NULL) 795 return (NULL); 796 797 ++sharename; 798 } else if (strchr(sharename, '\\') != NULL) { 799 /* 800 * This should be a share name (no embedded \'s). 801 */ 802 return (NULL); 803 } 804 805 return (sharename); 806 } 807 808 /* 809 * Map the service to a resource type. Valid values for service are: 810 * 811 * A: Disk share 812 * LPT1: Printer 813 * IPC Named pipe 814 * COMM Communications device 815 * ????? Any type of device (wildcard) 816 * 817 * We support IPC and disk shares; anything else is currently treated 818 * as an error. IPC$ is reserved as the named pipe share. 819 */ 820 static int 821 smb_tree_get_stype(const char *sharename, const char *service, 822 int32_t *stype_ret) 823 { 824 const char *any = "?????"; 825 826 if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) { 827 if (strcasecmp(sharename, "IPC$") == 0) { 828 *stype_ret = STYPE_IPC; 829 return (0); 830 } 831 } 832 833 if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) { 834 if (strcasecmp(sharename, "IPC$") == 0) 835 return (-1); 836 837 *stype_ret = STYPE_DISKTREE; 838 return (0); 839 } 840 841 return (-1); 842 } 843 844 /* 845 * Obtain the tree attributes: volume name, typename and flags. 846 */ 847 static int 848 smb_tree_getattr(const smb_share_t *si, smb_node_t *node, smb_tree_t *tree) 849 { 850 vfs_t *vfsp = SMB_NODE_VFS(node); 851 852 ASSERT(vfsp); 853 854 if (getvfs(&vfsp->vfs_fsid) != vfsp) 855 return (ESTALE); 856 857 smb_tree_get_volname(vfsp, tree); 858 smb_tree_get_flags(si, vfsp, tree); 859 860 VFS_RELE(vfsp); 861 return (0); 862 } 863 864 /* 865 * Extract the volume name. 866 */ 867 static void 868 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree) 869 { 870 refstr_t *vfs_mntpoint; 871 const char *s; 872 char *name; 873 874 vfs_mntpoint = vfs_getmntpoint(vfsp); 875 876 s = vfs_mntpoint->rs_string; 877 s += strspn(s, "/"); 878 (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN); 879 880 refstr_rele(vfs_mntpoint); 881 882 name = tree->t_volume; 883 (void) strsep((char **)&name, "/"); 884 } 885 886 /* 887 * Always set ACL support because the VFS will fake ACLs for file systems 888 * that don't support them. 889 * 890 * Some flags are dependent on the typename, which is also set up here. 891 * File system types are hardcoded in uts/common/os/vfs_conf.c. 892 */ 893 static void 894 smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree) 895 { 896 typedef struct smb_mtype { 897 char *mt_name; 898 size_t mt_namelen; 899 uint32_t mt_flags; 900 } smb_mtype_t; 901 902 static smb_mtype_t smb_mtype[] = { 903 { "zfs", 3, SMB_TREE_UNICODE_ON_DISK }, 904 { "ufs", 3, SMB_TREE_UNICODE_ON_DISK }, 905 { "nfs", 3, SMB_TREE_NFS_MOUNTED }, 906 { "tmpfs", 5, SMB_TREE_NO_EXPORT } 907 }; 908 smb_mtype_t *mtype; 909 char *name; 910 uint32_t flags = SMB_TREE_SUPPORTS_ACLS; 911 int i; 912 913 if (si->shr_flags & SMB_SHRF_CATIA) 914 flags |= SMB_TREE_CATIA; 915 916 if (vfsp->vfs_flag & VFS_RDONLY) 917 flags |= SMB_TREE_READONLY; 918 919 if (vfsp->vfs_flag & VFS_XATTR) 920 flags |= SMB_TREE_STREAMS; 921 922 if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) 923 flags |= SMB_TREE_NO_ATIME; 924 925 name = vfssw[vfsp->vfs_fstype].vsw_name; 926 927 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) { 928 mtype = &smb_mtype[i]; 929 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0) 930 flags |= mtype->mt_flags; 931 } 932 933 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 934 (void) utf8_strupr((char *)tree->t_typename); 935 936 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 937 flags |= SMB_TREE_XVATTR; 938 939 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 940 flags |= SMB_TREE_CASEINSENSITIVE; 941 942 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 943 flags |= SMB_TREE_NO_CASESENSITIVE; 944 945 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 946 flags |= SMB_TREE_DIRENTFLAGS; 947 948 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 949 flags |= SMB_TREE_ACLONCREATE; 950 951 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 952 flags |= SMB_TREE_ACEMASKONACCESS; 953 954 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name); 955 956 957 tree->t_flags = flags; 958 } 959 960 /* 961 * Report share access result to syslog. 962 */ 963 static void 964 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 965 { 966 va_list ap; 967 char buf[128]; 968 smb_user_t *user = sr->uid_user; 969 970 ASSERT(user); 971 972 if (smb_tcon_mute) 973 return; 974 975 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 976 /* 977 * Only report normal users, i.e. ignore W2K misuse 978 * of the IPC connection by filtering out internal 979 * names such as nobody and root. 980 */ 981 if ((strcmp(user->u_name, "root") == 0) || 982 (strcmp(user->u_name, "nobody") == 0)) { 983 return; 984 } 985 } 986 987 va_start(ap, fmt); 988 (void) vsnprintf(buf, 128, fmt, ap); 989 va_end(ap); 990 991 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 992 user->u_domain, user->u_name, sharename, buf); 993 } 994 995 /* 996 * smb_tree_lookup_odir 997 * 998 * Find the specified odir in the tree's list of odirs, and 999 * attempt to obtain a hold on the odir. 1000 * 1001 * Returns NULL if odir not found or a hold cannot be obtained. 1002 */ 1003 smb_odir_t * 1004 smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid) 1005 { 1006 smb_odir_t *od; 1007 smb_llist_t *od_list; 1008 1009 ASSERT(tree); 1010 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1011 1012 od_list = &tree->t_odir_list; 1013 smb_llist_enter(od_list, RW_READER); 1014 1015 od = smb_llist_head(od_list); 1016 while (od) { 1017 if (od->d_odid == odid) { 1018 if (!smb_odir_hold(od)) 1019 od = NULL; 1020 break; 1021 } 1022 od = smb_llist_next(od_list, od); 1023 } 1024 1025 smb_llist_exit(od_list); 1026 return (od); 1027 } 1028 1029 boolean_t 1030 smb_tree_is_connected(smb_tree_t *tree) 1031 { 1032 boolean_t rb; 1033 1034 mutex_enter(&tree->t_mutex); 1035 rb = smb_tree_is_connected_locked(tree); 1036 mutex_exit(&tree->t_mutex); 1037 return (rb); 1038 } 1039 1040 /* 1041 * smb_tree_get_odir 1042 * 1043 * Find the next open odir in the tree's list of odirs, and obtain 1044 * a hold on it. (A hold can only be obtained on an open odir.) 1045 * If the specified odir is NULL the search starts at the beginning 1046 * of the tree's odir list, otherwise the search starts after the 1047 * specified odir. 1048 */ 1049 static smb_odir_t * 1050 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od) 1051 { 1052 smb_llist_t *od_list; 1053 1054 ASSERT(tree); 1055 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1056 1057 od_list = &tree->t_odir_list; 1058 smb_llist_enter(od_list, RW_READER); 1059 1060 if (od) { 1061 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1062 od = smb_llist_next(od_list, od); 1063 } else { 1064 od = smb_llist_head(od_list); 1065 } 1066 1067 while (od) { 1068 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1069 1070 if (smb_odir_hold(od)) 1071 break; 1072 od = smb_llist_next(od_list, od); 1073 } 1074 1075 smb_llist_exit(od_list); 1076 return (od); 1077 } 1078 1079 /* 1080 * smb_tree_close_odirs 1081 * 1082 * Close all open odirs in the tree's list which were opened by 1083 * the process identified by pid. 1084 * If pid is zero, close all open odirs in the tree's list. 1085 */ 1086 static void 1087 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) 1088 { 1089 smb_odir_t *od, *next_od; 1090 1091 ASSERT(tree); 1092 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1093 1094 od = smb_tree_get_odir(tree, NULL); 1095 while (od) { 1096 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1097 ASSERT(od->d_tree == tree); 1098 1099 next_od = smb_tree_get_odir(tree, od); 1100 if ((pid == 0) || (od->d_opened_by_pid == pid)) 1101 smb_odir_close(od); 1102 smb_odir_release(od); 1103 1104 od = next_od; 1105 } 1106 } 1107