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