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