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 void smb_tree_dealloc(void *); 188 static boolean_t smb_tree_is_connected_locked(smb_tree_t *); 189 static char *smb_tree_get_sharename(char *); 190 static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *); 191 static void smb_tree_get_volname(vfs_t *, smb_tree_t *); 192 static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *); 193 static void smb_tree_log(smb_request_t *, const char *, const char *, ...); 194 static void smb_tree_close_odirs(smb_tree_t *, uint32_t); 195 static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int); 196 static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *); 197 static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *); 198 static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *); 199 static void smb_tree_netinfo_fini(smb_netconnectinfo_t *); 200 201 uint32_t 202 smb_tree_connect(smb_request_t *sr) 203 { 204 smb_server_t *sv = sr->sr_server; 205 uint32_t status; 206 207 if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) { 208 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 209 } 210 211 status = smb_tree_connect_core(sr); 212 smb_threshold_exit(&sv->sv_tcon_ct); 213 return (status); 214 } 215 216 /* 217 * Lookup the share name dispatch the appropriate stype handler. 218 * Share names are case insensitive so we map the share name to 219 * lower-case as a convenience for internal processing. 220 * 221 * Valid service values are: 222 * A: Disk share 223 * LPT1: Printer 224 * IPC Named pipe (IPC$ is reserved as the named pipe share). 225 * COMM Communications device 226 * ????? Any type of device (wildcard) 227 */ 228 uint32_t 229 smb_tree_connect_core(smb_request_t *sr) 230 { 231 smb_arg_tcon_t *tcon = &sr->sr_tcon; 232 smb_kshare_t *si; 233 char *name; 234 uint32_t status; 235 236 (void) smb_strlwr(tcon->path); 237 238 if ((name = smb_tree_get_sharename(tcon->path)) == NULL) { 239 smb_tree_log(sr, tcon->path, "invalid UNC path"); 240 return (NT_STATUS_BAD_NETWORK_NAME); 241 } 242 243 si = smb_kshare_lookup(sr->sr_server, name); 244 if (si == NULL) { 245 smb_tree_log(sr, name, "share not found"); 246 return (NT_STATUS_BAD_NETWORK_NAME); 247 } 248 249 if (!strcasecmp(SMB_SHARE_PRINT, name)) { 250 smb_kshare_release(sr->sr_server, si); 251 smb_tree_log(sr, name, "access not permitted"); 252 return (NT_STATUS_ACCESS_DENIED); 253 } 254 255 /* NB: name points into tcon->path - don't free it. */ 256 tcon->name = name; 257 sr->sr_tcon.si = si; 258 259 /* 260 * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request 261 * 262 * If we support 3.x, RejectUnencryptedAccess is TRUE, 263 * if Tcon.EncryptData is TRUE or global EncryptData is TRUE, 264 * and the connection doesn't support encryption, 265 * return ACCESS_DENIED. 266 * 267 * If RejectUnencryptedAccess is TRUE, we force max_protocol 268 * to at least 3.0. Additionally, if the tree requires encryption, 269 * we don't care what we support, we still enforce encryption. 270 */ 271 if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED || 272 si->shr_encrypt == SMB_CONFIG_REQUIRED) && 273 (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) { 274 status = NT_STATUS_ACCESS_DENIED; 275 goto out; 276 } 277 278 switch (si->shr_type & STYPE_MASK) { 279 case STYPE_DISKTREE: 280 status = smb_tree_connect_disk(sr, &sr->sr_tcon); 281 break; 282 case STYPE_IPC: 283 status = smb_tree_connect_ipc(sr, &sr->sr_tcon); 284 break; 285 case STYPE_PRINTQ: 286 status = smb_tree_connect_printq(sr, &sr->sr_tcon); 287 break; 288 default: 289 status = NT_STATUS_BAD_DEVICE_TYPE; 290 break; 291 } 292 293 out: 294 smb_kshare_release(sr->sr_server, si); 295 sr->sr_tcon.si = NULL; 296 297 return (status); 298 } 299 300 /* 301 * Disconnect a tree. 302 * 303 * The "do_exec" arg is obsolete and ignored. 304 */ 305 void 306 smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec) 307 { 308 _NOTE(ARGUNUSED(do_exec)) 309 smb_shr_execinfo_t execinfo; 310 311 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 312 313 mutex_enter(&tree->t_mutex); 314 ASSERT(tree->t_refcnt); 315 316 if (!smb_tree_is_connected_locked(tree)) { 317 mutex_exit(&tree->t_mutex); 318 return; 319 } 320 321 /* 322 * Indicate that the disconnect process has started. 323 */ 324 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 325 mutex_exit(&tree->t_mutex); 326 327 /* 328 * The files opened under this tree are closed. 329 */ 330 smb_ofile_close_all(tree, 0); 331 /* 332 * The directories opened under this tree are closed. 333 */ 334 smb_tree_close_odirs(tree, 0); 335 336 if ((tree->t_execflags & SMB_EXEC_UNMAP) != 0) { 337 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP); 338 (void) smb_kshare_exec(tree->t_server, &execinfo); 339 } 340 } 341 342 /* 343 * Take a reference on a tree. 344 */ 345 boolean_t 346 smb_tree_hold( 347 smb_tree_t *tree) 348 { 349 SMB_TREE_VALID(tree); 350 351 mutex_enter(&tree->t_mutex); 352 353 if (smb_tree_is_connected_locked(tree)) { 354 tree->t_refcnt++; 355 mutex_exit(&tree->t_mutex); 356 return (B_TRUE); 357 } 358 359 mutex_exit(&tree->t_mutex); 360 return (B_FALSE); 361 } 362 363 /* 364 * Bump the hold count regardless of the tree state. This is used in 365 * some internal code paths where we've already checked that we had a 366 * valid tree connection, and don't want to deal with the possiblity 367 * that the tree state might have changed to disconnecting after our 368 * original hold was taken. It's correct to continue processing a 369 * request even when new requests cannot lookup that tree anymore. 370 */ 371 void 372 smb_tree_hold_internal( 373 smb_tree_t *tree) 374 { 375 SMB_TREE_VALID(tree); 376 377 mutex_enter(&tree->t_mutex); 378 tree->t_refcnt++; 379 mutex_exit(&tree->t_mutex); 380 } 381 382 /* 383 * Release a reference on a tree. If the tree is disconnected and the 384 * reference count falls to zero, post the object for deletion. 385 * Object deletion is deferred to avoid modifying a list while an 386 * iteration may be in progress. 387 */ 388 void 389 smb_tree_release( 390 smb_tree_t *tree) 391 { 392 SMB_TREE_VALID(tree); 393 394 /* flush the ofile and odir lists' delete queues */ 395 smb_llist_flush(&tree->t_ofile_list); 396 smb_llist_flush(&tree->t_odir_list); 397 398 mutex_enter(&tree->t_mutex); 399 ASSERT(tree->t_refcnt); 400 tree->t_refcnt--; 401 402 switch (tree->t_state) { 403 case SMB_TREE_STATE_DISCONNECTING: 404 if (tree->t_refcnt == 0) { 405 smb_session_t *ssn = tree->t_session; 406 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 407 smb_llist_post(&ssn->s_tree_list, tree, 408 smb_tree_dealloc); 409 } 410 break; 411 case SMB_TREE_STATE_CONNECTED: 412 break; 413 default: 414 ASSERT(0); 415 break; 416 } 417 418 mutex_exit(&tree->t_mutex); 419 } 420 421 /* 422 * Close ofiles and odirs that match pid. 423 */ 424 void 425 smb_tree_close_pid( 426 smb_tree_t *tree, 427 uint32_t pid) 428 { 429 ASSERT(tree); 430 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 431 432 smb_ofile_close_all(tree, pid); 433 smb_tree_close_odirs(tree, pid); 434 } 435 436 /* 437 * Check whether or not a tree supports the features identified by flags. 438 */ 439 boolean_t 440 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags) 441 { 442 ASSERT(tree); 443 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 444 445 return ((tree->t_flags & flags) == flags); 446 } 447 448 /* 449 * If the enumeration request is for tree data, handle the request 450 * here. Otherwise, pass it on to the ofiles. 451 * 452 * This function should be called with a hold on the tree. 453 */ 454 int 455 smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum) 456 { 457 smb_llist_t *of_list; 458 smb_ofile_t *of; 459 int rc = 0; 460 461 if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE) 462 return (smb_tree_enum_private(tree, svcenum)); 463 464 of_list = &tree->t_ofile_list; 465 smb_llist_enter(of_list, RW_READER); 466 467 of = smb_llist_head(of_list); 468 while (of) { 469 if (smb_ofile_hold(of)) { 470 rc = smb_ofile_enum(of, svcenum); 471 smb_ofile_release(of); 472 } 473 if (rc != 0) 474 break; 475 of = smb_llist_next(of_list, of); 476 } 477 478 smb_llist_exit(of_list); 479 480 return (rc); 481 } 482 483 /* 484 * Close a file by its unique id. 485 */ 486 int 487 smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid) 488 { 489 smb_ofile_t *of; 490 491 ASSERT(tree); 492 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 493 494 /* 495 * Note that ORPHANED ofiles aren't fclosable, as they have 496 * no session, user, or tree by which they might be found. 497 * They will eventually expire. 498 */ 499 if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL) 500 return (ENOENT); 501 502 if (smb_ofile_disallow_fclose(of)) { 503 smb_ofile_release(of); 504 return (EACCES); 505 } 506 507 smb_ofile_close(of, 0); 508 smb_ofile_release(of); 509 return (0); 510 } 511 512 /* *************************** Static Functions ***************************** */ 513 514 #define SHARES_DIR ".zfs/shares/" 515 516 /* 517 * Calculates permissions given by the share's ACL to the 518 * user in the passed request. The default is full access. 519 * If any error occurs, full access is granted. 520 * 521 * Using the vnode of the share path find the root directory 522 * of the mounted file system. Then look to see if there is a 523 * .zfs/shares directory and if there is, lookup the file with 524 * the same name as the share name in it. The ACL set for this 525 * file is the share's ACL which is used for access check here. 526 */ 527 static uint32_t 528 smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp) 529 { 530 smb_user_t *user; 531 cred_t *cred; 532 int rc; 533 vfs_t *vfsp; 534 vnode_t *root = NULL; 535 vnode_t *sharevp = NULL; 536 char *sharepath; 537 struct pathname pnp; 538 size_t size; 539 uint32_t access; 540 541 user = sr->uid_user; 542 cred = user->u_cred; 543 access = ACE_ALL_PERMS; 544 545 if (si->shr_flags & SMB_SHRF_AUTOHOME) { 546 /* 547 * An autohome share owner gets full access to the share. 548 * Everyone else is denied access. 549 */ 550 if (si->shr_uid != crgetuid(cred)) 551 access = 0; 552 553 return (access); 554 } 555 556 /* 557 * The hold on 'root' is released by the lookuppnvp() that follows 558 */ 559 vfsp = pathvp->v_vfsp; 560 if (vfsp != NULL) 561 rc = VFS_ROOT(vfsp, &root); 562 else 563 rc = ENOENT; 564 565 if (rc != 0) 566 return (access); 567 568 569 size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1; 570 sharepath = smb_srm_alloc(sr, size); 571 (void) snprintf(sharepath, size, "%s%s", SHARES_DIR, si->shr_name); 572 573 pn_alloc(&pnp); 574 (void) pn_set(&pnp, sharepath); 575 rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root, 576 zone_kcred()); 577 pn_free(&pnp); 578 579 /* 580 * Now get the effective access value based on cred and ACL values. 581 */ 582 if (rc == 0) { 583 smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL, 584 cred); 585 VN_RELE(sharevp); 586 } 587 588 return (access); 589 } 590 591 /* 592 * Performs the following access checks for a disk share: 593 * 594 * - No IPC/anonymous user is allowed 595 * 596 * - If user is Guest, guestok property of the share should be 597 * enabled 598 * 599 * - If this is an Admin share, the user should have administrative 600 * privileges 601 * 602 * - Host based access control lists 603 * 604 * - Share ACL 605 * 606 * Returns the access allowed or 0 if access is denied. 607 */ 608 static uint32_t 609 smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp) 610 { 611 smb_user_t *user = sr->uid_user; 612 char *sharename = shr->shr_name; 613 uint32_t host_access; 614 uint32_t acl_access; 615 uint32_t access; 616 617 if (user->u_flags & SMB_USER_FLAG_ANON) { 618 smb_tree_log(sr, sharename, "access denied: IPC only"); 619 return (0); 620 } 621 622 if ((user->u_flags & SMB_USER_FLAG_GUEST) && 623 ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) { 624 smb_tree_log(sr, sharename, "access denied: guest disabled"); 625 return (0); 626 } 627 628 if ((shr->shr_flags & SMB_SHRF_ADMIN) && !smb_user_is_admin(user)) { 629 smb_tree_log(sr, sharename, "access denied: not admin"); 630 return (0); 631 } 632 633 host_access = smb_kshare_hostaccess(shr, sr->session); 634 if ((host_access & ACE_ALL_PERMS) == 0) { 635 smb_tree_log(sr, sharename, "access denied: host access"); 636 return (0); 637 } 638 639 acl_access = smb_tree_acl_access(sr, shr, vp); 640 if ((acl_access & ACE_ALL_PERMS) == 0) { 641 smb_tree_log(sr, sharename, "access denied: share ACL"); 642 return (0); 643 } 644 645 access = host_access & acl_access; 646 if ((access & ACE_ALL_PERMS) == 0) { 647 smb_tree_log(sr, sharename, "access denied"); 648 return (0); 649 } 650 651 return (access); 652 } 653 654 /* How long should tree connect wait for DH import to complete? */ 655 int smb_tcon_import_wait = 20; /* sec. */ 656 657 /* 658 * Connect a share for use with files and directories. 659 */ 660 uint32_t 661 smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon) 662 { 663 char *sharename = tcon->path; 664 const char *any = "?????"; 665 smb_user_t *user = sr->uid_user; 666 smb_node_t *snode = NULL; 667 smb_kshare_t *si = tcon->si; 668 char *service = tcon->service; 669 smb_tree_t *tree; 670 int rc; 671 uint32_t access; 672 smb_shr_execinfo_t execinfo; 673 clock_t time; 674 675 ASSERT(user); 676 ASSERT(user->u_cred); 677 678 if (service != NULL && 679 strcmp(service, any) != 0 && 680 strcasecmp(service, "A:") != 0) { 681 smb_tree_log(sr, sharename, "invalid service (%s)", service); 682 return (NT_STATUS_BAD_DEVICE_TYPE); 683 } 684 685 /* 686 * Check that the shared directory exists. 687 */ 688 snode = si->shr_root_node; 689 if (snode == NULL) { 690 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); 691 return (NT_STATUS_BAD_NETWORK_NAME); 692 } 693 694 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) { 695 return (NT_STATUS_ACCESS_DENIED); 696 } 697 698 /* 699 * Wait for DH import of persistent handles to finish. 700 * If we timeout, it's not clear what status to return, 701 * but as the share is not really available yet, let's 702 * return the status for "no such share". 703 */ 704 time = SEC_TO_TICK(smb_tcon_import_wait) + ddi_get_lbolt(); 705 mutex_enter(&si->shr_mutex); 706 while (si->shr_import_busy != NULL) { 707 if (cv_timedwait(&si->shr_cv, &si->shr_mutex, time) < 0) { 708 mutex_exit(&si->shr_mutex); 709 return (NT_STATUS_BAD_NETWORK_NAME); 710 } 711 } 712 mutex_exit(&si->shr_mutex); 713 714 /* 715 * Set up the OptionalSupport for this share. 716 */ 717 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; 718 719 switch (si->shr_flags & SMB_SHRF_CSC_MASK) { 720 case SMB_SHRF_CSC_DISABLED: 721 tcon->optional_support |= SMB_CSC_CACHE_NONE; 722 break; 723 case SMB_SHRF_CSC_AUTO: 724 tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT; 725 break; 726 case SMB_SHRF_CSC_VDO: 727 tcon->optional_support |= SMB_CSC_CACHE_VDO; 728 break; 729 case SMB_SHRF_CSC_MANUAL: 730 default: 731 /* 732 * Default to SMB_CSC_CACHE_MANUAL_REINT. 733 */ 734 break; 735 } 736 737 /* ABE support */ 738 if (si->shr_flags & SMB_SHRF_ABE) 739 tcon->optional_support |= 740 SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM; 741 742 if (si->shr_flags & SMB_SHRF_DFSROOT) 743 tcon->optional_support |= SMB_SHARE_IS_IN_DFS; 744 745 /* if 'smb' zfs property: shortnames=disabled */ 746 if (!smb_shortnames) 747 sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME; 748 749 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags); 750 751 if (tree == NULL) 752 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 753 754 if (tree->t_execflags & SMB_EXEC_MAP) { 755 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP); 756 757 rc = smb_kshare_exec(tree->t_server, &execinfo); 758 759 if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) { 760 /* 761 * Inline parts of: smb_tree_disconnect() 762 * Not using smb_tree_disconnect() for cleanup 763 * here because: we don't want an exec up-call, 764 * and there can't be any opens as we never 765 * returned this TID to the client. 766 */ 767 mutex_enter(&tree->t_mutex); 768 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 769 mutex_exit(&tree->t_mutex); 770 771 smb_tree_release(tree); 772 return (NT_STATUS_ACCESS_DENIED); 773 } 774 } 775 776 sr->tid_tree = tree; 777 sr->smb_tid = tree->t_tid; 778 779 return (0); 780 } 781 782 /* 783 * Shares have both a share and host based access control. The access 784 * granted will be minimum permissions based on both hostaccess 785 * (permissions allowed by host based access) and aclaccess (from the 786 * share ACL). 787 */ 788 uint32_t 789 smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon) 790 { 791 char *sharename = tcon->path; 792 const char *any = "?????"; 793 smb_user_t *user = sr->uid_user; 794 smb_node_t *dnode = NULL; 795 smb_node_t *snode = NULL; 796 smb_kshare_t *si = tcon->si; 797 char *service = tcon->service; 798 char last_component[MAXNAMELEN]; 799 smb_tree_t *tree; 800 int rc; 801 uint32_t access; 802 803 ASSERT(user); 804 ASSERT(user->u_cred); 805 806 if (sr->sr_server->sv_cfg.skc_print_enable == 0) { 807 smb_tree_log(sr, sharename, "printing disabled"); 808 return (NT_STATUS_BAD_NETWORK_NAME); 809 } 810 811 if (service != NULL && 812 strcmp(service, any) != 0 && 813 strcasecmp(service, "LPT1:") != 0) { 814 smb_tree_log(sr, sharename, "invalid service (%s)", service); 815 return (NT_STATUS_BAD_DEVICE_TYPE); 816 } 817 818 /* 819 * Check that the shared directory exists. 820 */ 821 rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode, 822 last_component); 823 if (rc == 0) { 824 rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS, 825 sr->sr_server->si_root_smb_node, dnode, last_component, 826 &snode); 827 828 smb_node_release(dnode); 829 } 830 831 if (rc) { 832 if (snode) 833 smb_node_release(snode); 834 835 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); 836 return (NT_STATUS_BAD_NETWORK_NAME); 837 } 838 839 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) { 840 smb_node_release(snode); 841 return (NT_STATUS_ACCESS_DENIED); 842 } 843 844 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; 845 846 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags); 847 848 smb_node_release(snode); 849 850 if (tree == NULL) 851 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 852 853 sr->tid_tree = tree; 854 sr->smb_tid = tree->t_tid; 855 856 return (0); 857 } 858 859 /* 860 * Connect an IPC share for use with named pipes. 861 */ 862 uint32_t 863 smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon) 864 { 865 char *name = tcon->path; 866 const char *any = "?????"; 867 smb_user_t *user = sr->uid_user; 868 smb_tree_t *tree; 869 smb_kshare_t *si = tcon->si; 870 char *service = tcon->service; 871 872 ASSERT(user); 873 874 if (service != NULL && 875 strcmp(service, any) != 0 && 876 strcasecmp(service, "IPC") != 0) { 877 smb_tree_log(sr, name, "invalid service (%s)", service); 878 return (NT_STATUS_BAD_DEVICE_TYPE); 879 } 880 881 if ((user->u_flags & SMB_USER_FLAG_ANON) && 882 sr->sr_cfg->skc_restrict_anon) { 883 smb_tree_log(sr, name, "access denied: restrict anonymous"); 884 return (NT_STATUS_ACCESS_DENIED); 885 } 886 887 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; 888 889 tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0); 890 if (tree == NULL) 891 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 892 893 sr->tid_tree = tree; 894 sr->smb_tid = tree->t_tid; 895 896 return (0); 897 } 898 899 /* 900 * Allocate a tree. 901 */ 902 smb_tree_t * 903 smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si, 904 smb_node_t *snode, uint32_t access, uint32_t execflags) 905 { 906 smb_session_t *session = sr->session; 907 smb_tree_t *tree; 908 uint32_t stype = si->shr_type; 909 uint16_t tid; 910 911 if (smb_idpool_alloc(&session->s_tid_pool, &tid)) 912 return (NULL); 913 914 tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP); 915 bzero(tree, sizeof (smb_tree_t)); 916 917 tree->t_session = session; 918 tree->t_server = session->s_server; 919 920 /* grab a ref for tree->t_owner */ 921 smb_user_hold_internal(sr->uid_user); 922 tree->t_owner = sr->uid_user; 923 924 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) { 925 if (smb_tree_getattr(si, snode, tree) != 0) { 926 smb_idpool_free(&session->s_tid_pool, tid); 927 kmem_cache_free(smb_cache_tree, tree); 928 return (NULL); 929 } 930 } 931 932 if (smb_idpool_constructor(&tree->t_fid_pool)) { 933 smb_idpool_free(&session->s_tid_pool, tid); 934 kmem_cache_free(smb_cache_tree, tree); 935 return (NULL); 936 } 937 938 if (smb_idpool_constructor(&tree->t_odid_pool)) { 939 smb_idpool_destructor(&tree->t_fid_pool); 940 smb_idpool_free(&session->s_tid_pool, tid); 941 kmem_cache_free(smb_cache_tree, tree); 942 return (NULL); 943 } 944 945 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), 946 offsetof(smb_ofile_t, f_tree_lnd)); 947 948 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), 949 offsetof(smb_odir_t, d_lnd)); 950 951 (void) strlcpy(tree->t_sharename, si->shr_name, 952 sizeof (tree->t_sharename)); 953 (void) strlcpy(tree->t_resource, si->shr_path, 954 sizeof (tree->t_resource)); 955 956 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); 957 958 tree->t_refcnt = 1; 959 tree->t_tid = tid; 960 tree->t_res_type = stype; 961 tree->t_state = SMB_TREE_STATE_CONNECTED; 962 tree->t_magic = SMB_TREE_MAGIC; 963 tree->t_access = access; 964 tree->t_connect_time = gethrestime_sec(); 965 tree->t_execflags = execflags; 966 967 /* if FS is readonly, enforce that here */ 968 if (tree->t_flags & SMB_TREE_READONLY) 969 tree->t_access &= ~ACE_ALL_WRITE_PERMS; 970 971 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) { 972 smb_node_ref(snode); 973 tree->t_snode = snode; 974 tree->t_acltype = smb_fsop_acltype(snode); 975 } 976 977 smb_llist_enter(&session->s_tree_list, RW_WRITER); 978 smb_llist_insert_head(&session->s_tree_list, tree); 979 smb_llist_exit(&session->s_tree_list); 980 atomic_inc_32(&session->s_tree_cnt); 981 smb_server_inc_trees(session->s_server); 982 return (tree); 983 } 984 985 /* 986 * Deallocate a tree. The open file and open directory lists should be 987 * empty. 988 * 989 * Remove the tree from the user's tree list before freeing resources 990 * associated with the tree. 991 */ 992 static void 993 smb_tree_dealloc(void *arg) 994 { 995 smb_session_t *session; 996 smb_tree_t *tree = (smb_tree_t *)arg; 997 998 SMB_TREE_VALID(tree); 999 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 1000 ASSERT(tree->t_refcnt == 0); 1001 1002 smb_server_dec_trees(tree->t_server); 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 #ifdef _FAKE_KERNEL 1178 /* See libfksmbsrv:fake_vfs.c */ 1179 { "fake", 3, SMB_TREE_SPARSE}, 1180 #endif /* _FAKE_KERNEL */ 1181 { "zfs", 3, SMB_TREE_QUOTA | SMB_TREE_SPARSE}, 1182 { "ufs", 3, 0 }, 1183 { "nfs", 3, SMB_TREE_NFS_MOUNTED }, 1184 { "tmpfs", 5, SMB_TREE_NO_EXPORT } 1185 }; 1186 smb_mtype_t *mtype; 1187 char *name; 1188 uint32_t flags = 1189 SMB_TREE_SUPPORTS_ACLS | 1190 SMB_TREE_UNICODE_ON_DISK; 1191 int i; 1192 1193 if (si->shr_flags & SMB_SHRF_DFSROOT) 1194 flags |= SMB_TREE_DFSROOT; 1195 1196 if (si->shr_flags & SMB_SHRF_CATIA) 1197 flags |= SMB_TREE_CATIA; 1198 1199 if (si->shr_flags & SMB_SHRF_ABE) 1200 flags |= SMB_TREE_ABE; 1201 1202 if (si->shr_flags & SMB_SHRF_CA) 1203 flags |= SMB_TREE_CA; 1204 1205 if (si->shr_flags & SMB_SHRF_FSO) 1206 flags |= SMB_TREE_FORCE_L2_OPLOCK; 1207 1208 if (ssn->s_cfg.skc_oplock_enable) { 1209 /* if 'smb' zfs property: oplocks=enabled */ 1210 flags |= SMB_TREE_OPLOCKS; 1211 } 1212 1213 /* Global config option for now. Later make per-share. */ 1214 if (ssn->s_cfg.skc_traverse_mounts) 1215 flags |= SMB_TREE_TRAVERSE_MOUNTS; 1216 1217 /* if 'smb' zfs property: shortnames=enabled */ 1218 if (smb_shortnames) 1219 flags |= SMB_TREE_SHORTNAMES; 1220 1221 if (vfsp->vfs_flag & VFS_RDONLY) 1222 flags |= SMB_TREE_READONLY; 1223 1224 if (vfsp->vfs_flag & VFS_XATTR) 1225 flags |= SMB_TREE_STREAMS; 1226 1227 vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp)); 1228 if (vswp != NULL) { 1229 name = vswp->vsw_name; 1230 vfs_unrefvfssw(vswp); 1231 } else { 1232 name = "?"; 1233 } 1234 1235 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) { 1236 mtype = &smb_mtype[i]; 1237 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0) 1238 flags |= mtype->mt_flags; 1239 } 1240 1241 /* 1242 * SMB_TREE_QUOTA will be on here if the FS is ZFS. We want to 1243 * turn it OFF when the share property says false. 1244 */ 1245 if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0) 1246 flags &= ~SMB_TREE_QUOTA; 1247 1248 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 1249 (void) smb_strupr((char *)tree->t_typename); 1250 1251 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 1252 flags |= SMB_TREE_XVATTR; 1253 1254 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 1255 flags |= SMB_TREE_CASEINSENSITIVE; 1256 1257 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 1258 flags |= SMB_TREE_NO_CASESENSITIVE; 1259 1260 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 1261 flags |= SMB_TREE_DIRENTFLAGS; 1262 1263 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 1264 flags |= SMB_TREE_ACLONCREATE; 1265 1266 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 1267 flags |= SMB_TREE_ACEMASKONACCESS; 1268 1269 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name); 1270 1271 1272 tree->t_flags = flags; 1273 } 1274 1275 /* 1276 * Report share access result to syslog. 1277 */ 1278 static void 1279 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 1280 { 1281 va_list ap; 1282 char buf[128]; 1283 smb_user_t *user = sr->uid_user; 1284 1285 ASSERT(user); 1286 1287 if (smb_tcon_mute) 1288 return; 1289 1290 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 1291 /* 1292 * Only report normal users, i.e. ignore W2K misuse 1293 * of the IPC connection by filtering out internal 1294 * names such as nobody and root. 1295 */ 1296 if ((strcmp(user->u_name, "root") == 0) || 1297 (strcmp(user->u_name, "nobody") == 0)) { 1298 return; 1299 } 1300 } 1301 1302 va_start(ap, fmt); 1303 (void) vsnprintf(buf, 128, fmt, ap); 1304 va_end(ap); 1305 1306 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 1307 user->u_domain, user->u_name, sharename, buf); 1308 } 1309 1310 /* 1311 * smb_tree_lookup_odir 1312 * 1313 * Find the specified odir in the tree's list of odirs, and 1314 * attempt to obtain a hold on the odir. 1315 * 1316 * Returns NULL if odir not found or a hold cannot be obtained. 1317 */ 1318 smb_odir_t * 1319 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid) 1320 { 1321 smb_odir_t *od; 1322 smb_llist_t *od_list; 1323 smb_tree_t *tree = sr->tid_tree; 1324 1325 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1326 1327 od_list = &tree->t_odir_list; 1328 1329 smb_llist_enter(od_list, RW_READER); 1330 od = smb_llist_head(od_list); 1331 while (od) { 1332 if (od->d_odid == odid) 1333 break; 1334 od = smb_llist_next(od_list, od); 1335 } 1336 if (od == NULL) 1337 goto out; 1338 1339 /* 1340 * Only allow use of a given Search ID with the same UID that 1341 * was used to create it. MS-CIFS 3.3.5.14 1342 */ 1343 if (od->d_user != sr->uid_user) { 1344 od = NULL; 1345 goto out; 1346 } 1347 if (!smb_odir_hold(od)) 1348 od = NULL; 1349 1350 out: 1351 smb_llist_exit(od_list); 1352 return (od); 1353 } 1354 1355 boolean_t 1356 smb_tree_is_connected(smb_tree_t *tree) 1357 { 1358 boolean_t rb; 1359 1360 mutex_enter(&tree->t_mutex); 1361 rb = smb_tree_is_connected_locked(tree); 1362 mutex_exit(&tree->t_mutex); 1363 return (rb); 1364 } 1365 1366 /* 1367 * smb_tree_close_odirs 1368 * 1369 * Close all open odirs in the tree's list which were opened by 1370 * the process identified by pid. 1371 * If pid is zero, close all open odirs in the tree's list. 1372 */ 1373 static void 1374 smb_tree_close_odirs(smb_tree_t *tree, uint32_t pid) 1375 { 1376 smb_llist_t *od_list; 1377 smb_odir_t *od; 1378 1379 ASSERT(tree); 1380 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1381 1382 od_list = &tree->t_odir_list; 1383 smb_llist_enter(od_list, RW_READER); 1384 1385 for (od = smb_llist_head(od_list); 1386 od != NULL; 1387 od = smb_llist_next(od_list, od)) { 1388 1389 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1390 ASSERT(od->d_tree == tree); 1391 1392 if (pid != 0 && od->d_opened_by_pid != pid) 1393 continue; 1394 1395 if (smb_odir_hold(od)) { 1396 smb_odir_close(od); 1397 smb_odir_release(od); 1398 } 1399 } 1400 1401 smb_llist_exit(od_list); 1402 } 1403 1404 static void 1405 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, 1406 int exec_type) 1407 { 1408 exec->e_sharename = tree->t_sharename; 1409 exec->e_winname = tree->t_owner->u_name; 1410 exec->e_userdom = tree->t_owner->u_domain; 1411 exec->e_srv_ipaddr = tree->t_session->local_ipaddr; 1412 exec->e_cli_ipaddr = tree->t_session->ipaddr; 1413 exec->e_cli_netbiosname = tree->t_session->workstation; 1414 exec->e_uid = crgetuid(tree->t_owner->u_cred); 1415 exec->e_type = exec_type; 1416 } 1417 1418 /* 1419 * Private function to support smb_tree_enum. 1420 */ 1421 static int 1422 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum) 1423 { 1424 uint8_t *pb; 1425 uint_t nbytes; 1426 int rc; 1427 1428 if (svcenum->se_nskip > 0) { 1429 svcenum->se_nskip--; 1430 return (0); 1431 } 1432 1433 if (svcenum->se_nitems >= svcenum->se_nlimit) { 1434 svcenum->se_nitems = svcenum->se_nlimit; 1435 return (0); 1436 } 1437 1438 pb = &svcenum->se_buf[svcenum->se_bused]; 1439 rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes); 1440 if (rc == 0) { 1441 svcenum->se_bavail -= nbytes; 1442 svcenum->se_bused += nbytes; 1443 svcenum->se_nitems++; 1444 } 1445 1446 return (rc); 1447 } 1448 1449 /* 1450 * Encode connection information into a buffer: connection information 1451 * needed in user space to support RPC requests. 1452 */ 1453 static int 1454 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen, 1455 uint32_t *nbytes) 1456 { 1457 smb_netconnectinfo_t info; 1458 int rc; 1459 1460 smb_tree_netinfo_init(tree, &info); 1461 rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes); 1462 smb_tree_netinfo_fini(&info); 1463 1464 return (rc); 1465 } 1466 1467 static void 1468 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen) 1469 { 1470 smb_user_t *user = tree->t_owner; 1471 1472 /* 1473 * u_domain_len and u_name_len include the '\0' in their 1474 * lengths, hence the sum of the two lengths gives us room 1475 * for both the '\\' and '\0' chars. 1476 */ 1477 ASSERT(namestr); 1478 ASSERT(namelen); 1479 ASSERT(user->u_domain_len > 0); 1480 ASSERT(user->u_name_len > 0); 1481 *namelen = user->u_domain_len + user->u_name_len; 1482 *namestr = kmem_alloc(*namelen, KM_SLEEP); 1483 (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain, 1484 user->u_name); 1485 } 1486 1487 /* 1488 * Note: ci_numusers should be the number of users connected to 1489 * the share rather than the number of references on the tree but 1490 * we don't have a mechanism to track users/share in smbsrv yet. 1491 */ 1492 static void 1493 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info) 1494 { 1495 ASSERT(tree); 1496 1497 info->ci_id = tree->t_tid; 1498 info->ci_type = tree->t_res_type; 1499 info->ci_numopens = tree->t_open_files; 1500 info->ci_numusers = tree->t_refcnt; 1501 info->ci_time = gethrestime_sec() - tree->t_connect_time; 1502 1503 info->ci_sharelen = strlen(tree->t_sharename) + 1; 1504 info->ci_share = smb_mem_strdup(tree->t_sharename); 1505 1506 smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen); 1507 } 1508 1509 static void 1510 smb_tree_netinfo_fini(smb_netconnectinfo_t *info) 1511 { 1512 if (info == NULL) 1513 return; 1514 1515 if (info->ci_username) 1516 kmem_free(info->ci_username, info->ci_namelen); 1517 if (info->ci_share) 1518 smb_mem_free(info->ci_share); 1519 1520 bzero(info, sizeof (smb_netconnectinfo_t)); 1521 } 1522