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