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