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 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 */ 27 28 /* 29 * General Structures Layout 30 * ------------------------- 31 * 32 * This is a simplified diagram showing the relationship between most of the 33 * main structures. 34 * 35 * +-------------------+ 36 * | SMB_INFO | 37 * +-------------------+ 38 * | 39 * | 40 * v 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | SESSION |<----->| SESSION |......| SESSION | 43 * +-------------------+ +-------------------+ +-------------------+ 44 * | | 45 * | | 46 * | v 47 * | +-------------------+ +-------------------+ +-------------------+ 48 * | | USER |<--->| USER |...| USER | 49 * | +-------------------+ +-------------------+ +-------------------+ 50 * | 51 * | 52 * v 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | TREE |<----->| TREE |......| TREE | 55 * +-------------------+ +-------------------+ +-------------------+ 56 * | | 57 * | | 58 * | v 59 * | +-------+ +-------+ +-------+ 60 * | | OFILE |<----->| OFILE |......| OFILE | 61 * | +-------+ +-------+ +-------+ 62 * | 63 * | 64 * v 65 * +-------+ +------+ +------+ 66 * | ODIR |<----->| ODIR |......| ODIR | 67 * +-------+ +------+ +------+ 68 * 69 * 70 * Tree State Machine 71 * ------------------ 72 * 73 * +-----------------------------+ T0 74 * | SMB_TREE_STATE_CONNECTED |<----------- Creation/Allocation 75 * +-----------------------------+ 76 * | 77 * | T1 78 * | 79 * v 80 * +------------------------------+ 81 * | SMB_TREE_STATE_DISCONNECTING | 82 * +------------------------------+ 83 * | 84 * | T2 85 * | 86 * v 87 * +-----------------------------+ T3 88 * | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free 89 * +-----------------------------+ 90 * 91 * SMB_TREE_STATE_CONNECTED 92 * 93 * While in this state: 94 * - The tree is queued in the list of trees of its user. 95 * - References will be given out if the tree is looked up. 96 * - Files under that tree can be accessed. 97 * 98 * SMB_TREE_STATE_DISCONNECTING 99 * 100 * While in this state: 101 * - The tree is queued in the list of trees of its user. 102 * - References will not be given out if the tree is looked up. 103 * - The files and directories open under the tree are being closed. 104 * - The resources associated with the tree remain. 105 * 106 * SMB_TREE_STATE_DISCONNECTED 107 * 108 * While in this state: 109 * - The tree is queued in the list of trees of its user. 110 * - References will not be given out if the tree is looked up. 111 * - The tree has no more files and directories opened. 112 * - The resources associated with the tree remain. 113 * 114 * Transition T0 115 * 116 * This transition occurs in smb_tree_connect(). A new tree is created and 117 * added to the list of trees of a user. 118 * 119 * Transition T1 120 * 121 * This transition occurs in smb_tree_disconnect(). 122 * 123 * Transition T2 124 * 125 * This transition occurs in smb_tree_disconnect() 126 * 127 * Transition T3 128 * 129 * This transition occurs in smb_tree_release(). The resources associated 130 * with the tree are freed as well as the tree structure. For the transition 131 * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED and the 132 * reference count must be zero. 133 * 134 * Comments 135 * -------- 136 * 137 * The state machine of the tree structures is controlled by 3 elements: 138 * - The list of trees of the user it belongs to. 139 * - The mutex embedded in the structure itself. 140 * - The reference count. 141 * 142 * There's a mutex embedded in the tree structure used to protect its fields 143 * and there's a lock embedded in the list of trees of a user. To 144 * increment or to decrement the reference count the mutex must be entered. 145 * To insert the tree into the list of trees of the user and to remove 146 * the tree from it, the lock must be entered in RW_WRITER mode. 147 * 148 * Rules of access to a tree structure: 149 * 150 * 1) In order to avoid deadlocks, when both (mutex and lock of the user 151 * list) have to be entered, the lock must be entered first. Additionally, 152 * when both the (mutex and lock of the ofile list) have to be entered, 153 * the mutex must be entered first. However, the ofile list lock must NOT 154 * be dropped while the mutex is held in such a way that the ofile deleteq 155 * is flushed. 156 * 157 * 2) All actions applied to a tree require a reference count. 158 * 159 * 3) There are 2 ways of getting a reference count: when a tree is 160 * connected and when a tree is looked up. 161 * 162 * It should be noted that the reference count of a tree registers the 163 * number of references to the tree in other structures (such as an smb 164 * request). The reference count is not incremented in these 2 instances: 165 * 166 * 1) The tree is connected. An tree is anchored by its state. If there's 167 * no activity involving a tree currently connected, the reference 168 * count of that tree is zero. 169 * 170 * 2) The tree is queued in the list of trees of the user. The fact of 171 * being queued in that list is NOT registered by incrementing the 172 * reference count. 173 */ 174 175 #include <sys/refstr_impl.h> 176 #include <smbsrv/smb_kproto.h> 177 #include <smbsrv/smb_ktypes.h> 178 #include <smbsrv/smb_fsops.h> 179 #include <smbsrv/smb_share.h> 180 181 int smb_tcon_mute = 0; 182 183 uint32_t smb_tree_connect_core(smb_request_t *); 184 uint32_t smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *); 185 uint32_t smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *); 186 uint32_t smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *); 187 static smb_tree_t *smb_tree_alloc(smb_request_t *, const smb_kshare_t *, 188 smb_node_t *, uint32_t, uint32_t); 189 static void smb_tree_dealloc(void *); 190 static boolean_t smb_tree_is_connected_locked(smb_tree_t *); 191 static char *smb_tree_get_sharename(char *); 192 static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *); 193 static void smb_tree_get_volname(vfs_t *, smb_tree_t *); 194 static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *); 195 static void smb_tree_log(smb_request_t *, const char *, const char *, ...); 196 static void smb_tree_close_odirs(smb_tree_t *, uint16_t); 197 static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *); 198 static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *); 199 static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int); 200 static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *); 201 static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *); 202 static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *); 203 static void smb_tree_netinfo_fini(smb_netconnectinfo_t *); 204 205 uint32_t 206 smb_tree_connect(smb_request_t *sr) 207 { 208 smb_server_t *sv = sr->sr_server; 209 uint32_t status; 210 211 if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) { 212 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 213 } 214 215 status = smb_tree_connect_core(sr); 216 smb_threshold_exit(&sv->sv_tcon_ct); 217 return (status); 218 } 219 220 /* 221 * Lookup the share name dispatch the appropriate stype handler. 222 * Share names are case insensitive so we map the share name to 223 * lower-case as a convenience for internal processing. 224 * 225 * Valid service values are: 226 * A: Disk share 227 * LPT1: Printer 228 * IPC Named pipe (IPC$ is reserved as the named pipe share). 229 * COMM Communications device 230 * ????? Any type of device (wildcard) 231 */ 232 uint32_t 233 smb_tree_connect_core(smb_request_t *sr) 234 { 235 smb_arg_tcon_t *tcon = &sr->sr_tcon; 236 smb_kshare_t *si; 237 char *name; 238 uint32_t status; 239 240 (void) smb_strlwr(tcon->path); 241 242 if ((name = smb_tree_get_sharename(tcon->path)) == NULL) { 243 smb_tree_log(sr, tcon->path, "invalid UNC path"); 244 return (NT_STATUS_BAD_NETWORK_NAME); 245 } 246 247 si = smb_kshare_lookup(sr->sr_server, name); 248 if (si == NULL) { 249 smb_tree_log(sr, name, "share not found"); 250 return (NT_STATUS_BAD_NETWORK_NAME); 251 } 252 253 if (!strcasecmp(SMB_SHARE_PRINT, name)) { 254 smb_kshare_release(sr->sr_server, si); 255 smb_tree_log(sr, name, "access not permitted"); 256 return (NT_STATUS_ACCESS_DENIED); 257 } 258 259 /* NB: name points into tcon->path - don't free it. */ 260 tcon->name = name; 261 sr->sr_tcon.si = si; 262 263 /* 264 * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request 265 * 266 * If we support 3.x, RejectUnencryptedAccess is TRUE, 267 * if Tcon.EncryptData is TRUE or global EncryptData is TRUE, 268 * and the connection doesn't support encryption, 269 * return ACCESS_DENIED. 270 * 271 * If RejectUnencryptedAccess is TRUE, we force max_protocol 272 * to at least 3.0. Additionally, if the tree requires encryption, 273 * we don't care what we support, we still enforce encryption. 274 */ 275 if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED || 276 si->shr_encrypt == SMB_CONFIG_REQUIRED) && 277 (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) { 278 status = NT_STATUS_ACCESS_DENIED; 279 goto out; 280 } 281 282 switch (si->shr_type & STYPE_MASK) { 283 case STYPE_DISKTREE: 284 status = smb_tree_connect_disk(sr, &sr->sr_tcon); 285 break; 286 case STYPE_IPC: 287 status = smb_tree_connect_ipc(sr, &sr->sr_tcon); 288 break; 289 case STYPE_PRINTQ: 290 status = smb_tree_connect_printq(sr, &sr->sr_tcon); 291 break; 292 default: 293 status = NT_STATUS_BAD_DEVICE_TYPE; 294 break; 295 } 296 297 out: 298 smb_kshare_release(sr->sr_server, si); 299 sr->sr_tcon.si = NULL; 300 301 return (status); 302 } 303 304 /* 305 * Disconnect a tree. 306 */ 307 void 308 smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec) 309 { 310 smb_shr_execinfo_t execinfo; 311 312 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 313 314 mutex_enter(&tree->t_mutex); 315 ASSERT(tree->t_refcnt); 316 317 if (smb_tree_is_connected_locked(tree)) { 318 /* 319 * Indicate that the disconnect process has started. 320 */ 321 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 322 mutex_exit(&tree->t_mutex); 323 324 if (do_exec) { 325 /* 326 * The files opened under this tree are closed. 327 */ 328 smb_ofile_close_all(tree, 0); 329 /* 330 * The directories opened under this tree are closed. 331 */ 332 smb_tree_close_odirs(tree, 0); 333 } 334 335 mutex_enter(&tree->t_mutex); 336 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 337 smb_server_dec_trees(tree->t_server); 338 } 339 340 mutex_exit(&tree->t_mutex); 341 342 if (do_exec && (tree->t_state == SMB_TREE_STATE_DISCONNECTED) && 343 (tree->t_execflags & SMB_EXEC_UNMAP)) { 344 345 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP); 346 (void) smb_kshare_exec(tree->t_server, &execinfo); 347 } 348 } 349 350 /* 351 * Take a reference on a tree. 352 */ 353 boolean_t 354 smb_tree_hold( 355 smb_tree_t *tree) 356 { 357 SMB_TREE_VALID(tree); 358 359 mutex_enter(&tree->t_mutex); 360 361 if (smb_tree_is_connected_locked(tree)) { 362 tree->t_refcnt++; 363 mutex_exit(&tree->t_mutex); 364 return (B_TRUE); 365 } 366 367 mutex_exit(&tree->t_mutex); 368 return (B_FALSE); 369 } 370 371 /* 372 * Bump the hold count regardless of the tree state. This is used in 373 * some internal code paths where we've already checked that we had a 374 * valid tree connection, and don't want to deal with the possiblity 375 * that the tree state might have changed to disconnecting after our 376 * original hold was taken. It's correct to continue processing a 377 * request even when new requests cannot lookup that tree anymore. 378 */ 379 void 380 smb_tree_hold_internal( 381 smb_tree_t *tree) 382 { 383 SMB_TREE_VALID(tree); 384 385 mutex_enter(&tree->t_mutex); 386 tree->t_refcnt++; 387 mutex_exit(&tree->t_mutex); 388 } 389 390 /* 391 * Release a reference on a tree. If the tree is disconnected and the 392 * reference count falls to zero, post the object for deletion. 393 * Object deletion is deferred to avoid modifying a list while an 394 * iteration may be in progress. 395 */ 396 void 397 smb_tree_release( 398 smb_tree_t *tree) 399 { 400 SMB_TREE_VALID(tree); 401 402 /* flush the ofile and odir lists' delete queues */ 403 smb_llist_flush(&tree->t_ofile_list); 404 smb_llist_flush(&tree->t_odir_list); 405 406 mutex_enter(&tree->t_mutex); 407 ASSERT(tree->t_refcnt); 408 tree->t_refcnt--; 409 410 switch (tree->t_state) { 411 case SMB_TREE_STATE_DISCONNECTED: 412 if (tree->t_refcnt == 0) { 413 smb_session_t *ssn = tree->t_session; 414 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 415 smb_llist_post(&ssn->s_tree_list, tree, 416 smb_tree_dealloc); 417 } 418 break; 419 case SMB_TREE_STATE_CONNECTED: 420 case SMB_TREE_STATE_DISCONNECTING: 421 break; 422 default: 423 ASSERT(0); 424 break; 425 } 426 427 mutex_exit(&tree->t_mutex); 428 } 429 430 /* 431 * Close ofiles and odirs that match pid. 432 */ 433 void 434 smb_tree_close_pid( 435 smb_tree_t *tree, 436 uint32_t pid) 437 { 438 ASSERT(tree); 439 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 440 441 smb_ofile_close_all(tree, pid); 442 smb_tree_close_odirs(tree, pid); 443 } 444 445 /* 446 * Check whether or not a tree supports the features identified by flags. 447 */ 448 boolean_t 449 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags) 450 { 451 ASSERT(tree); 452 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 453 454 return ((tree->t_flags & flags) == flags); 455 } 456 457 /* 458 * If the enumeration request is for tree data, handle the request 459 * here. Otherwise, pass it on to the ofiles. 460 * 461 * This function should be called with a hold on the tree. 462 */ 463 int 464 smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum) 465 { 466 smb_ofile_t *of; 467 smb_ofile_t *next; 468 int rc = 0; 469 470 ASSERT(tree); 471 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 472 473 if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE) 474 return (smb_tree_enum_private(tree, svcenum)); 475 476 of = smb_tree_get_ofile(tree, NULL); 477 while (of) { 478 ASSERT(of->f_tree == tree); 479 480 rc = smb_ofile_enum(of, svcenum); 481 if (rc != 0) { 482 smb_ofile_release(of); 483 break; 484 } 485 486 next = smb_tree_get_ofile(tree, of); 487 smb_ofile_release(of); 488 of = next; 489 } 490 491 return (rc); 492 } 493 494 /* 495 * Close a file by its unique id. 496 */ 497 int 498 smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid) 499 { 500 smb_ofile_t *of; 501 502 ASSERT(tree); 503 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 504 505 /* 506 * Note that ORPHANED ofiles aren't fclosable, as they have 507 * no session, user, or tree by which they might be found. 508 * They will eventually expire. 509 */ 510 if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL) 511 return (ENOENT); 512 513 if (smb_ofile_disallow_fclose(of)) { 514 smb_ofile_release(of); 515 return (EACCES); 516 } 517 518 smb_ofile_close(of, 0); 519 smb_ofile_release(of); 520 return (0); 521 } 522 523 /* *************************** Static Functions ***************************** */ 524 525 #define SHARES_DIR ".zfs/shares/" 526 527 /* 528 * Calculates permissions given by the share's ACL to the 529 * user in the passed request. The default is full access. 530 * If any error occurs, full access is granted. 531 * 532 * Using the vnode of the share path find the root directory 533 * of the mounted file system. Then look to see if there is a 534 * .zfs/shares directory and if there is, lookup the file with 535 * the same name as the share name in it. The ACL set for this 536 * file is the share's ACL which is used for access check here. 537 */ 538 static uint32_t 539 smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp) 540 { 541 smb_user_t *user; 542 cred_t *cred; 543 int rc; 544 vfs_t *vfsp; 545 vnode_t *root = NULL; 546 vnode_t *sharevp = NULL; 547 char *sharepath; 548 struct pathname pnp; 549 size_t size; 550 uint32_t access; 551 552 user = sr->uid_user; 553 cred = user->u_cred; 554 access = ACE_ALL_PERMS; 555 556 if (si->shr_flags & SMB_SHRF_AUTOHOME) { 557 /* 558 * An autohome share owner gets full access to the share. 559 * Everyone else is denied access. 560 */ 561 if (si->shr_uid != crgetuid(cred)) 562 access = 0; 563 564 return (access); 565 } 566 567 /* 568 * The hold on 'root' is released by the lookuppnvp() that follows 569 */ 570 vfsp = pathvp->v_vfsp; 571 if (vfsp != NULL) 572 rc = VFS_ROOT(vfsp, &root); 573 else 574 rc = ENOENT; 575 576 if (rc != 0) 577 return (access); 578 579 580 size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1; 581 sharepath = smb_srm_alloc(sr, size); 582 (void) snprintf(sharepath, size, "%s%s", SHARES_DIR, si->shr_name); 583 584 pn_alloc(&pnp); 585 (void) pn_set(&pnp, sharepath); 586 rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root, 587 zone_kcred()); 588 pn_free(&pnp); 589 590 /* 591 * Now get the effective access value based on cred and ACL values. 592 */ 593 if (rc == 0) { 594 smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL, 595 cred); 596 VN_RELE(sharevp); 597 } 598 599 return (access); 600 } 601 602 /* 603 * Performs the following access checks for a disk share: 604 * 605 * - No IPC/anonymous user is allowed 606 * 607 * - If user is Guest, guestok property of the share should be 608 * enabled 609 * 610 * - If this is an Admin share, the user should have administrative 611 * privileges 612 * 613 * - Host based access control lists 614 * 615 * - Share ACL 616 * 617 * Returns the access allowed or 0 if access is denied. 618 */ 619 static uint32_t 620 smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp) 621 { 622 smb_user_t *user = sr->uid_user; 623 char *sharename = shr->shr_name; 624 uint32_t host_access; 625 uint32_t acl_access; 626 uint32_t access; 627 628 if (user->u_flags & SMB_USER_FLAG_ANON) { 629 smb_tree_log(sr, sharename, "access denied: IPC only"); 630 return (0); 631 } 632 633 if ((user->u_flags & SMB_USER_FLAG_GUEST) && 634 ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) { 635 smb_tree_log(sr, sharename, "access denied: guest disabled"); 636 return (0); 637 } 638 639 if ((shr->shr_flags & SMB_SHRF_ADMIN) && !smb_user_is_admin(user)) { 640 smb_tree_log(sr, sharename, "access denied: not admin"); 641 return (0); 642 } 643 644 host_access = smb_kshare_hostaccess(shr, sr->session); 645 if ((host_access & ACE_ALL_PERMS) == 0) { 646 smb_tree_log(sr, sharename, "access denied: host access"); 647 return (0); 648 } 649 650 acl_access = smb_tree_acl_access(sr, shr, vp); 651 if ((acl_access & ACE_ALL_PERMS) == 0) { 652 smb_tree_log(sr, sharename, "access denied: share ACL"); 653 return (0); 654 } 655 656 access = host_access & acl_access; 657 if ((access & ACE_ALL_PERMS) == 0) { 658 smb_tree_log(sr, sharename, "access denied"); 659 return (0); 660 } 661 662 return (access); 663 } 664 665 /* 666 * Connect a share for use with files and directories. 667 */ 668 uint32_t 669 smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon) 670 { 671 char *sharename = tcon->path; 672 const char *any = "?????"; 673 smb_user_t *user = sr->uid_user; 674 smb_node_t *dnode = NULL; 675 smb_node_t *snode = NULL; 676 smb_kshare_t *si = tcon->si; 677 char *service = tcon->service; 678 char last_component[MAXNAMELEN]; 679 smb_tree_t *tree; 680 cred_t *kcr; 681 int rc; 682 uint32_t access; 683 smb_shr_execinfo_t execinfo; 684 685 ASSERT(user); 686 ASSERT(user->u_cred); 687 688 if (service != NULL && 689 strcmp(service, any) != 0 && 690 strcasecmp(service, "A:") != 0) { 691 smb_tree_log(sr, sharename, "invalid service (%s)", service); 692 return (NT_STATUS_BAD_DEVICE_TYPE); 693 } 694 695 /* 696 * Check that the shared directory exists. 697 * Client might not have access to the path _leading_ to the share, 698 * so we use "kcred" to get to the share root. 699 */ 700 kcr = zone_kcred(); 701 rc = smb_pathname_reduce(sr, kcr, si->shr_path, 0, 0, &dnode, 702 last_component); 703 if (rc == 0) { 704 rc = smb_fsop_lookup(sr, kcr, SMB_FOLLOW_LINKS, 705 sr->sr_server->si_root_smb_node, dnode, last_component, 706 &snode); 707 708 smb_node_release(dnode); 709 } 710 711 if (rc) { 712 if (snode) 713 smb_node_release(snode); 714 715 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); 716 return (NT_STATUS_BAD_NETWORK_NAME); 717 } 718 719 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) { 720 smb_node_release(snode); 721 return (NT_STATUS_ACCESS_DENIED); 722 } 723 724 /* 725 * Set up the OptionalSupport for this share. 726 */ 727 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; 728 729 switch (si->shr_flags & SMB_SHRF_CSC_MASK) { 730 case SMB_SHRF_CSC_DISABLED: 731 tcon->optional_support |= SMB_CSC_CACHE_NONE; 732 break; 733 case SMB_SHRF_CSC_AUTO: 734 tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT; 735 break; 736 case SMB_SHRF_CSC_VDO: 737 tcon->optional_support |= SMB_CSC_CACHE_VDO; 738 break; 739 case SMB_SHRF_CSC_MANUAL: 740 default: 741 /* 742 * Default to SMB_CSC_CACHE_MANUAL_REINT. 743 */ 744 break; 745 } 746 747 /* ABE support */ 748 if (si->shr_flags & SMB_SHRF_ABE) 749 tcon->optional_support |= 750 SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM; 751 752 if (si->shr_flags & SMB_SHRF_DFSROOT) 753 tcon->optional_support |= SMB_SHARE_IS_IN_DFS; 754 755 /* if 'smb' zfs property: shortnames=disabled */ 756 if (!smb_shortnames) 757 sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME; 758 759 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags); 760 761 smb_node_release(snode); 762 763 if (tree == NULL) 764 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 765 766 if (tree->t_execflags & SMB_EXEC_MAP) { 767 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP); 768 769 rc = smb_kshare_exec(tree->t_server, &execinfo); 770 771 if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) { 772 smb_tree_disconnect(tree, B_FALSE); 773 smb_tree_release(tree); 774 return (NT_STATUS_ACCESS_DENIED); 775 } 776 } 777 778 sr->tid_tree = tree; 779 sr->smb_tid = tree->t_tid; 780 781 return (0); 782 } 783 784 /* 785 * Shares have both a share and host based access control. The access 786 * granted will be minimum permissions based on both hostaccess 787 * (permissions allowed by host based access) and aclaccess (from the 788 * share ACL). 789 */ 790 uint32_t 791 smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon) 792 { 793 char *sharename = tcon->path; 794 const char *any = "?????"; 795 smb_user_t *user = sr->uid_user; 796 smb_node_t *dnode = NULL; 797 smb_node_t *snode = NULL; 798 smb_kshare_t *si = tcon->si; 799 char *service = tcon->service; 800 char last_component[MAXNAMELEN]; 801 smb_tree_t *tree; 802 int rc; 803 uint32_t access; 804 805 ASSERT(user); 806 ASSERT(user->u_cred); 807 808 if (sr->sr_server->sv_cfg.skc_print_enable == 0) { 809 smb_tree_log(sr, sharename, "printing disabled"); 810 return (NT_STATUS_BAD_NETWORK_NAME); 811 } 812 813 if (service != NULL && 814 strcmp(service, any) != 0 && 815 strcasecmp(service, "LPT1:") != 0) { 816 smb_tree_log(sr, sharename, "invalid service (%s)", service); 817 return (NT_STATUS_BAD_DEVICE_TYPE); 818 } 819 820 /* 821 * Check that the shared directory exists. 822 */ 823 rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode, 824 last_component); 825 if (rc == 0) { 826 rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS, 827 sr->sr_server->si_root_smb_node, dnode, last_component, 828 &snode); 829 830 smb_node_release(dnode); 831 } 832 833 if (rc) { 834 if (snode) 835 smb_node_release(snode); 836 837 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); 838 return (NT_STATUS_BAD_NETWORK_NAME); 839 } 840 841 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) { 842 smb_node_release(snode); 843 return (NT_STATUS_ACCESS_DENIED); 844 } 845 846 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; 847 848 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags); 849 850 smb_node_release(snode); 851 852 if (tree == NULL) 853 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 854 855 sr->tid_tree = tree; 856 sr->smb_tid = tree->t_tid; 857 858 return (0); 859 } 860 861 /* 862 * Connect an IPC share for use with named pipes. 863 */ 864 uint32_t 865 smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon) 866 { 867 char *name = tcon->path; 868 const char *any = "?????"; 869 smb_user_t *user = sr->uid_user; 870 smb_tree_t *tree; 871 smb_kshare_t *si = tcon->si; 872 char *service = tcon->service; 873 874 ASSERT(user); 875 876 if (service != NULL && 877 strcmp(service, any) != 0 && 878 strcasecmp(service, "IPC") != 0) { 879 smb_tree_log(sr, name, "invalid service (%s)", service); 880 return (NT_STATUS_BAD_DEVICE_TYPE); 881 } 882 883 if ((user->u_flags & SMB_USER_FLAG_ANON) && 884 sr->sr_cfg->skc_restrict_anon) { 885 smb_tree_log(sr, name, "access denied: restrict anonymous"); 886 return (NT_STATUS_ACCESS_DENIED); 887 } 888 889 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; 890 891 tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0); 892 if (tree == NULL) 893 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 894 895 sr->tid_tree = tree; 896 sr->smb_tid = tree->t_tid; 897 898 return (0); 899 } 900 901 /* 902 * Allocate a tree. 903 */ 904 static smb_tree_t * 905 smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si, 906 smb_node_t *snode, uint32_t access, uint32_t execflags) 907 { 908 smb_session_t *session = sr->session; 909 smb_tree_t *tree; 910 uint32_t stype = si->shr_type; 911 uint16_t tid; 912 913 if (smb_idpool_alloc(&session->s_tid_pool, &tid)) 914 return (NULL); 915 916 tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP); 917 bzero(tree, sizeof (smb_tree_t)); 918 919 tree->t_session = session; 920 tree->t_server = session->s_server; 921 922 /* grab a ref for tree->t_owner */ 923 smb_user_hold_internal(sr->uid_user); 924 tree->t_owner = sr->uid_user; 925 926 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) { 927 if (smb_tree_getattr(si, snode, tree) != 0) { 928 smb_idpool_free(&session->s_tid_pool, tid); 929 kmem_cache_free(smb_cache_tree, tree); 930 return (NULL); 931 } 932 } 933 934 if (smb_idpool_constructor(&tree->t_fid_pool)) { 935 smb_idpool_free(&session->s_tid_pool, tid); 936 kmem_cache_free(smb_cache_tree, tree); 937 return (NULL); 938 } 939 940 if (smb_idpool_constructor(&tree->t_odid_pool)) { 941 smb_idpool_destructor(&tree->t_fid_pool); 942 smb_idpool_free(&session->s_tid_pool, tid); 943 kmem_cache_free(smb_cache_tree, tree); 944 return (NULL); 945 } 946 947 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), 948 offsetof(smb_ofile_t, f_tree_lnd)); 949 950 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), 951 offsetof(smb_odir_t, d_lnd)); 952 953 (void) strlcpy(tree->t_sharename, si->shr_name, 954 sizeof (tree->t_sharename)); 955 (void) strlcpy(tree->t_resource, si->shr_path, 956 sizeof (tree->t_resource)); 957 958 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); 959 960 tree->t_refcnt = 1; 961 tree->t_tid = tid; 962 tree->t_res_type = stype; 963 tree->t_state = SMB_TREE_STATE_CONNECTED; 964 tree->t_magic = SMB_TREE_MAGIC; 965 tree->t_access = access; 966 tree->t_connect_time = gethrestime_sec(); 967 tree->t_execflags = execflags; 968 969 /* if FS is readonly, enforce that here */ 970 if (tree->t_flags & SMB_TREE_READONLY) 971 tree->t_access &= ~ACE_ALL_WRITE_PERMS; 972 973 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) { 974 smb_node_ref(snode); 975 tree->t_snode = snode; 976 tree->t_acltype = smb_fsop_acltype(snode); 977 } 978 979 smb_llist_enter(&session->s_tree_list, RW_WRITER); 980 smb_llist_insert_head(&session->s_tree_list, tree); 981 smb_llist_exit(&session->s_tree_list); 982 atomic_inc_32(&session->s_tree_cnt); 983 smb_server_inc_trees(session->s_server); 984 return (tree); 985 } 986 987 /* 988 * Deallocate a tree. The open file and open directory lists should be 989 * empty. 990 * 991 * Remove the tree from the user's tree list before freeing resources 992 * associated with the tree. 993 */ 994 static void 995 smb_tree_dealloc(void *arg) 996 { 997 smb_session_t *session; 998 smb_tree_t *tree = (smb_tree_t *)arg; 999 1000 SMB_TREE_VALID(tree); 1001 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 1002 ASSERT(tree->t_refcnt == 0); 1003 1004 session = tree->t_session; 1005 smb_llist_enter(&session->s_tree_list, RW_WRITER); 1006 smb_llist_remove(&session->s_tree_list, tree); 1007 smb_idpool_free(&session->s_tid_pool, tree->t_tid); 1008 atomic_dec_32(&session->s_tree_cnt); 1009 smb_llist_exit(&session->s_tree_list); 1010 1011 /* 1012 * This tree is no longer on s_tree_list, however... 1013 * 1014 * This is called via smb_llist_post, which means it may run 1015 * BEFORE smb_tree_release drops t_mutex (if another thread 1016 * flushes the delete queue before we do). Synchronize. 1017 */ 1018 mutex_enter(&tree->t_mutex); 1019 mutex_exit(&tree->t_mutex); 1020 1021 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; 1022 1023 if (tree->t_snode) 1024 smb_node_release(tree->t_snode); 1025 1026 mutex_destroy(&tree->t_mutex); 1027 smb_llist_destructor(&tree->t_ofile_list); 1028 smb_llist_destructor(&tree->t_odir_list); 1029 smb_idpool_destructor(&tree->t_fid_pool); 1030 smb_idpool_destructor(&tree->t_odid_pool); 1031 1032 SMB_USER_VALID(tree->t_owner); 1033 smb_user_release(tree->t_owner); 1034 1035 kmem_cache_free(smb_cache_tree, tree); 1036 } 1037 1038 /* 1039 * Determine whether or not a tree is connected. 1040 * This function must be called with the tree mutex held. 1041 */ 1042 static boolean_t 1043 smb_tree_is_connected_locked(smb_tree_t *tree) 1044 { 1045 switch (tree->t_state) { 1046 case SMB_TREE_STATE_CONNECTED: 1047 return (B_TRUE); 1048 1049 case SMB_TREE_STATE_DISCONNECTING: 1050 case SMB_TREE_STATE_DISCONNECTED: 1051 /* 1052 * The tree exists but is being disconnected or destroyed. 1053 */ 1054 return (B_FALSE); 1055 1056 default: 1057 ASSERT(0); 1058 return (B_FALSE); 1059 } 1060 } 1061 1062 /* 1063 * Return a pointer to the share name within a share resource path. 1064 * 1065 * The share path may be a Uniform Naming Convention (UNC) string 1066 * (\\server\share) or simply the share name. We validate the UNC 1067 * format but we don't look at the server name. 1068 */ 1069 static char * 1070 smb_tree_get_sharename(char *unc_path) 1071 { 1072 char *sharename = unc_path; 1073 1074 if (sharename[0] == '\\') { 1075 /* 1076 * Looks like a UNC path, validate the format. 1077 */ 1078 if (sharename[1] != '\\') 1079 return (NULL); 1080 1081 if ((sharename = strchr(sharename+2, '\\')) == NULL) 1082 return (NULL); 1083 1084 ++sharename; 1085 } else if (strchr(sharename, '\\') != NULL) { 1086 /* 1087 * This should be a share name (no embedded \'s). 1088 */ 1089 return (NULL); 1090 } 1091 1092 return (sharename); 1093 } 1094 1095 /* 1096 * Obtain the tree attributes: volume name, typename and flags. 1097 */ 1098 static int 1099 smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree) 1100 { 1101 vfs_t *vfsp = SMB_NODE_VFS(node); 1102 smb_cfg_val_t srv_encrypt; 1103 1104 ASSERT(vfsp); 1105 1106 if (getvfs(&vfsp->vfs_fsid) != vfsp) 1107 return (ESTALE); 1108 1109 smb_tree_get_volname(vfsp, tree); 1110 smb_tree_get_flags(si, vfsp, tree); 1111 1112 srv_encrypt = tree->t_session->s_server->sv_cfg.skc_encrypt; 1113 if (tree->t_session->dialect >= SMB_VERS_3_0) { 1114 if (si->shr_encrypt == SMB_CONFIG_REQUIRED || 1115 srv_encrypt == SMB_CONFIG_REQUIRED) 1116 tree->t_encrypt = SMB_CONFIG_REQUIRED; 1117 else if (si->shr_encrypt == SMB_CONFIG_ENABLED || 1118 srv_encrypt == SMB_CONFIG_ENABLED) 1119 tree->t_encrypt = SMB_CONFIG_ENABLED; 1120 else 1121 tree->t_encrypt = SMB_CONFIG_DISABLED; 1122 } else 1123 tree->t_encrypt = SMB_CONFIG_DISABLED; 1124 1125 VFS_RELE(vfsp); 1126 return (0); 1127 } 1128 1129 /* 1130 * Extract the volume name. 1131 */ 1132 static void 1133 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree) 1134 { 1135 #ifdef _FAKE_KERNEL 1136 _NOTE(ARGUNUSED(vfsp)) 1137 (void) strlcpy(tree->t_volume, "fake", SMB_VOLNAMELEN); 1138 #else /* _FAKE_KERNEL */ 1139 refstr_t *vfs_mntpoint; 1140 const char *s; 1141 char *name; 1142 1143 vfs_mntpoint = vfs_getmntpoint(vfsp); 1144 1145 s = refstr_value(vfs_mntpoint); 1146 s += strspn(s, "/"); 1147 (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN); 1148 1149 refstr_rele(vfs_mntpoint); 1150 1151 name = tree->t_volume; 1152 (void) strsep((char **)&name, "/"); 1153 #endif /* _FAKE_KERNEL */ 1154 } 1155 1156 /* 1157 * Always set "unicode on disk" because we always use utf8 names locally. 1158 * Always set ACL support because the VFS will fake ACLs for file systems 1159 * that don't support them. 1160 * 1161 * Some flags are dependent on the typename, which is also set up here. 1162 * File system types are hardcoded in uts/common/os/vfs_conf.c. 1163 */ 1164 static void 1165 smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree) 1166 { 1167 smb_session_t *ssn = tree->t_session; 1168 struct vfssw *vswp; 1169 1170 typedef struct smb_mtype { 1171 char *mt_name; 1172 size_t mt_namelen; 1173 uint32_t mt_flags; 1174 } smb_mtype_t; 1175 1176 static smb_mtype_t smb_mtype[] = { 1177 { "zfs", 3, SMB_TREE_QUOTA | SMB_TREE_SPARSE}, 1178 { "ufs", 3, 0 }, 1179 { "nfs", 3, SMB_TREE_NFS_MOUNTED }, 1180 { "tmpfs", 5, SMB_TREE_NO_EXPORT } 1181 }; 1182 smb_mtype_t *mtype; 1183 char *name; 1184 uint32_t flags = 1185 SMB_TREE_SUPPORTS_ACLS | 1186 SMB_TREE_UNICODE_ON_DISK; 1187 int i; 1188 1189 if (si->shr_flags & SMB_SHRF_DFSROOT) 1190 flags |= SMB_TREE_DFSROOT; 1191 1192 if (si->shr_flags & SMB_SHRF_CATIA) 1193 flags |= SMB_TREE_CATIA; 1194 1195 if (si->shr_flags & SMB_SHRF_ABE) 1196 flags |= SMB_TREE_ABE; 1197 1198 if (si->shr_flags & SMB_SHRF_FSO) 1199 flags |= SMB_TREE_FORCE_L2_OPLOCK; 1200 1201 if (ssn->s_cfg.skc_oplock_enable) { 1202 /* if 'smb' zfs property: oplocks=enabled */ 1203 flags |= SMB_TREE_OPLOCKS; 1204 } 1205 1206 /* Global config option for now. Later make per-share. */ 1207 if (ssn->s_cfg.skc_traverse_mounts) 1208 flags |= SMB_TREE_TRAVERSE_MOUNTS; 1209 1210 /* if 'smb' zfs property: shortnames=enabled */ 1211 if (smb_shortnames) 1212 flags |= SMB_TREE_SHORTNAMES; 1213 1214 if (vfsp->vfs_flag & VFS_RDONLY) 1215 flags |= SMB_TREE_READONLY; 1216 1217 if (vfsp->vfs_flag & VFS_XATTR) 1218 flags |= SMB_TREE_STREAMS; 1219 1220 vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp)); 1221 if (vswp != NULL) { 1222 name = vswp->vsw_name; 1223 vfs_unrefvfssw(vswp); 1224 } else { 1225 name = "?"; 1226 } 1227 1228 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) { 1229 mtype = &smb_mtype[i]; 1230 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0) 1231 flags |= mtype->mt_flags; 1232 } 1233 1234 /* 1235 * SMB_TREE_QUOTA will be on here if the FS is ZFS. We want to 1236 * turn it OFF when the share property says false. 1237 */ 1238 if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0) 1239 flags &= ~SMB_TREE_QUOTA; 1240 1241 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 1242 (void) smb_strupr((char *)tree->t_typename); 1243 1244 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 1245 flags |= SMB_TREE_XVATTR; 1246 1247 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 1248 flags |= SMB_TREE_CASEINSENSITIVE; 1249 1250 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 1251 flags |= SMB_TREE_NO_CASESENSITIVE; 1252 1253 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 1254 flags |= SMB_TREE_DIRENTFLAGS; 1255 1256 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 1257 flags |= SMB_TREE_ACLONCREATE; 1258 1259 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 1260 flags |= SMB_TREE_ACEMASKONACCESS; 1261 1262 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name); 1263 1264 1265 tree->t_flags = flags; 1266 } 1267 1268 /* 1269 * Report share access result to syslog. 1270 */ 1271 static void 1272 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 1273 { 1274 va_list ap; 1275 char buf[128]; 1276 smb_user_t *user = sr->uid_user; 1277 1278 ASSERT(user); 1279 1280 if (smb_tcon_mute) 1281 return; 1282 1283 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 1284 /* 1285 * Only report normal users, i.e. ignore W2K misuse 1286 * of the IPC connection by filtering out internal 1287 * names such as nobody and root. 1288 */ 1289 if ((strcmp(user->u_name, "root") == 0) || 1290 (strcmp(user->u_name, "nobody") == 0)) { 1291 return; 1292 } 1293 } 1294 1295 va_start(ap, fmt); 1296 (void) vsnprintf(buf, 128, fmt, ap); 1297 va_end(ap); 1298 1299 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 1300 user->u_domain, user->u_name, sharename, buf); 1301 } 1302 1303 /* 1304 * smb_tree_lookup_odir 1305 * 1306 * Find the specified odir in the tree's list of odirs, and 1307 * attempt to obtain a hold on the odir. 1308 * 1309 * Returns NULL if odir not found or a hold cannot be obtained. 1310 */ 1311 smb_odir_t * 1312 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid) 1313 { 1314 smb_odir_t *od; 1315 smb_llist_t *od_list; 1316 smb_tree_t *tree = sr->tid_tree; 1317 1318 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1319 1320 od_list = &tree->t_odir_list; 1321 1322 smb_llist_enter(od_list, RW_READER); 1323 od = smb_llist_head(od_list); 1324 while (od) { 1325 if (od->d_odid == odid) 1326 break; 1327 od = smb_llist_next(od_list, od); 1328 } 1329 if (od == NULL) 1330 goto out; 1331 1332 /* 1333 * Only allow use of a given Search ID with the same UID that 1334 * was used to create it. MS-CIFS 3.3.5.14 1335 */ 1336 if (od->d_user != sr->uid_user) { 1337 od = NULL; 1338 goto out; 1339 } 1340 if (!smb_odir_hold(od)) 1341 od = NULL; 1342 1343 out: 1344 smb_llist_exit(od_list); 1345 return (od); 1346 } 1347 1348 boolean_t 1349 smb_tree_is_connected(smb_tree_t *tree) 1350 { 1351 boolean_t rb; 1352 1353 mutex_enter(&tree->t_mutex); 1354 rb = smb_tree_is_connected_locked(tree); 1355 mutex_exit(&tree->t_mutex); 1356 return (rb); 1357 } 1358 1359 /* 1360 * Get the next open ofile in the list. A reference is taken on 1361 * the ofile, which can be released later with smb_ofile_release(). 1362 * 1363 * If the specified ofile is NULL, search from the beginning of the 1364 * list. Otherwise, the search starts just after that ofile. 1365 * 1366 * Returns NULL if there are no open files in the list. 1367 */ 1368 static smb_ofile_t * 1369 smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of) 1370 { 1371 smb_llist_t *ofile_list; 1372 1373 ASSERT(tree); 1374 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1375 1376 ofile_list = &tree->t_ofile_list; 1377 smb_llist_enter(ofile_list, RW_READER); 1378 1379 if (of) { 1380 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1381 of = smb_llist_next(ofile_list, of); 1382 } else { 1383 of = smb_llist_head(ofile_list); 1384 } 1385 1386 while (of) { 1387 if (smb_ofile_hold(of)) 1388 break; 1389 1390 of = smb_llist_next(ofile_list, of); 1391 } 1392 1393 smb_llist_exit(ofile_list); 1394 return (of); 1395 } 1396 1397 /* 1398 * smb_tree_get_odir 1399 * 1400 * Find the next odir in the tree's list of odirs, and obtain a 1401 * hold on it. 1402 * If the specified odir is NULL the search starts at the beginning 1403 * of the tree's odir list, otherwise the search starts after the 1404 * specified odir. 1405 */ 1406 static smb_odir_t * 1407 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od) 1408 { 1409 smb_llist_t *od_list; 1410 1411 ASSERT(tree); 1412 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1413 1414 od_list = &tree->t_odir_list; 1415 smb_llist_enter(od_list, RW_READER); 1416 1417 if (od) { 1418 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1419 od = smb_llist_next(od_list, od); 1420 } else { 1421 od = smb_llist_head(od_list); 1422 } 1423 1424 while (od) { 1425 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1426 1427 if (smb_odir_hold(od)) 1428 break; 1429 od = smb_llist_next(od_list, od); 1430 } 1431 1432 smb_llist_exit(od_list); 1433 return (od); 1434 } 1435 1436 /* 1437 * smb_tree_close_odirs 1438 * 1439 * Close all open odirs in the tree's list which were opened by 1440 * the process identified by pid. 1441 * If pid is zero, close all open odirs in the tree's list. 1442 */ 1443 static void 1444 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) 1445 { 1446 smb_odir_t *od, *next_od; 1447 1448 ASSERT(tree); 1449 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1450 1451 od = smb_tree_get_odir(tree, NULL); 1452 while (od) { 1453 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1454 ASSERT(od->d_tree == tree); 1455 1456 next_od = smb_tree_get_odir(tree, od); 1457 if ((pid == 0) || (od->d_opened_by_pid == pid)) 1458 smb_odir_close(od); 1459 smb_odir_release(od); 1460 1461 od = next_od; 1462 } 1463 } 1464 1465 static void 1466 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, 1467 int exec_type) 1468 { 1469 exec->e_sharename = tree->t_sharename; 1470 exec->e_winname = tree->t_owner->u_name; 1471 exec->e_userdom = tree->t_owner->u_domain; 1472 exec->e_srv_ipaddr = tree->t_session->local_ipaddr; 1473 exec->e_cli_ipaddr = tree->t_session->ipaddr; 1474 exec->e_cli_netbiosname = tree->t_session->workstation; 1475 exec->e_uid = crgetuid(tree->t_owner->u_cred); 1476 exec->e_type = exec_type; 1477 } 1478 1479 /* 1480 * Private function to support smb_tree_enum. 1481 */ 1482 static int 1483 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum) 1484 { 1485 uint8_t *pb; 1486 uint_t nbytes; 1487 int rc; 1488 1489 if (svcenum->se_nskip > 0) { 1490 svcenum->se_nskip--; 1491 return (0); 1492 } 1493 1494 if (svcenum->se_nitems >= svcenum->se_nlimit) { 1495 svcenum->se_nitems = svcenum->se_nlimit; 1496 return (0); 1497 } 1498 1499 pb = &svcenum->se_buf[svcenum->se_bused]; 1500 rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes); 1501 if (rc == 0) { 1502 svcenum->se_bavail -= nbytes; 1503 svcenum->se_bused += nbytes; 1504 svcenum->se_nitems++; 1505 } 1506 1507 return (rc); 1508 } 1509 1510 /* 1511 * Encode connection information into a buffer: connection information 1512 * needed in user space to support RPC requests. 1513 */ 1514 static int 1515 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen, 1516 uint32_t *nbytes) 1517 { 1518 smb_netconnectinfo_t info; 1519 int rc; 1520 1521 smb_tree_netinfo_init(tree, &info); 1522 rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes); 1523 smb_tree_netinfo_fini(&info); 1524 1525 return (rc); 1526 } 1527 1528 static void 1529 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen) 1530 { 1531 smb_user_t *user = tree->t_owner; 1532 1533 /* 1534 * u_domain_len and u_name_len include the '\0' in their 1535 * lengths, hence the sum of the two lengths gives us room 1536 * for both the '\\' and '\0' chars. 1537 */ 1538 ASSERT(namestr); 1539 ASSERT(namelen); 1540 ASSERT(user->u_domain_len > 0); 1541 ASSERT(user->u_name_len > 0); 1542 *namelen = user->u_domain_len + user->u_name_len; 1543 *namestr = kmem_alloc(*namelen, KM_SLEEP); 1544 (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain, 1545 user->u_name); 1546 } 1547 1548 /* 1549 * Note: ci_numusers should be the number of users connected to 1550 * the share rather than the number of references on the tree but 1551 * we don't have a mechanism to track users/share in smbsrv yet. 1552 */ 1553 static void 1554 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info) 1555 { 1556 ASSERT(tree); 1557 1558 info->ci_id = tree->t_tid; 1559 info->ci_type = tree->t_res_type; 1560 info->ci_numopens = tree->t_open_files; 1561 info->ci_numusers = tree->t_refcnt; 1562 info->ci_time = gethrestime_sec() - tree->t_connect_time; 1563 1564 info->ci_sharelen = strlen(tree->t_sharename) + 1; 1565 info->ci_share = smb_mem_strdup(tree->t_sharename); 1566 1567 smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen); 1568 } 1569 1570 static void 1571 smb_tree_netinfo_fini(smb_netconnectinfo_t *info) 1572 { 1573 if (info == NULL) 1574 return; 1575 1576 if (info->ci_username) 1577 kmem_free(info->ci_username, info->ci_namelen); 1578 if (info->ci_share) 1579 smb_mem_free(info->ci_share); 1580 1581 bzero(info, sizeof (smb_netconnectinfo_t)); 1582 } 1583