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         int                     rc;
 658         uint32_t                access;
 659         smb_shr_execinfo_t      execinfo;
 660 
 661         ASSERT(user);
 662         ASSERT(user->u_cred);
 663 
 664         if (service != NULL &&
 665             strcmp(service, any) != 0 &&
 666             strcasecmp(service, "A:") != 0) {
 667                 smb_tree_log(sr, sharename, "invalid service (%s)", service);
 668                 return (NT_STATUS_BAD_DEVICE_TYPE);
 669         }
 670 
 671         /*
 672          * Check that the shared directory exists.
 673          */
 674         rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
 675             last_component);
 676         if (rc == 0) {
 677                 rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
 678                     sr->sr_server->si_root_smb_node, dnode, last_component,
 679                     &snode);
 680 
 681                 smb_node_release(dnode);
 682         }
 683 
 684         if (rc) {
 685                 if (snode)
 686                         smb_node_release(snode);
 687 
 688                 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
 689                 return (NT_STATUS_BAD_NETWORK_NAME);
 690         }
 691 
 692         if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
 693                 smb_node_release(snode);
 694                 return (NT_STATUS_ACCESS_DENIED);
 695         }
 696 
 697         /*
 698          * Set up the OptionalSupport for this share.
 699          */
 700         tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
 701 
 702         switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
 703         case SMB_SHRF_CSC_DISABLED:
 704                 tcon->optional_support |= SMB_CSC_CACHE_NONE;
 705                 break;
 706         case SMB_SHRF_CSC_AUTO:
 707                 tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT;
 708                 break;
 709         case SMB_SHRF_CSC_VDO:
 710                 tcon->optional_support |= SMB_CSC_CACHE_VDO;
 711                 break;
 712         case SMB_SHRF_CSC_MANUAL:
 713         default:
 714                 /*
 715                  * Default to SMB_CSC_CACHE_MANUAL_REINT.
 716                  */
 717                 break;
 718         }
 719 
 720         /* ABE support */
 721         if (si->shr_flags & SMB_SHRF_ABE)
 722                 tcon->optional_support |=
 723                     SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
 724 
 725         if (si->shr_flags & SMB_SHRF_DFSROOT)
 726                 tcon->optional_support |= SMB_SHARE_IS_IN_DFS;
 727 
 728         /* if 'smb' zfs property: shortnames=disabled */
 729         if (!smb_shortnames)
 730                 sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
 731 
 732         tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
 733 
 734         smb_node_release(snode);
 735 
 736         if (tree == NULL)
 737                 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
 738 
 739         if (tree->t_execflags & SMB_EXEC_MAP) {
 740                 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP);
 741 
 742                 rc = smb_kshare_exec(tree->t_server, &execinfo);
 743 
 744                 if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) {
 745                         smb_tree_disconnect(tree, B_FALSE);
 746                         smb_tree_release(tree);
 747                         return (NT_STATUS_ACCESS_DENIED);
 748                 }
 749         }
 750 
 751         sr->tid_tree = tree;
 752         sr->smb_tid  = tree->t_tid;
 753 
 754         return (0);
 755 }
 756 
 757 /*
 758  * Shares have both a share and host based access control.  The access
 759  * granted will be minimum permissions based on both hostaccess
 760  * (permissions allowed by host based access) and aclaccess (from the
 761  * share ACL).
 762  */
 763 uint32_t
 764 smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon)
 765 {
 766         char                    *sharename = tcon->path;
 767         const char              *any = "?????";
 768         smb_user_t              *user = sr->uid_user;
 769         smb_node_t              *dnode = NULL;
 770         smb_node_t              *snode = NULL;
 771         smb_kshare_t            *si = tcon->si;
 772         char                    *service = tcon->service;
 773         char                    last_component[MAXNAMELEN];
 774         smb_tree_t              *tree;
 775         int                     rc;
 776         uint32_t                access;
 777 
 778         ASSERT(user);
 779         ASSERT(user->u_cred);
 780 
 781         if (sr->sr_server->sv_cfg.skc_print_enable == 0) {
 782                 smb_tree_log(sr, sharename, "printing disabled");
 783                 return (NT_STATUS_BAD_NETWORK_NAME);
 784         }
 785 
 786         if (service != NULL &&
 787             strcmp(service, any) != 0 &&
 788             strcasecmp(service, "LPT1:") != 0) {
 789                 smb_tree_log(sr, sharename, "invalid service (%s)", service);
 790                 return (NT_STATUS_BAD_DEVICE_TYPE);
 791         }
 792 
 793         /*
 794          * Check that the shared directory exists.
 795          */
 796         rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
 797             last_component);
 798         if (rc == 0) {
 799                 rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
 800                     sr->sr_server->si_root_smb_node, dnode, last_component,
 801                     &snode);
 802 
 803                 smb_node_release(dnode);
 804         }
 805 
 806         if (rc) {
 807                 if (snode)
 808                         smb_node_release(snode);
 809 
 810                 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
 811                 return (NT_STATUS_BAD_NETWORK_NAME);
 812         }
 813 
 814         if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
 815                 smb_node_release(snode);
 816                 return (NT_STATUS_ACCESS_DENIED);
 817         }
 818 
 819         tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
 820 
 821         tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
 822 
 823         smb_node_release(snode);
 824 
 825         if (tree == NULL)
 826                 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
 827 
 828         sr->tid_tree = tree;
 829         sr->smb_tid  = tree->t_tid;
 830 
 831         return (0);
 832 }
 833 
 834 /*
 835  * Connect an IPC share for use with named pipes.
 836  */
 837 uint32_t
 838 smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon)
 839 {
 840         char            *name = tcon->path;
 841         const char      *any = "?????";
 842         smb_user_t      *user = sr->uid_user;
 843         smb_tree_t      *tree;
 844         smb_kshare_t    *si = tcon->si;
 845         char            *service = tcon->service;
 846 
 847         ASSERT(user);
 848 
 849         if (service != NULL &&
 850             strcmp(service, any) != 0 &&
 851             strcasecmp(service, "IPC") != 0) {
 852                 smb_tree_log(sr, name, "invalid service (%s)", service);
 853                 return (NT_STATUS_BAD_DEVICE_TYPE);
 854         }
 855 
 856         if ((user->u_flags & SMB_USER_FLAG_ANON) &&
 857             sr->sr_cfg->skc_restrict_anon) {
 858                 smb_tree_log(sr, name, "access denied: restrict anonymous");
 859                 return (NT_STATUS_ACCESS_DENIED);
 860         }
 861 
 862         tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
 863 
 864         tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
 865         if (tree == NULL)
 866                 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
 867 
 868         sr->tid_tree = tree;
 869         sr->smb_tid  = tree->t_tid;
 870 
 871         return (0);
 872 }
 873 
 874 /*
 875  * Allocate a tree.
 876  */
 877 static smb_tree_t *
 878 smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
 879     smb_node_t *snode, uint32_t access, uint32_t execflags)
 880 {
 881         smb_session_t   *session = sr->session;
 882         smb_tree_t      *tree;
 883         uint32_t        stype = si->shr_type;
 884         uint16_t        tid;
 885 
 886         if (smb_idpool_alloc(&session->s_tid_pool, &tid))
 887                 return (NULL);
 888 
 889         tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP);
 890         bzero(tree, sizeof (smb_tree_t));
 891 
 892         tree->t_session = session;
 893         tree->t_server = session->s_server;
 894 
 895         /* grab a ref for tree->t_owner */
 896         smb_user_hold_internal(sr->uid_user);
 897         tree->t_owner = sr->uid_user;
 898 
 899         if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
 900                 if (smb_tree_getattr(si, snode, tree) != 0) {
 901                         smb_idpool_free(&session->s_tid_pool, tid);
 902                         kmem_cache_free(smb_cache_tree, tree);
 903                         return (NULL);
 904                 }
 905         }
 906 
 907         if (smb_idpool_constructor(&tree->t_fid_pool)) {
 908                 smb_idpool_free(&session->s_tid_pool, tid);
 909                 kmem_cache_free(smb_cache_tree, tree);
 910                 return (NULL);
 911         }
 912 
 913         if (smb_idpool_constructor(&tree->t_odid_pool)) {
 914                 smb_idpool_destructor(&tree->t_fid_pool);
 915                 smb_idpool_free(&session->s_tid_pool, tid);
 916                 kmem_cache_free(smb_cache_tree, tree);
 917                 return (NULL);
 918         }
 919 
 920         smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
 921             offsetof(smb_ofile_t, f_lnd));
 922 
 923         smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
 924             offsetof(smb_odir_t, d_lnd));
 925 
 926         (void) strlcpy(tree->t_sharename, si->shr_name,
 927             sizeof (tree->t_sharename));
 928         (void) strlcpy(tree->t_resource, si->shr_path,
 929             sizeof (tree->t_resource));
 930 
 931         mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
 932 
 933         tree->t_refcnt = 1;
 934         tree->t_tid = tid;
 935         tree->t_res_type = stype;
 936         tree->t_state = SMB_TREE_STATE_CONNECTED;
 937         tree->t_magic = SMB_TREE_MAGIC;
 938         tree->t_access = access;
 939         tree->t_connect_time = gethrestime_sec();
 940         tree->t_execflags = execflags;
 941 
 942         /* if FS is readonly, enforce that here */
 943         if (tree->t_flags & SMB_TREE_READONLY)
 944                 tree->t_access &= ~ACE_ALL_WRITE_PERMS;
 945 
 946         if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
 947                 smb_node_ref(snode);
 948                 tree->t_snode = snode;
 949                 tree->t_acltype = smb_fsop_acltype(snode);
 950         }
 951 
 952         smb_llist_enter(&session->s_tree_list, RW_WRITER);
 953         smb_llist_insert_head(&session->s_tree_list, tree);
 954         smb_llist_exit(&session->s_tree_list);
 955         atomic_inc_32(&session->s_tree_cnt);
 956         smb_server_inc_trees(session->s_server);
 957         return (tree);
 958 }
 959 
 960 /*
 961  * Deallocate a tree.  The open file and open directory lists should be
 962  * empty.
 963  *
 964  * Remove the tree from the user's tree list before freeing resources
 965  * associated with the tree.
 966  */
 967 void
 968 smb_tree_dealloc(void *arg)
 969 {
 970         smb_session_t   *session;
 971         smb_tree_t      *tree = (smb_tree_t *)arg;
 972 
 973         SMB_TREE_VALID(tree);
 974         ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
 975         ASSERT(tree->t_refcnt == 0);
 976 
 977         session = tree->t_session;
 978         smb_llist_enter(&session->s_tree_list, RW_WRITER);
 979         smb_llist_remove(&session->s_tree_list, tree);
 980         smb_idpool_free(&session->s_tid_pool, tree->t_tid);
 981         atomic_dec_32(&session->s_tree_cnt);
 982         smb_llist_exit(&session->s_tree_list);
 983 
 984         mutex_enter(&tree->t_mutex);
 985         mutex_exit(&tree->t_mutex);
 986 
 987         tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
 988 
 989         if (tree->t_snode)
 990                 smb_node_release(tree->t_snode);
 991 
 992         mutex_destroy(&tree->t_mutex);
 993         smb_llist_destructor(&tree->t_ofile_list);
 994         smb_llist_destructor(&tree->t_odir_list);
 995         smb_idpool_destructor(&tree->t_fid_pool);
 996         smb_idpool_destructor(&tree->t_odid_pool);
 997 
 998         SMB_USER_VALID(tree->t_owner);
 999         smb_user_release(tree->t_owner);
1000 
1001         kmem_cache_free(smb_cache_tree, tree);
1002 }
1003 
1004 /*
1005  * Determine whether or not a tree is connected.
1006  * This function must be called with the tree mutex held.
1007  */
1008 static boolean_t
1009 smb_tree_is_connected_locked(smb_tree_t *tree)
1010 {
1011         switch (tree->t_state) {
1012         case SMB_TREE_STATE_CONNECTED:
1013                 return (B_TRUE);
1014 
1015         case SMB_TREE_STATE_DISCONNECTING:
1016         case SMB_TREE_STATE_DISCONNECTED:
1017                 /*
1018                  * The tree exists but being diconnected or destroyed.
1019                  */
1020                 return (B_FALSE);
1021 
1022         default:
1023                 ASSERT(0);
1024                 return (B_FALSE);
1025         }
1026 }
1027 
1028 /*
1029  * Determine whether or not a tree is disconnected.
1030  * This function must be called with the tree mutex held.
1031  */
1032 static boolean_t
1033 smb_tree_is_disconnected(smb_tree_t *tree)
1034 {
1035         switch (tree->t_state) {
1036         case SMB_TREE_STATE_DISCONNECTED:
1037                 return (B_TRUE);
1038 
1039         case SMB_TREE_STATE_CONNECTED:
1040         case SMB_TREE_STATE_DISCONNECTING:
1041                 return (B_FALSE);
1042 
1043         default:
1044                 ASSERT(0);
1045                 return (B_FALSE);
1046         }
1047 }
1048 
1049 /*
1050  * Return a pointer to the share name within a share resource path.
1051  *
1052  * The share path may be a Uniform Naming Convention (UNC) string
1053  * (\\server\share) or simply the share name.  We validate the UNC
1054  * format but we don't look at the server name.
1055  */
1056 static char *
1057 smb_tree_get_sharename(char *unc_path)
1058 {
1059         char *sharename = unc_path;
1060 
1061         if (sharename[0] == '\\') {
1062                 /*
1063                  * Looks like a UNC path, validate the format.
1064                  */
1065                 if (sharename[1] != '\\')
1066                         return (NULL);
1067 
1068                 if ((sharename = strchr(sharename+2, '\\')) == NULL)
1069                         return (NULL);
1070 
1071                 ++sharename;
1072         } else if (strchr(sharename, '\\') != NULL) {
1073                 /*
1074                  * This should be a share name (no embedded \'s).
1075                  */
1076                 return (NULL);
1077         }
1078 
1079         return (sharename);
1080 }
1081 
1082 /*
1083  * Obtain the tree attributes: volume name, typename and flags.
1084  */
1085 static int
1086 smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1087 {
1088         vfs_t *vfsp = SMB_NODE_VFS(node);
1089 
1090         ASSERT(vfsp);
1091 
1092         if (getvfs(&vfsp->vfs_fsid) != vfsp)
1093                 return (ESTALE);
1094 
1095         smb_tree_get_volname(vfsp, tree);
1096         smb_tree_get_flags(si, vfsp, tree);
1097 
1098         VFS_RELE(vfsp);
1099         return (0);
1100 }
1101 
1102 /*
1103  * Extract the volume name.
1104  */
1105 static void
1106 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1107 {
1108 #ifdef  _FAKE_KERNEL
1109         _NOTE(ARGUNUSED(vfsp))
1110         (void) strlcpy(tree->t_volume, "fake", SMB_VOLNAMELEN);
1111 #else   /* _FAKE_KERNEL */
1112         refstr_t *vfs_mntpoint;
1113         const char *s;
1114         char *name;
1115 
1116         vfs_mntpoint = vfs_getmntpoint(vfsp);
1117 
1118         s = refstr_value(vfs_mntpoint);
1119         s += strspn(s, "/");
1120         (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1121 
1122         refstr_rele(vfs_mntpoint);
1123 
1124         name = tree->t_volume;
1125         (void) strsep((char **)&name, "/");
1126 #endif  /* _FAKE_KERNEL */
1127 }
1128 
1129 /*
1130  * Always set "unicode on disk" because we always use utf8 names locally.
1131  * Always set ACL support because the VFS will fake ACLs for file systems
1132  * that don't support them.
1133  *
1134  * Some flags are dependent on the typename, which is also set up here.
1135  * File system types are hardcoded in uts/common/os/vfs_conf.c.
1136  */
1137 static void
1138 smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1139 {
1140         smb_session_t *ssn = tree->t_session;
1141         struct vfssw    *vswp;
1142 
1143         typedef struct smb_mtype {
1144                 char            *mt_name;
1145                 size_t          mt_namelen;
1146                 uint32_t        mt_flags;
1147         } smb_mtype_t;
1148 
1149         static smb_mtype_t smb_mtype[] = {
1150                 { "zfs",    3,  SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1151                 { "ufs",    3,  0 },
1152                 { "nfs",    3,  SMB_TREE_NFS_MOUNTED },
1153                 { "tmpfs",  5,  SMB_TREE_NO_EXPORT }
1154         };
1155         smb_mtype_t     *mtype;
1156         char            *name;
1157         uint32_t        flags =
1158             SMB_TREE_SUPPORTS_ACLS |
1159             SMB_TREE_UNICODE_ON_DISK;
1160         int             i;
1161 
1162         if (si->shr_flags & SMB_SHRF_DFSROOT)
1163                 flags |= SMB_TREE_DFSROOT;
1164 
1165         if (si->shr_flags & SMB_SHRF_CATIA)
1166                 flags |= SMB_TREE_CATIA;
1167 
1168         if (si->shr_flags & SMB_SHRF_ABE)
1169                 flags |= SMB_TREE_ABE;
1170 
1171         if (ssn->s_cfg.skc_oplock_enable) {
1172                 /* if 'smb' zfs property: oplocks=enabled */
1173                 flags |= SMB_TREE_OPLOCKS;
1174         }
1175 
1176         /* Global config option for now.  Later make per-share. */
1177         if (ssn->s_cfg.skc_traverse_mounts)
1178                 flags |= SMB_TREE_TRAVERSE_MOUNTS;
1179 
1180         /* if 'smb' zfs property: shortnames=enabled */
1181         if (smb_shortnames)
1182                 flags |= SMB_TREE_SHORTNAMES;
1183 
1184         if (vfsp->vfs_flag & VFS_RDONLY)
1185                 flags |= SMB_TREE_READONLY;
1186 
1187         if (vfsp->vfs_flag & VFS_XATTR)
1188                 flags |= SMB_TREE_STREAMS;
1189 
1190         vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp));
1191         if (vswp != NULL) {
1192                 name = vswp->vsw_name;
1193                 vfs_unrefvfssw(vswp);
1194         } else {
1195                 name = "?";
1196         }
1197 
1198         for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1199                 mtype = &smb_mtype[i];
1200                 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1201                         flags |= mtype->mt_flags;
1202         }
1203 
1204         (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1205         (void) smb_strupr((char *)tree->t_typename);
1206 
1207         if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1208                 flags |= SMB_TREE_XVATTR;
1209 
1210         if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1211                 flags |= SMB_TREE_CASEINSENSITIVE;
1212 
1213         if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1214                 flags |= SMB_TREE_NO_CASESENSITIVE;
1215 
1216         if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1217                 flags |= SMB_TREE_DIRENTFLAGS;
1218 
1219         if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1220                 flags |= SMB_TREE_ACLONCREATE;
1221 
1222         if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1223                 flags |= SMB_TREE_ACEMASKONACCESS;
1224 
1225         DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1226 
1227 
1228         tree->t_flags = flags;
1229 }
1230 
1231 /*
1232  * Report share access result to syslog.
1233  */
1234 static void
1235 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1236 {
1237         va_list ap;
1238         char buf[128];
1239         smb_user_t *user = sr->uid_user;
1240 
1241         ASSERT(user);
1242 
1243         if (smb_tcon_mute)
1244                 return;
1245 
1246         if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1247                 /*
1248                  * Only report normal users, i.e. ignore W2K misuse
1249                  * of the IPC connection by filtering out internal
1250                  * names such as nobody and root.
1251                  */
1252                 if ((strcmp(user->u_name, "root") == 0) ||
1253                     (strcmp(user->u_name, "nobody") == 0)) {
1254                         return;
1255                 }
1256         }
1257 
1258         va_start(ap, fmt);
1259         (void) vsnprintf(buf, 128, fmt, ap);
1260         va_end(ap);
1261 
1262         cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1263             user->u_domain, user->u_name, sharename, buf);
1264 }
1265 
1266 /*
1267  * smb_tree_lookup_odir
1268  *
1269  * Find the specified odir in the tree's list of odirs, and
1270  * attempt to obtain a hold on the odir.
1271  *
1272  * Returns NULL if odir not found or a hold cannot be obtained.
1273  */
1274 smb_odir_t *
1275 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
1276 {
1277         smb_odir_t      *od;
1278         smb_llist_t     *od_list;
1279         smb_tree_t      *tree = sr->tid_tree;
1280 
1281         ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1282 
1283         od_list = &tree->t_odir_list;
1284 
1285         smb_llist_enter(od_list, RW_READER);
1286         od = smb_llist_head(od_list);
1287         while (od) {
1288                 if (od->d_odid == odid)
1289                         break;
1290                 od = smb_llist_next(od_list, od);
1291         }
1292         if (od == NULL)
1293                 goto out;
1294 
1295         /*
1296          * Only allow use of a given Search ID with the same UID that
1297          * was used to create it.  MS-CIFS 3.3.5.14
1298          */
1299         if (od->d_user != sr->uid_user) {
1300                 od = NULL;
1301                 goto out;
1302         }
1303         if (!smb_odir_hold(od))
1304                 od = NULL;
1305 
1306 out:
1307         smb_llist_exit(od_list);
1308         return (od);
1309 }
1310 
1311 boolean_t
1312 smb_tree_is_connected(smb_tree_t *tree)
1313 {
1314         boolean_t       rb;
1315 
1316         mutex_enter(&tree->t_mutex);
1317         rb = smb_tree_is_connected_locked(tree);
1318         mutex_exit(&tree->t_mutex);
1319         return (rb);
1320 }
1321 
1322 /*
1323  * Get the next open ofile in the list.  A reference is taken on
1324  * the ofile, which can be released later with smb_ofile_release().
1325  *
1326  * If the specified ofile is NULL, search from the beginning of the
1327  * list.  Otherwise, the search starts just after that ofile.
1328  *
1329  * Returns NULL if there are no open files in the list.
1330  */
1331 static smb_ofile_t *
1332 smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of)
1333 {
1334         smb_llist_t *ofile_list;
1335 
1336         ASSERT(tree);
1337         ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1338 
1339         ofile_list = &tree->t_ofile_list;
1340         smb_llist_enter(ofile_list, RW_READER);
1341 
1342         if (of) {
1343                 ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1344                 of = smb_llist_next(ofile_list, of);
1345         } else {
1346                 of = smb_llist_head(ofile_list);
1347         }
1348 
1349         while (of) {
1350                 if (smb_ofile_hold(of))
1351                         break;
1352 
1353                 of = smb_llist_next(ofile_list, of);
1354         }
1355 
1356         smb_llist_exit(ofile_list);
1357         return (of);
1358 }
1359 
1360 /*
1361  * smb_tree_get_odir
1362  *
1363  * Find the next odir in the tree's list of odirs, and obtain a
1364  * hold on it.
1365  * If the specified odir is NULL the search starts at the beginning
1366  * of the tree's odir list, otherwise the search starts after the
1367  * specified odir.
1368  */
1369 static smb_odir_t *
1370 smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
1371 {
1372         smb_llist_t *od_list;
1373 
1374         ASSERT(tree);
1375         ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1376 
1377         od_list = &tree->t_odir_list;
1378         smb_llist_enter(od_list, RW_READER);
1379 
1380         if (od) {
1381                 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1382                 od = smb_llist_next(od_list, od);
1383         } else {
1384                 od = smb_llist_head(od_list);
1385         }
1386 
1387         while (od) {
1388                 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1389 
1390                 if (smb_odir_hold(od))
1391                         break;
1392                 od = smb_llist_next(od_list, od);
1393         }
1394 
1395         smb_llist_exit(od_list);
1396         return (od);
1397 }
1398 
1399 /*
1400  * smb_tree_close_odirs
1401  *
1402  * Close all open odirs in the tree's list which were opened by
1403  * the process identified by pid.
1404  * If pid is zero, close all open odirs in the tree's list.
1405  */
1406 static void
1407 smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
1408 {
1409         smb_odir_t *od, *next_od;
1410 
1411         ASSERT(tree);
1412         ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1413 
1414         od = smb_tree_get_odir(tree, NULL);
1415         while (od) {
1416                 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1417                 ASSERT(od->d_tree == tree);
1418 
1419                 next_od = smb_tree_get_odir(tree, od);
1420                 if ((pid == 0) || (od->d_opened_by_pid == pid))
1421                         smb_odir_close(od);
1422                 smb_odir_release(od);
1423 
1424                 od = next_od;
1425         }
1426 }
1427 
1428 static void
1429 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
1430     int exec_type)
1431 {
1432         exec->e_sharename = tree->t_sharename;
1433         exec->e_winname = tree->t_owner->u_name;
1434         exec->e_userdom = tree->t_owner->u_domain;
1435         exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1436         exec->e_cli_ipaddr = tree->t_session->ipaddr;
1437         exec->e_cli_netbiosname = tree->t_session->workstation;
1438         exec->e_uid = crgetuid(tree->t_owner->u_cred);
1439         exec->e_type = exec_type;
1440 }
1441 
1442 /*
1443  * Private function to support smb_tree_enum.
1444  */
1445 static int
1446 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
1447 {
1448         uint8_t *pb;
1449         uint_t nbytes;
1450         int rc;
1451 
1452         if (svcenum->se_nskip > 0) {
1453                 svcenum->se_nskip--;
1454                 return (0);
1455         }
1456 
1457         if (svcenum->se_nitems >= svcenum->se_nlimit) {
1458                 svcenum->se_nitems = svcenum->se_nlimit;
1459                 return (0);
1460         }
1461 
1462         pb = &svcenum->se_buf[svcenum->se_bused];
1463         rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
1464         if (rc == 0) {
1465                 svcenum->se_bavail -= nbytes;
1466                 svcenum->se_bused += nbytes;
1467                 svcenum->se_nitems++;
1468         }
1469 
1470         return (rc);
1471 }
1472 
1473 /*
1474  * Encode connection information into a buffer: connection information
1475  * needed in user space to support RPC requests.
1476  */
1477 static int
1478 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
1479     uint32_t *nbytes)
1480 {
1481         smb_netconnectinfo_t    info;
1482         int                     rc;
1483 
1484         smb_tree_netinfo_init(tree, &info);
1485         rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
1486         smb_tree_netinfo_fini(&info);
1487 
1488         return (rc);
1489 }
1490 
1491 static void
1492 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
1493 {
1494         smb_user_t              *user = tree->t_owner;
1495 
1496         /*
1497          * u_domain_len and u_name_len include the '\0' in their
1498          * lengths, hence the sum of the two lengths gives us room
1499          * for both the '\\' and '\0' chars.
1500          */
1501         ASSERT(namestr);
1502         ASSERT(namelen);
1503         ASSERT(user->u_domain_len > 0);
1504         ASSERT(user->u_name_len > 0);
1505         *namelen = user->u_domain_len + user->u_name_len;
1506         *namestr = kmem_alloc(*namelen, KM_SLEEP);
1507         (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
1508             user->u_name);
1509 }
1510 
1511 /*
1512  * Note: ci_numusers should be the number of users connected to
1513  * the share rather than the number of references on the tree but
1514  * we don't have a mechanism to track users/share in smbsrv yet.
1515  */
1516 static void
1517 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
1518 {
1519         ASSERT(tree);
1520 
1521         info->ci_id = tree->t_tid;
1522         info->ci_type = tree->t_res_type;
1523         info->ci_numopens = tree->t_open_files;
1524         info->ci_numusers = tree->t_refcnt;
1525         info->ci_time = gethrestime_sec() - tree->t_connect_time;
1526 
1527         info->ci_sharelen = strlen(tree->t_sharename) + 1;
1528         info->ci_share = smb_mem_strdup(tree->t_sharename);
1529 
1530         smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
1531 }
1532 
1533 static void
1534 smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
1535 {
1536         if (info == NULL)
1537                 return;
1538 
1539         if (info->ci_username)
1540                 kmem_free(info->ci_username, info->ci_namelen);
1541         if (info->ci_share)
1542                 smb_mem_free(info->ci_share);
1543 
1544         bzero(info, sizeof (smb_netconnectinfo_t));
1545 }