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 #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_FSO) 1203 flags |= SMB_TREE_FORCE_L2_OPLOCK; 1204 1205 if (ssn->s_cfg.skc_oplock_enable) { 1206 /* if 'smb' zfs property: oplocks=enabled */ 1207 flags |= SMB_TREE_OPLOCKS; 1208 } 1209 1210 /* Global config option for now. Later make per-share. */ 1211 if (ssn->s_cfg.skc_traverse_mounts) 1212 flags |= SMB_TREE_TRAVERSE_MOUNTS; 1213 1214 /* if 'smb' zfs property: shortnames=enabled */ 1215 if (smb_shortnames) 1216 flags |= SMB_TREE_SHORTNAMES; 1217 1218 if (vfsp->vfs_flag & VFS_RDONLY) 1219 flags |= SMB_TREE_READONLY; 1220 1221 if (vfsp->vfs_flag & VFS_XATTR) 1222 flags |= SMB_TREE_STREAMS; 1223 1224 vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp)); 1225 if (vswp != NULL) { 1226 name = vswp->vsw_name; 1227 vfs_unrefvfssw(vswp); 1228 } else { 1229 name = "?"; 1230 } 1231 1232 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) { 1233 mtype = &smb_mtype[i]; 1234 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0) 1235 flags |= mtype->mt_flags; 1236 } 1237 1238 /* 1239 * SMB_TREE_QUOTA will be on here if the FS is ZFS. We want to 1240 * turn it OFF when the share property says false. 1241 */ 1242 if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0) 1243 flags &= ~SMB_TREE_QUOTA; 1244 1245 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 1246 (void) smb_strupr((char *)tree->t_typename); 1247 1248 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 1249 flags |= SMB_TREE_XVATTR; 1250 1251 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 1252 flags |= SMB_TREE_CASEINSENSITIVE; 1253 1254 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 1255 flags |= SMB_TREE_NO_CASESENSITIVE; 1256 1257 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 1258 flags |= SMB_TREE_DIRENTFLAGS; 1259 1260 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 1261 flags |= SMB_TREE_ACLONCREATE; 1262 1263 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 1264 flags |= SMB_TREE_ACEMASKONACCESS; 1265 1266 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name); 1267 1268 1269 tree->t_flags = flags; 1270 } 1271 1272 /* 1273 * Report share access result to syslog. 1274 */ 1275 static void 1276 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 1277 { 1278 va_list ap; 1279 char buf[128]; 1280 smb_user_t *user = sr->uid_user; 1281 1282 ASSERT(user); 1283 1284 if (smb_tcon_mute) 1285 return; 1286 1287 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 1288 /* 1289 * Only report normal users, i.e. ignore W2K misuse 1290 * of the IPC connection by filtering out internal 1291 * names such as nobody and root. 1292 */ 1293 if ((strcmp(user->u_name, "root") == 0) || 1294 (strcmp(user->u_name, "nobody") == 0)) { 1295 return; 1296 } 1297 } 1298 1299 va_start(ap, fmt); 1300 (void) vsnprintf(buf, 128, fmt, ap); 1301 va_end(ap); 1302 1303 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 1304 user->u_domain, user->u_name, sharename, buf); 1305 } 1306 1307 /* 1308 * smb_tree_lookup_odir 1309 * 1310 * Find the specified odir in the tree's list of odirs, and 1311 * attempt to obtain a hold on the odir. 1312 * 1313 * Returns NULL if odir not found or a hold cannot be obtained. 1314 */ 1315 smb_odir_t * 1316 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid) 1317 { 1318 smb_odir_t *od; 1319 smb_llist_t *od_list; 1320 smb_tree_t *tree = sr->tid_tree; 1321 1322 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1323 1324 od_list = &tree->t_odir_list; 1325 1326 smb_llist_enter(od_list, RW_READER); 1327 od = smb_llist_head(od_list); 1328 while (od) { 1329 if (od->d_odid == odid) 1330 break; 1331 od = smb_llist_next(od_list, od); 1332 } 1333 if (od == NULL) 1334 goto out; 1335 1336 /* 1337 * Only allow use of a given Search ID with the same UID that 1338 * was used to create it. MS-CIFS 3.3.5.14 1339 */ 1340 if (od->d_user != sr->uid_user) { 1341 od = NULL; 1342 goto out; 1343 } 1344 if (!smb_odir_hold(od)) 1345 od = NULL; 1346 1347 out: 1348 smb_llist_exit(od_list); 1349 return (od); 1350 } 1351 1352 boolean_t 1353 smb_tree_is_connected(smb_tree_t *tree) 1354 { 1355 boolean_t rb; 1356 1357 mutex_enter(&tree->t_mutex); 1358 rb = smb_tree_is_connected_locked(tree); 1359 mutex_exit(&tree->t_mutex); 1360 return (rb); 1361 } 1362 1363 /* 1364 * Get the next open ofile in the list. A reference is taken on 1365 * the ofile, which can be released later with smb_ofile_release(). 1366 * 1367 * If the specified ofile is NULL, search from the beginning of the 1368 * list. Otherwise, the search starts just after that ofile. 1369 * 1370 * Returns NULL if there are no open files in the list. 1371 */ 1372 static smb_ofile_t * 1373 smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of) 1374 { 1375 smb_llist_t *ofile_list; 1376 1377 ASSERT(tree); 1378 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1379 1380 ofile_list = &tree->t_ofile_list; 1381 smb_llist_enter(ofile_list, RW_READER); 1382 1383 if (of) { 1384 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1385 of = smb_llist_next(ofile_list, of); 1386 } else { 1387 of = smb_llist_head(ofile_list); 1388 } 1389 1390 while (of) { 1391 if (smb_ofile_hold(of)) 1392 break; 1393 1394 of = smb_llist_next(ofile_list, of); 1395 } 1396 1397 smb_llist_exit(ofile_list); 1398 return (of); 1399 } 1400 1401 /* 1402 * smb_tree_get_odir 1403 * 1404 * Find the next odir in the tree's list of odirs, and obtain a 1405 * hold on it. 1406 * If the specified odir is NULL the search starts at the beginning 1407 * of the tree's odir list, otherwise the search starts after the 1408 * specified odir. 1409 */ 1410 static smb_odir_t * 1411 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od) 1412 { 1413 smb_llist_t *od_list; 1414 1415 ASSERT(tree); 1416 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1417 1418 od_list = &tree->t_odir_list; 1419 smb_llist_enter(od_list, RW_READER); 1420 1421 if (od) { 1422 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1423 od = smb_llist_next(od_list, od); 1424 } else { 1425 od = smb_llist_head(od_list); 1426 } 1427 1428 while (od) { 1429 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1430 1431 if (smb_odir_hold(od)) 1432 break; 1433 od = smb_llist_next(od_list, od); 1434 } 1435 1436 smb_llist_exit(od_list); 1437 return (od); 1438 } 1439 1440 /* 1441 * smb_tree_close_odirs 1442 * 1443 * Close all open odirs in the tree's list which were opened by 1444 * the process identified by pid. 1445 * If pid is zero, close all open odirs in the tree's list. 1446 */ 1447 static void 1448 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) 1449 { 1450 smb_odir_t *od, *next_od; 1451 1452 ASSERT(tree); 1453 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1454 1455 od = smb_tree_get_odir(tree, NULL); 1456 while (od) { 1457 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1458 ASSERT(od->d_tree == tree); 1459 1460 next_od = smb_tree_get_odir(tree, od); 1461 if ((pid == 0) || (od->d_opened_by_pid == pid)) 1462 smb_odir_close(od); 1463 smb_odir_release(od); 1464 1465 od = next_od; 1466 } 1467 } 1468 1469 static void 1470 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, 1471 int exec_type) 1472 { 1473 exec->e_sharename = tree->t_sharename; 1474 exec->e_winname = tree->t_owner->u_name; 1475 exec->e_userdom = tree->t_owner->u_domain; 1476 exec->e_srv_ipaddr = tree->t_session->local_ipaddr; 1477 exec->e_cli_ipaddr = tree->t_session->ipaddr; 1478 exec->e_cli_netbiosname = tree->t_session->workstation; 1479 exec->e_uid = crgetuid(tree->t_owner->u_cred); 1480 exec->e_type = exec_type; 1481 } 1482 1483 /* 1484 * Private function to support smb_tree_enum. 1485 */ 1486 static int 1487 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum) 1488 { 1489 uint8_t *pb; 1490 uint_t nbytes; 1491 int rc; 1492 1493 if (svcenum->se_nskip > 0) { 1494 svcenum->se_nskip--; 1495 return (0); 1496 } 1497 1498 if (svcenum->se_nitems >= svcenum->se_nlimit) { 1499 svcenum->se_nitems = svcenum->se_nlimit; 1500 return (0); 1501 } 1502 1503 pb = &svcenum->se_buf[svcenum->se_bused]; 1504 rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes); 1505 if (rc == 0) { 1506 svcenum->se_bavail -= nbytes; 1507 svcenum->se_bused += nbytes; 1508 svcenum->se_nitems++; 1509 } 1510 1511 return (rc); 1512 } 1513 1514 /* 1515 * Encode connection information into a buffer: connection information 1516 * needed in user space to support RPC requests. 1517 */ 1518 static int 1519 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen, 1520 uint32_t *nbytes) 1521 { 1522 smb_netconnectinfo_t info; 1523 int rc; 1524 1525 smb_tree_netinfo_init(tree, &info); 1526 rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes); 1527 smb_tree_netinfo_fini(&info); 1528 1529 return (rc); 1530 } 1531 1532 static void 1533 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen) 1534 { 1535 smb_user_t *user = tree->t_owner; 1536 1537 /* 1538 * u_domain_len and u_name_len include the '\0' in their 1539 * lengths, hence the sum of the two lengths gives us room 1540 * for both the '\\' and '\0' chars. 1541 */ 1542 ASSERT(namestr); 1543 ASSERT(namelen); 1544 ASSERT(user->u_domain_len > 0); 1545 ASSERT(user->u_name_len > 0); 1546 *namelen = user->u_domain_len + user->u_name_len; 1547 *namestr = kmem_alloc(*namelen, KM_SLEEP); 1548 (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain, 1549 user->u_name); 1550 } 1551 1552 /* 1553 * Note: ci_numusers should be the number of users connected to 1554 * the share rather than the number of references on the tree but 1555 * we don't have a mechanism to track users/share in smbsrv yet. 1556 */ 1557 static void 1558 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info) 1559 { 1560 ASSERT(tree); 1561 1562 info->ci_id = tree->t_tid; 1563 info->ci_type = tree->t_res_type; 1564 info->ci_numopens = tree->t_open_files; 1565 info->ci_numusers = tree->t_refcnt; 1566 info->ci_time = gethrestime_sec() - tree->t_connect_time; 1567 1568 info->ci_sharelen = strlen(tree->t_sharename) + 1; 1569 info->ci_share = smb_mem_strdup(tree->t_sharename); 1570 1571 smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen); 1572 } 1573 1574 static void 1575 smb_tree_netinfo_fini(smb_netconnectinfo_t *info) 1576 { 1577 if (info == NULL) 1578 return; 1579 1580 if (info->ci_username) 1581 kmem_free(info->ci_username, info->ci_namelen); 1582 if (info->ci_share) 1583 smb_mem_free(info->ci_share); 1584 1585 bzero(info, sizeof (smb_netconnectinfo_t)); 1586 } 1587