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 2012 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, sv); 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 if ((si = smb_kshare_lookup(name)) == NULL) { 241 smb_tree_log(sr, name, "share not found"); 242 smbsr_error(sr, 0, ERRSRV, ERRinvnetname); 243 return (NULL); 244 } 245 246 if (!strcasecmp(SMB_SHARE_PRINT, name)) { 247 smb_kshare_release(si); 248 smb_tree_log(sr, name, "access not permitted"); 249 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 250 return (NULL); 251 } 252 253 sr->sr_tcon.si = si; 254 255 switch (si->shr_type & STYPE_MASK) { 256 case STYPE_DISKTREE: 257 tree = smb_tree_connect_disk(sr, name); 258 break; 259 case STYPE_IPC: 260 tree = smb_tree_connect_ipc(sr, name); 261 break; 262 case STYPE_PRINTQ: 263 tree = smb_tree_connect_printq(sr, name); 264 break; 265 default: 266 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, 267 ERRDOS, ERROR_BAD_DEV_TYPE); 268 break; 269 } 270 271 smb_kshare_release(si); 272 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(&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) sprintf(sharepath, "%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 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->ipaddr); 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(&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(session->s_server->si_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(session->s_server->si_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(session->s_server->si_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(session->s_server->si_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(tree->t_server->si_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 = vfs_mntpoint->rs_string; 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 1119 typedef struct smb_mtype { 1120 char *mt_name; 1121 size_t mt_namelen; 1122 uint32_t mt_flags; 1123 } smb_mtype_t; 1124 1125 static smb_mtype_t smb_mtype[] = { 1126 { "zfs", 3, SMB_TREE_UNICODE_ON_DISK | 1127 SMB_TREE_QUOTA | SMB_TREE_SPARSE}, 1128 { "ufs", 3, SMB_TREE_UNICODE_ON_DISK }, 1129 { "nfs", 3, SMB_TREE_NFS_MOUNTED }, 1130 { "tmpfs", 5, SMB_TREE_NO_EXPORT } 1131 }; 1132 smb_mtype_t *mtype; 1133 char *name; 1134 uint32_t flags = SMB_TREE_SUPPORTS_ACLS; 1135 int i; 1136 1137 if (si->shr_flags & SMB_SHRF_DFSROOT) 1138 flags |= SMB_TREE_DFSROOT; 1139 1140 if (si->shr_flags & SMB_SHRF_CATIA) 1141 flags |= SMB_TREE_CATIA; 1142 1143 if (si->shr_flags & SMB_SHRF_ABE) 1144 flags |= SMB_TREE_ABE; 1145 1146 if (ssn->s_cfg.skc_oplock_enable) { 1147 /* if 'smb' zfs property: oplocks=enabled */ 1148 flags |= SMB_TREE_OPLOCKS; 1149 } 1150 1151 /* Global config option for now. Later make per-share. */ 1152 if (ssn->s_cfg.skc_traverse_mounts) 1153 flags |= SMB_TREE_TRAVERSE_MOUNTS; 1154 1155 /* if 'smb' zfs property: shortnames=enabled */ 1156 if (smb_shortnames) 1157 flags |= SMB_TREE_SHORTNAMES; 1158 1159 if (vfsp->vfs_flag & VFS_RDONLY) 1160 flags |= SMB_TREE_READONLY; 1161 1162 if (vfsp->vfs_flag & VFS_XATTR) 1163 flags |= SMB_TREE_STREAMS; 1164 1165 name = vfssw[vfsp->vfs_fstype].vsw_name; 1166 1167 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) { 1168 mtype = &smb_mtype[i]; 1169 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0) 1170 flags |= mtype->mt_flags; 1171 } 1172 1173 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); 1174 (void) smb_strupr((char *)tree->t_typename); 1175 1176 if (vfs_has_feature(vfsp, VFSFT_XVATTR)) 1177 flags |= SMB_TREE_XVATTR; 1178 1179 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE)) 1180 flags |= SMB_TREE_CASEINSENSITIVE; 1181 1182 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE)) 1183 flags |= SMB_TREE_NO_CASESENSITIVE; 1184 1185 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS)) 1186 flags |= SMB_TREE_DIRENTFLAGS; 1187 1188 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE)) 1189 flags |= SMB_TREE_ACLONCREATE; 1190 1191 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS)) 1192 flags |= SMB_TREE_ACEMASKONACCESS; 1193 1194 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name); 1195 1196 1197 tree->t_flags = flags; 1198 } 1199 1200 /* 1201 * Report share access result to syslog. 1202 */ 1203 static void 1204 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) 1205 { 1206 va_list ap; 1207 char buf[128]; 1208 smb_user_t *user = sr->uid_user; 1209 1210 ASSERT(user); 1211 1212 if (smb_tcon_mute) 1213 return; 1214 1215 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) { 1216 /* 1217 * Only report normal users, i.e. ignore W2K misuse 1218 * of the IPC connection by filtering out internal 1219 * names such as nobody and root. 1220 */ 1221 if ((strcmp(user->u_name, "root") == 0) || 1222 (strcmp(user->u_name, "nobody") == 0)) { 1223 return; 1224 } 1225 } 1226 1227 va_start(ap, fmt); 1228 (void) vsnprintf(buf, 128, fmt, ap); 1229 va_end(ap); 1230 1231 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", 1232 user->u_domain, user->u_name, sharename, buf); 1233 } 1234 1235 /* 1236 * smb_tree_lookup_odir 1237 * 1238 * Find the specified odir in the tree's list of odirs, and 1239 * attempt to obtain a hold on the odir. 1240 * 1241 * Returns NULL if odir not found or a hold cannot be obtained. 1242 */ 1243 smb_odir_t * 1244 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid) 1245 { 1246 smb_odir_t *od; 1247 smb_llist_t *od_list; 1248 smb_tree_t *tree = sr->tid_tree; 1249 1250 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1251 1252 od_list = &tree->t_odir_list; 1253 1254 smb_llist_enter(od_list, RW_READER); 1255 od = smb_llist_head(od_list); 1256 while (od) { 1257 if (od->d_odid == odid) 1258 break; 1259 od = smb_llist_next(od_list, od); 1260 } 1261 if (od == NULL) 1262 goto out; 1263 1264 /* 1265 * Only allow use of a given Search ID with the same UID that 1266 * was used to create it. MS-CIFS 3.3.5.14 1267 */ 1268 if (od->d_user != sr->uid_user) { 1269 od = NULL; 1270 goto out; 1271 } 1272 if (!smb_odir_hold(od)) 1273 od = NULL; 1274 1275 out: 1276 smb_llist_exit(od_list); 1277 return (od); 1278 } 1279 1280 boolean_t 1281 smb_tree_is_connected(smb_tree_t *tree) 1282 { 1283 boolean_t rb; 1284 1285 mutex_enter(&tree->t_mutex); 1286 rb = smb_tree_is_connected_locked(tree); 1287 mutex_exit(&tree->t_mutex); 1288 return (rb); 1289 } 1290 1291 /* 1292 * Get the next open ofile in the list. A reference is taken on 1293 * the ofile, which can be released later with smb_ofile_release(). 1294 * 1295 * If the specified ofile is NULL, search from the beginning of the 1296 * list. Otherwise, the search starts just after that ofile. 1297 * 1298 * Returns NULL if there are no open files in the list. 1299 */ 1300 static smb_ofile_t * 1301 smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of) 1302 { 1303 smb_llist_t *ofile_list; 1304 1305 ASSERT(tree); 1306 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1307 1308 ofile_list = &tree->t_ofile_list; 1309 smb_llist_enter(ofile_list, RW_READER); 1310 1311 if (of) { 1312 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1313 of = smb_llist_next(ofile_list, of); 1314 } else { 1315 of = smb_llist_head(ofile_list); 1316 } 1317 1318 while (of) { 1319 if (smb_ofile_hold(of)) 1320 break; 1321 1322 of = smb_llist_next(ofile_list, of); 1323 } 1324 1325 smb_llist_exit(ofile_list); 1326 return (of); 1327 } 1328 1329 /* 1330 * smb_tree_get_odir 1331 * 1332 * Find the next odir in the tree's list of odirs, and obtain a 1333 * hold on it. 1334 * If the specified odir is NULL the search starts at the beginning 1335 * of the tree's odir list, otherwise the search starts after the 1336 * specified odir. 1337 */ 1338 static smb_odir_t * 1339 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od) 1340 { 1341 smb_llist_t *od_list; 1342 1343 ASSERT(tree); 1344 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1345 1346 od_list = &tree->t_odir_list; 1347 smb_llist_enter(od_list, RW_READER); 1348 1349 if (od) { 1350 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1351 od = smb_llist_next(od_list, od); 1352 } else { 1353 od = smb_llist_head(od_list); 1354 } 1355 1356 while (od) { 1357 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1358 1359 if (smb_odir_hold(od)) 1360 break; 1361 od = smb_llist_next(od_list, od); 1362 } 1363 1364 smb_llist_exit(od_list); 1365 return (od); 1366 } 1367 1368 /* 1369 * smb_tree_close_odirs 1370 * 1371 * Close all open odirs in the tree's list which were opened by 1372 * the process identified by pid. 1373 * If pid is zero, close all open odirs in the tree's list. 1374 */ 1375 static void 1376 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) 1377 { 1378 smb_odir_t *od, *next_od; 1379 1380 ASSERT(tree); 1381 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 1382 1383 od = smb_tree_get_odir(tree, NULL); 1384 while (od) { 1385 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1386 ASSERT(od->d_tree == tree); 1387 1388 next_od = smb_tree_get_odir(tree, od); 1389 if ((pid == 0) || (od->d_opened_by_pid == pid)) 1390 smb_odir_close(od); 1391 smb_odir_release(od); 1392 1393 od = next_od; 1394 } 1395 } 1396 1397 static void 1398 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, 1399 int exec_type) 1400 { 1401 exec->e_sharename = tree->t_sharename; 1402 exec->e_winname = tree->t_owner->u_name; 1403 exec->e_userdom = tree->t_owner->u_domain; 1404 exec->e_srv_ipaddr = tree->t_session->local_ipaddr; 1405 exec->e_cli_ipaddr = tree->t_session->ipaddr; 1406 exec->e_cli_netbiosname = tree->t_session->workstation; 1407 exec->e_uid = crgetuid(tree->t_owner->u_cred); 1408 exec->e_type = exec_type; 1409 } 1410 1411 /* 1412 * Private function to support smb_tree_enum. 1413 */ 1414 static int 1415 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum) 1416 { 1417 uint8_t *pb; 1418 uint_t nbytes; 1419 int rc; 1420 1421 if (svcenum->se_nskip > 0) { 1422 svcenum->se_nskip--; 1423 return (0); 1424 } 1425 1426 if (svcenum->se_nitems >= svcenum->se_nlimit) { 1427 svcenum->se_nitems = svcenum->se_nlimit; 1428 return (0); 1429 } 1430 1431 pb = &svcenum->se_buf[svcenum->se_bused]; 1432 rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes); 1433 if (rc == 0) { 1434 svcenum->se_bavail -= nbytes; 1435 svcenum->se_bused += nbytes; 1436 svcenum->se_nitems++; 1437 } 1438 1439 return (rc); 1440 } 1441 1442 /* 1443 * Encode connection information into a buffer: connection information 1444 * needed in user space to support RPC requests. 1445 */ 1446 static int 1447 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen, 1448 uint32_t *nbytes) 1449 { 1450 smb_netconnectinfo_t info; 1451 int rc; 1452 1453 smb_tree_netinfo_init(tree, &info); 1454 rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes); 1455 smb_tree_netinfo_fini(&info); 1456 1457 return (rc); 1458 } 1459 1460 static void 1461 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen) 1462 { 1463 smb_user_t *user = tree->t_owner; 1464 1465 /* 1466 * u_domain_len and u_name_len include the '\0' in their 1467 * lengths, hence the sum of the two lengths gives us room 1468 * for both the '\\' and '\0' chars. 1469 */ 1470 ASSERT(namestr); 1471 ASSERT(namelen); 1472 ASSERT(user->u_domain_len > 0); 1473 ASSERT(user->u_name_len > 0); 1474 *namelen = user->u_domain_len + user->u_name_len; 1475 *namestr = kmem_alloc(*namelen, KM_SLEEP); 1476 (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain, 1477 user->u_name); 1478 } 1479 1480 /* 1481 * Note: ci_numusers should be the number of users connected to 1482 * the share rather than the number of references on the tree but 1483 * we don't have a mechanism to track users/share in smbsrv yet. 1484 */ 1485 static void 1486 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info) 1487 { 1488 ASSERT(tree); 1489 1490 info->ci_id = tree->t_tid; 1491 info->ci_type = tree->t_res_type; 1492 info->ci_numopens = tree->t_open_files; 1493 info->ci_numusers = tree->t_refcnt; 1494 info->ci_time = gethrestime_sec() - tree->t_connect_time; 1495 1496 info->ci_sharelen = strlen(tree->t_sharename) + 1; 1497 info->ci_share = smb_mem_strdup(tree->t_sharename); 1498 1499 smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen); 1500 } 1501 1502 static void 1503 smb_tree_netinfo_fini(smb_netconnectinfo_t *info) 1504 { 1505 if (info == NULL) 1506 return; 1507 1508 if (info->ci_username) 1509 kmem_free(info->ci_username, info->ci_namelen); 1510 if (info->ci_share) 1511 smb_mem_free(info->ci_share); 1512 1513 bzero(info, sizeof (smb_netconnectinfo_t)); 1514 } 1515