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