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 VN_RELE(sharevp); 426 } 427 } 428 429 /* 430 * Connect a share for use with files and directories. 431 */ 432 433 static smb_tree_t * 434 smb_tree_connect_disk(smb_request_t *sr, const char *sharename) 435 { 436 smb_user_t *user = sr->uid_user; 437 smb_node_t *dir_snode = NULL; 438 smb_node_t *snode = NULL; 439 char last_component[MAXNAMELEN]; 440 smb_tree_t *tree; 441 smb_share_t *si; 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); 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 ((aclaccess & ACE_ALL_PERMS) == 0) { 560 smb_tree_log(sr, sharename, "access denied: share ACL"); 561 smbsr_error(sr, 0, ERRSRV, ERRaccess); 562 kmem_free(si, sizeof (smb_share_t)); 563 smb_node_release(snode); 564 return (NULL); 565 } 566 567 /* 568 * Set tree ACL access to the minimum ACL permissions based on 569 * hostaccess (those allowed by host based access) and 570 * aclaccess (those from the ACL object for the share). This 571 * is done during the alloc. 572 */ 573 574 (void) strlcpy(si->shr_name, sharename, MAXNAMELEN); 575 tree = smb_tree_alloc(user, si, STYPE_DISKTREE, snode, 576 hostaccess & aclaccess); 577 578 smb_node_release(snode); 579 580 if (tree == NULL) 581 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 582 else { 583 584 tree->t_shr_flags = si->shr_flags; 585 586 if (tree->t_shr_flags & SMB_SHRF_MAP) { 587 (void) smb_tree_set_execsub_info(tree, &subs); 588 589 rc = smb_kshare_exec(sr->sr_server->sv_lmshrd, 590 (char *)sharename, &subs, SMB_SHR_MAP); 591 592 if (rc != 0 && tree->t_shr_flags & SMB_SHRF_DISP_TERM) { 593 smb_tree_disconnect(tree, B_FALSE); 594 smb_tree_release(tree); 595 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, 596 ERRaccess); 597 kmem_free(si, sizeof (smb_share_t)); 598 return (NULL); 599 } 600 } 601 } 602 603 kmem_free(si, sizeof (smb_share_t)); 604 605 return (tree); 606 } 607 608 /* 609 * Connect an IPC share for use with named pipes. 610 */ 611 static smb_tree_t * 612 smb_tree_connect_ipc(smb_request_t *sr, const char *name) 613 { 614 smb_user_t *user = sr->uid_user; 615 smb_tree_t *tree; 616 smb_share_t *si; 617 618 ASSERT(user); 619 620 if ((user->u_flags & SMB_USER_FLAG_IPC) && 621 sr->sr_cfg->skc_restrict_anon) { 622 smb_tree_log(sr, name, "access denied: restrict anonymous"); 623 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 624 return (NULL); 625 } 626 627 sr->arg.tcon.optional_support = SMB_SUPPORT_SEARCH_BITS; 628 629 si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP); 630 (void) strlcpy(si->shr_name, name, MAXNAMELEN); 631 (void) strlcpy(si->shr_path, name, MAXPATHLEN); 632 si->shr_type = STYPE_IPC | STYPE_SPECIAL; 633 634 tree = smb_tree_alloc(user, si, STYPE_IPC, NULL, ACE_ALL_PERMS); 635 if (tree == NULL) { 636 smb_tree_log(sr, name, "access denied"); 637 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 638 } 639 640 kmem_free(si, sizeof (smb_share_t)); 641 return (tree); 642 } 643 644 /* 645 * Allocate a tree. 646 */ 647 static smb_tree_t * 648 smb_tree_alloc( 649 smb_user_t *user, 650 const smb_share_t *si, 651 int32_t stype, 652 smb_node_t *snode, 653 uint32_t access) 654 { 655 smb_tree_t *tree; 656 uint16_t tid; 657 658 if (smb_idpool_alloc(&user->u_tid_pool, &tid)) 659 return (NULL); 660 661 tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP); 662 bzero(tree, sizeof (smb_tree_t)); 663 664 if (STYPE_ISDSK(stype)) { 665 if (smb_tree_getattr(si, snode, tree) != 0) { 666 smb_idpool_free(&user->u_tid_pool, tid); 667 kmem_cache_free(user->u_server->si_cache_tree, tree); 668 return (NULL); 669 } 670 } 671 672 if (smb_idpool_constructor(&tree->t_fid_pool)) { 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 if (smb_idpool_constructor(&tree->t_odid_pool)) { 679 smb_idpool_destructor(&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 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), 686 offsetof(smb_ofile_t, f_lnd)); 687 688 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), 689 offsetof(smb_odir_t, d_lnd)); 690 691 (void) strlcpy(tree->t_sharename, si->shr_name, 692 sizeof (tree->t_sharename)); 693 (void) strlcpy(tree->t_resource, si->shr_path, 694 sizeof (tree->t_resource)); 695 696 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); 697 698 tree->t_user = user; 699 tree->t_session = user->u_session; 700 tree->t_server = user->u_server; 701 tree->t_refcnt = 1; 702 tree->t_tid = tid; 703 tree->t_res_type = stype; 704 tree->t_state = SMB_TREE_STATE_CONNECTED; 705 tree->t_magic = SMB_TREE_MAGIC; 706 tree->t_access = access; 707 708 /* if FS is readonly, enforce that here */ 709 if (tree->t_flags & SMB_TREE_READONLY) 710 tree->t_access &= ~ACE_ALL_WRITE_PERMS; 711 712 if (STYPE_ISDSK(stype)) { 713 smb_node_ref(snode); 714 tree->t_snode = snode; 715 tree->t_acltype = smb_fsop_acltype(snode); 716 } 717 718 smb_llist_enter(&user->u_tree_list, RW_WRITER); 719 smb_llist_insert_head(&user->u_tree_list, tree); 720 smb_llist_exit(&user->u_tree_list); 721 atomic_inc_32(&user->u_session->s_tree_cnt); 722 atomic_inc_32(&user->u_server->sv_open_trees); 723 724 return (tree); 725 } 726 727 /* 728 * Deallocate a tree: release all resources associated with a tree and 729 * remove the tree from the user's tree list. 730 * 731 * The tree being destroyed must be in the "destroying" state and the 732 * reference count must be zero. This function assumes it's single threaded 733 * i.e. only one thread will attempt to destroy a specific tree, which 734 * should be the case if the tree is in disconnected and has a reference 735 * count of zero. 736 */ 737 static void 738 smb_tree_dealloc(smb_tree_t *tree) 739 { 740 ASSERT(tree); 741 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 742 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 743 ASSERT(tree->t_refcnt == 0); 744 745 /* 746 * Remove the tree from the user's tree list. This must be done 747 * before any resources associated with the tree are released. 748 */ 749 smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER); 750 smb_llist_remove(&tree->t_user->u_tree_list, tree); 751 smb_llist_exit(&tree->t_user->u_tree_list); 752 753 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; 754 smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid); 755 atomic_dec_32(&tree->t_session->s_tree_cnt); 756 757 if (tree->t_snode) 758 smb_node_release(tree->t_snode); 759 760 mutex_destroy(&tree->t_mutex); 761 762 /* 763 * The list of open files and open directories should be empty. 764 */ 765 smb_llist_destructor(&tree->t_ofile_list); 766 smb_llist_destructor(&tree->t_odir_list); 767 smb_idpool_destructor(&tree->t_fid_pool); 768 smb_idpool_destructor(&tree->t_odid_pool); 769 kmem_cache_free(tree->t_server->si_cache_tree, tree); 770 } 771 772 /* 773 * Determine whether or not a tree is connected. 774 * This function must be called with the tree mutex held. 775 */ 776 static boolean_t 777 smb_tree_is_connected_locked(smb_tree_t *tree) 778 { 779 switch (tree->t_state) { 780 case SMB_TREE_STATE_CONNECTED: 781 return (B_TRUE); 782 783 case SMB_TREE_STATE_DISCONNECTING: 784 case SMB_TREE_STATE_DISCONNECTED: 785 /* 786 * The tree exists but being diconnected or destroyed. 787 */ 788 return (B_FALSE); 789 790 default: 791 ASSERT(0); 792 return (B_FALSE); 793 } 794 } 795 796 /* 797 * Determine whether or not a tree is disconnected. 798 * This function must be called with the tree mutex held. 799 */ 800 static boolean_t 801 smb_tree_is_disconnected(smb_tree_t *tree) 802 { 803 switch (tree->t_state) { 804 case SMB_TREE_STATE_DISCONNECTED: 805 return (B_TRUE); 806 807 case SMB_TREE_STATE_CONNECTED: 808 case SMB_TREE_STATE_DISCONNECTING: 809 return (B_FALSE); 810 811 default: 812 ASSERT(0); 813 return (B_FALSE); 814 } 815 } 816 817 /* 818 * Return a pointer to the share name within a share resource path. 819 * 820 * The share path may be a Uniform Naming Convention (UNC) string 821 * (\\server\share) or simply the share name. We validate the UNC 822 * format but we don't look at the server name. 823 */ 824 static const char * 825 smb_tree_get_sharename(const char *unc_path) 826 { 827 const char *sharename = unc_path; 828 829 if (sharename[0] == '\\') { 830 /* 831 * Looks like a UNC path, validate the format. 832 */ 833 if (sharename[1] != '\\') 834 return (NULL); 835 836 if ((sharename = strchr(sharename+2, '\\')) == NULL) 837 return (NULL); 838 839 ++sharename; 840 } else if (strchr(sharename, '\\') != NULL) { 841 /* 842 * This should be a share name (no embedded \'s). 843 */ 844 return (NULL); 845 } 846 847 return (sharename); 848 } 849 850 /* 851 * Map the service to a resource type. Valid values for service are: 852 * 853 * A: Disk share 854 * LPT1: Printer 855 * IPC Named pipe 856 * COMM Communications device 857 * ????? Any type of device (wildcard) 858 * 859 * We support IPC and disk shares; anything else is currently treated 860 * as an error. IPC$ is reserved as the named pipe share. 861 */ 862 static int 863 smb_tree_get_stype(const char *sharename, const char *service, 864 int32_t *stype_ret) 865 { 866 const char *any = "?????"; 867 868 if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) { 869 if (strcasecmp(sharename, "IPC$") == 0) { 870 *stype_ret = STYPE_IPC; 871 return (0); 872 } 873 } 874 875 if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) { 876 if (strcasecmp(sharename, "IPC$") == 0) 877 return (-1); 878 879 *stype_ret = STYPE_DISKTREE; 880 return (0); 881 } 882 883 return (-1); 884 } 885 886 /* 887 * Obtain the tree attributes: volume name, typename and flags. 888 */ 889 static int 890 smb_tree_getattr(const smb_share_t *si, smb_node_t *node, smb_tree_t *tree) 891 { 892 vfs_t *vfsp = SMB_NODE_VFS(node); 893 894 ASSERT(vfsp); 895 896 if (getvfs(&vfsp->vfs_fsid) != vfsp) 897 return (ESTALE); 898 899 smb_tree_get_volname(vfsp, tree); 900 smb_tree_get_flags(si, vfsp, tree); 901 902 VFS_RELE(vfsp); 903 return (0); 904 } 905 906 /* 907 * Extract the volume name. 908 */ 909 static void 910 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree) 911 { 912 refstr_t *vfs_mntpoint; 913 const char *s; 914 char *name; 915 916 vfs_mntpoint = vfs_getmntpoint(vfsp); 917 918 s = vfs_mntpoint->rs_string; 919 s += strspn(s, "/"); 920 (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN); 921 922 refstr_rele(vfs_mntpoint); 923 924 name = tree->t_volume; 925 (void) strsep((char **)&name, "/"); 926 } 927 928 /* 929 * Always set ACL support because the VFS will fake ACLs for file systems 930 * that don't support them. 931 * 932 * Some flags are dependent on the typename, which is also set up here. 933 * File system types are hardcoded in uts/common/os/vfs_conf.c. 934 */ 935 static void 936 smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree) 937 { 938 typedef struct smb_mtype { 939 char *mt_name; 940 size_t mt_namelen; 941 uint32_t mt_flags; 942 } smb_mtype_t; 943 944 static smb_mtype_t smb_mtype[] = { 945 { "zfs", 3, SMB_TREE_UNICODE_ON_DISK }, 946 { "ufs", 3, SMB_TREE_UNICODE_ON_DISK }, 947 { "nfs", 3, SMB_TREE_NFS_MOUNTED }, 948 { "tmpfs", 5, SMB_TREE_NO_EXPORT } 949 }; 950 smb_mtype_t *mtype; 951 char *name; 952 uint32_t flags = SMB_TREE_SUPPORTS_ACLS; 953 int i; 954 955 if (si->shr_flags & SMB_SHRF_CATIA) 956 flags |= SMB_TREE_CATIA; 957 958 if (vfsp->vfs_flag & VFS_RDONLY) 959 flags |= SMB_TREE_READONLY; 960 961 if (vfsp->vfs_flag & VFS_XATTR) 962 flags |= SMB_TREE_STREAMS; 963 964 if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) 965 flags |= SMB_TREE_NO_ATIME; 966 967 name = vfssw[vfsp->vfs_fstype].vsw_name; 968 969 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) { 970 mtype = &smb_mtype[i]; 971 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0) 972 flags |= mtype->mt_flags; 973 } 974 975 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 976 (void) utf8_strupr((char *)tree->t_typename); 977 978 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 979 flags |= SMB_TREE_XVATTR; 980 981 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 982 flags |= SMB_TREE_CASEINSENSITIVE; 983 984 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 985 flags |= SMB_TREE_NO_CASESENSITIVE; 986 987 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 988 flags |= SMB_TREE_DIRENTFLAGS; 989 990 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 991 flags |= SMB_TREE_ACLONCREATE; 992 993 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 994 flags |= SMB_TREE_ACEMASKONACCESS; 995 996 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name); 997 998 999 tree->t_flags = flags; 1000 } 1001 1002 /* 1003 * Report share access result to syslog. 1004 */ 1005 static void 1006 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 1007 { 1008 va_list ap; 1009 char buf[128]; 1010 smb_user_t *user = sr->uid_user; 1011 1012 ASSERT(user); 1013 1014 if (smb_tcon_mute) 1015 return; 1016 1017 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 1018 /* 1019 * Only report normal users, i.e. ignore W2K misuse 1020 * of the IPC connection by filtering out internal 1021 * names such as nobody and root. 1022 */ 1023 if ((strcmp(user->u_name, "root") == 0) || 1024 (strcmp(user->u_name, "nobody") == 0)) { 1025 return; 1026 } 1027 } 1028 1029 va_start(ap, fmt); 1030 (void) vsnprintf(buf, 128, fmt, ap); 1031 va_end(ap); 1032 1033 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 1034 user->u_domain, user->u_name, sharename, buf); 1035 } 1036 1037 /* 1038 * smb_tree_lookup_odir 1039 * 1040 * Find the specified odir in the tree's list of odirs, and 1041 * attempt to obtain a hold on the odir. 1042 * 1043 * Returns NULL if odir not found or a hold cannot be obtained. 1044 */ 1045 smb_odir_t * 1046 smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid) 1047 { 1048 smb_odir_t *od; 1049 smb_llist_t *od_list; 1050 1051 ASSERT(tree); 1052 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1053 1054 od_list = &tree->t_odir_list; 1055 smb_llist_enter(od_list, RW_READER); 1056 1057 od = smb_llist_head(od_list); 1058 while (od) { 1059 if (od->d_odid == odid) { 1060 if (!smb_odir_hold(od)) 1061 od = NULL; 1062 break; 1063 } 1064 od = smb_llist_next(od_list, od); 1065 } 1066 1067 smb_llist_exit(od_list); 1068 return (od); 1069 } 1070 1071 boolean_t 1072 smb_tree_is_connected(smb_tree_t *tree) 1073 { 1074 boolean_t rb; 1075 1076 mutex_enter(&tree->t_mutex); 1077 rb = smb_tree_is_connected_locked(tree); 1078 mutex_exit(&tree->t_mutex); 1079 return (rb); 1080 } 1081 1082 /* 1083 * smb_tree_get_odir 1084 * 1085 * Find the next odir in the tree's list of odirs, and obtain a 1086 * hold on it. 1087 * If the specified odir is NULL the search starts at the beginning 1088 * of the tree's odir list, otherwise the search starts after the 1089 * specified odir. 1090 */ 1091 static smb_odir_t * 1092 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od) 1093 { 1094 smb_llist_t *od_list; 1095 1096 ASSERT(tree); 1097 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1098 1099 od_list = &tree->t_odir_list; 1100 smb_llist_enter(od_list, RW_READER); 1101 1102 if (od) { 1103 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1104 od = smb_llist_next(od_list, od); 1105 } else { 1106 od = smb_llist_head(od_list); 1107 } 1108 1109 while (od) { 1110 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1111 1112 if (smb_odir_hold(od)) 1113 break; 1114 od = smb_llist_next(od_list, od); 1115 } 1116 1117 smb_llist_exit(od_list); 1118 return (od); 1119 } 1120 1121 /* 1122 * smb_tree_close_odirs 1123 * 1124 * Close all open odirs in the tree's list which were opened by 1125 * the process identified by pid. 1126 * If pid is zero, close all open odirs in the tree's list. 1127 */ 1128 static void 1129 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) 1130 { 1131 smb_odir_t *od, *next_od; 1132 1133 ASSERT(tree); 1134 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1135 1136 od = smb_tree_get_odir(tree, NULL); 1137 while (od) { 1138 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1139 ASSERT(od->d_tree == tree); 1140 1141 next_od = smb_tree_get_odir(tree, od); 1142 if ((pid == 0) || (od->d_opened_by_pid == pid)) 1143 smb_odir_close(od); 1144 smb_odir_release(od); 1145 1146 od = next_od; 1147 } 1148 } 1149 1150 static void 1151 smb_tree_set_execsub_info(smb_tree_t *tree, smb_execsub_info_t *subs) 1152 { 1153 subs->e_winname = tree->t_user->u_name; 1154 subs->e_userdom = tree->t_user->u_domain; 1155 subs->e_srv_ipaddr = tree->t_session->local_ipaddr; 1156 subs->e_cli_ipaddr = tree->t_session->ipaddr; 1157 subs->e_cli_netbiosname = tree->t_session->workstation; 1158 subs->e_uid = tree->t_user->u_cred->cr_uid; 1159 } 1160