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