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