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