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