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