Print this page
    
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
re #14152 Race between ipmi_submit_driver_request() and kcs_loop() (sync with illumos fix 3902)
SMB-46 File handle leaks exposed by mtime fixes (rm 7815)
re #7815 SMB server delivers old modification time...
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/smbsrv/smb_directory.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_directory.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
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | 
      ↓ open down ↓ | 
    14 lines elided | 
    
      ↑ open up ↑ | 
  
  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   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   *
  25      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       25 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  26   26   */
  27   27  
  28   28  #include <smbsrv/smb_kproto.h>
  29   29  #include <smbsrv/smbinfo.h>
  30   30  #include <smbsrv/smb_fsops.h>
  31   31  
  32   32  /*
  33   33   * The create directory message is sent to create a new directory.  The
  34   34   * appropriate Tid and additional pathname are passed.  The directory must
  35   35   * not exist for it to be created.
  36   36   *
  37   37   * Client Request                     Description
  38   38   * ================================== =================================
  39   39   * UCHAR WordCount;                   Count of parameter words = 0
  40   40   * USHORT ByteCount;                  Count of data bytes; min = 2
  41   41   * UCHAR BufferFormat;                0x04
  42   42   * STRING DirectoryName[];            Directory name
  43   43   *
  44   44   * Servers require clients to have at least create permission for the
  45   45   * subtree containing the directory in order to create a new directory.
  46   46   * The creator's access rights to the new directory are be determined by
  47   47   * local policy on the server.
  48   48   *
  49   49   * Server Response                    Description
  50   50   * ================================== =================================
  51   51   * UCHAR WordCount;                   Count of parameter words = 0
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
  52   52   * USHORT ByteCount;                  Count of data bytes = 0
  53   53   */
  54   54  smb_sdrc_t
  55   55  smb_pre_create_directory(smb_request_t *sr)
  56   56  {
  57   57          int rc;
  58   58  
  59   59          rc = smbsr_decode_data(sr, "%S", sr,
  60   60              &sr->arg.dirop.fqi.fq_path.pn_path);
  61   61  
  62      -        DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr,
  63      -            struct dirop *, &sr->arg.dirop);
       62 +        DTRACE_SMB_START(op__CreateDirectory, smb_request_t *, sr);
  64   63  
  65   64          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  66   65  }
  67   66  
  68   67  void
  69   68  smb_post_create_directory(smb_request_t *sr)
  70   69  {
  71      -        DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, sr);
       70 +        DTRACE_SMB_DONE(op__CreateDirectory, smb_request_t *, sr);
  72   71  }
  73   72  
  74   73  smb_sdrc_t
  75   74  smb_com_create_directory(smb_request_t *sr)
  76   75  {
  77   76          int rc = 0;
  78   77          smb_pathname_t *pn = &sr->arg.dirop.fqi.fq_path;
  79   78  
  80   79          if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
  81   80                  smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
  82   81                      ERRDOS, ERROR_ACCESS_DENIED);
  83   82                  return (SDRC_ERROR);
  84   83          }
  85   84  
  86   85          smb_pathname_init(sr, pn, pn->pn_path);
  87   86          if (!smb_pathname_validate(sr, pn) ||
  88   87              !smb_validate_dirname(sr, pn)) {
  89   88                  return (SDRC_ERROR);
  90   89          }
  91   90  
  92   91          if ((rc = smb_common_create_directory(sr)) != 0) {
  93   92                  smbsr_errno(sr, rc);
  94   93                  return (SDRC_ERROR);
  95   94          }
  96   95  
  97   96          rc = smbsr_encode_empty_result(sr);
  98   97          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  99   98  }
 100   99  
 101  100  /*
 102  101   * smb_common_create_directory
 103  102   *
 104  103   * Currently called from:
 105  104   *              smb_com_create_directory
 106  105   *              smb_com_trans2_create_directory
 107  106   *
 108  107   * Returns errno values.
 109  108   */
 110  109  int
 111  110  smb_common_create_directory(smb_request_t *sr)
 112  111  {
 113  112          int rc;
 114  113          smb_attr_t new_attr;
 115  114          smb_fqi_t *fqi;
 116  115          smb_node_t *tnode;
 117  116  
 118  117          fqi = &sr->arg.dirop.fqi;
 119  118          tnode = sr->tid_tree->t_snode;
 120  119  
 121  120          rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
 122  121              tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
 123  122          if (rc != 0)
 124  123                  return (rc);
 125  124  
 126  125          if (smb_is_invalid_filename(fqi->fq_last_comp)) {
 127  126                  smb_node_release(fqi->fq_dnode);
 128  127                  return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */
 129  128          }
 130  129  
 131  130          /* lookup node - to ensure that it does NOT exist */
 132  131          rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 133  132              tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
 134  133          if (rc == 0) {
 135  134                  smb_node_release(fqi->fq_dnode);
 136  135                  smb_node_release(fqi->fq_fnode);
 137  136                  return (EEXIST);
 138  137          }
 139  138          if (rc != ENOENT) {
 140  139                  smb_node_release(fqi->fq_dnode);
 141  140                  return (rc);
 142  141          }
 143  142  
 144  143          rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
 145  144              FILE_ADD_SUBDIRECTORY);
 146  145          if (rc != NT_STATUS_SUCCESS) {
 147  146                  smb_node_release(fqi->fq_dnode);
 148  147                  return (EACCES);
 149  148          }
 150  149  
 151  150          /*
 152  151           * Explicitly set sa_dosattr, otherwise the file system may
 153  152           * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for
 154  153           * compatibility with windows servers, should not be set.
 155  154           */
 156  155          bzero(&new_attr, sizeof (new_attr));
 157  156          new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY;
 158  157          new_attr.sa_vattr.va_type = VDIR;
 159  158          new_attr.sa_vattr.va_mode = 0777;
 160  159          new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
 161  160  
 162  161          rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp,
 163  162              &new_attr, &fqi->fq_fnode);
 164  163          if (rc != 0) {
 165  164                  smb_node_release(fqi->fq_dnode);
 166  165                  return (rc);
 167  166          }
 168  167  
 169  168          sr->arg.open.create_options = FILE_DIRECTORY_FILE;
 170  169  
 171  170          smb_node_release(fqi->fq_dnode);
 172  171          smb_node_release(fqi->fq_fnode);
 173  172          return (0);
 174  173  }
 175  174  
 176  175  /*
 177  176   * The delete directory message is sent to delete an empty directory. The
 178  177   * appropriate Tid and additional pathname are passed. The directory must
 179  178   * be empty for it to be deleted.
 180  179   *
 181  180   * NT supports a hidden permission known as File Delete Child (FDC). If
 182  181   * the user has FullControl access to a directory, the user is permitted
 183  182   * to delete any object in the directory regardless of the permissions
 184  183   * on the object.
 185  184   *
 186  185   * Client Request                     Description
 187  186   * ================================== =================================
 188  187   * UCHAR WordCount;                   Count of parameter words = 0
 189  188   * USHORT ByteCount;                  Count of data bytes; min = 2
 190  189   * UCHAR BufferFormat;                0x04
 191  190   * STRING DirectoryName[];            Directory name
 192  191   *
 193  192   * The directory to be deleted cannot be the root of the share specified
 194  193   * by Tid.
 195  194   *
 196  195   * Server Response                    Description
 197  196   * ================================== =================================
 198  197   * UCHAR WordCount;                   Count of parameter words = 0
  
    | 
      ↓ open down ↓ | 
    117 lines elided | 
    
      ↑ open up ↑ | 
  
 199  198   * USHORT ByteCount;                  Count of data bytes = 0
 200  199   */
 201  200  smb_sdrc_t
 202  201  smb_pre_delete_directory(smb_request_t *sr)
 203  202  {
 204  203          int rc;
 205  204  
 206  205          rc = smbsr_decode_data(sr, "%S", sr,
 207  206              &sr->arg.dirop.fqi.fq_path.pn_path);
 208  207  
 209      -        DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr,
 210      -            struct dirop *, &sr->arg.dirop);
      208 +        DTRACE_SMB_START(op__DeleteDirectory, smb_request_t *, sr);
 211  209  
 212  210          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 213  211  }
 214  212  
 215  213  void
 216  214  smb_post_delete_directory(smb_request_t *sr)
 217  215  {
 218      -        DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr);
      216 +        DTRACE_SMB_DONE(op__DeleteDirectory, smb_request_t *, sr);
 219  217  }
 220  218  
 221  219  smb_sdrc_t
 222  220  smb_com_delete_directory(smb_request_t *sr)
 223  221  {
 224  222          int rc;
 225  223          uint32_t flags = 0;
 226  224          smb_fqi_t *fqi;
 227  225          smb_node_t *tnode;
 228  226  
 229  227          if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 230  228                  smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 231  229                      ERRDOS, ERROR_ACCESS_DENIED);
 232  230                  return (SDRC_ERROR);
 233  231          }
 234  232  
 235  233          fqi = &sr->arg.dirop.fqi;
 236  234          tnode = sr->tid_tree->t_snode;
 237  235  
 238  236          smb_pathname_init(sr, &fqi->fq_path, fqi->fq_path.pn_path);
 239  237          if (!smb_pathname_validate(sr, &fqi->fq_path) ||
 240  238              !smb_validate_dirname(sr, &fqi->fq_path)) {
 241  239                  return (SDRC_ERROR);
 242  240          }
 243  241  
 244  242          rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
 245  243              tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
 246  244  
 247  245          if (rc != 0) {
 248  246                  smbsr_errno(sr, rc);
 249  247                  return (SDRC_ERROR);
 250  248          }
 251  249  
 252  250          rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 253  251              tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
 254  252          if (rc != 0) {
 255      -                if (rc == ENOENT)
 256      -                        smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 257      -                            ERRDOS, ERROR_FILE_NOT_FOUND);
 258      -                else
 259      -                        smbsr_errno(sr, rc);
      253 +                smbsr_errno(sr, rc);
 260  254                  smb_node_release(fqi->fq_dnode);
 261  255                  return (SDRC_ERROR);
 262  256          }
 263  257  
 264  258          /*
 265  259           * Delete should fail if this is the root of a share
 266  260           * or a DFS link
 267  261           */
 268  262          if ((fqi->fq_fnode == tnode) || smb_node_is_dfslink(fqi->fq_fnode)) {
 269  263                  smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 270  264                      ERRDOS, ERROR_ACCESS_DENIED);
 271  265                  smb_node_release(fqi->fq_dnode);
 272  266                  smb_node_release(fqi->fq_fnode);
 273  267                  return (SDRC_ERROR);
 274  268          }
 275  269  
 276  270          if (!smb_node_is_dir(fqi->fq_fnode)) {
 277  271                  smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
 278  272                      ERRDOS, ERROR_PATH_NOT_FOUND);
 279  273                  smb_node_release(fqi->fq_dnode);
 280  274                  smb_node_release(fqi->fq_fnode);
 281  275                  return (SDRC_ERROR);
 282  276          }
 283  277  
 284  278          /*
 285  279           * Using kcred because we just want the DOS attrs
 286  280           * and don't want access errors for this.
 287  281           */
 288  282          fqi->fq_fattr.sa_mask = SMB_AT_DOSATTR;
 289  283          rc = smb_node_getattr(sr, fqi->fq_fnode, zone_kcred(), NULL,
 290  284              &fqi->fq_fattr);
 291  285          if (rc != 0) {
 292  286                  smbsr_errno(sr, rc);
 293  287                  smb_node_release(fqi->fq_dnode);
 294  288                  smb_node_release(fqi->fq_fnode);
 295  289                  return (SDRC_ERROR);
 296  290          }
 297  291  
 298  292          if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
 299  293              (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
 300  294              != NT_STATUS_SUCCESS)) {
 301  295                  smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
 302  296                      ERRDOS, ERROR_ACCESS_DENIED);
 303  297                  smb_node_release(fqi->fq_dnode);
 304  298                  smb_node_release(fqi->fq_fnode);
 305  299                  return (SDRC_ERROR);
 306  300          }
 307  301  
 308  302          if (SMB_TREE_SUPPORTS_CATIA(sr))
 309  303                  flags |= SMB_CATIA;
 310  304  
 311  305          rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
 312  306              fqi->fq_fnode->od_name, flags);
 313  307  
 314  308          smb_node_release(fqi->fq_fnode);
 315  309          smb_node_release(fqi->fq_dnode);
 316  310  
 317  311          if (rc != 0) {
 318  312                  if (rc == EEXIST)
 319  313                          smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
 320  314                              ERRDOS, ERROR_DIR_NOT_EMPTY);
 321  315                  else
 322  316                          smbsr_errno(sr, rc);
 323  317                  return (SDRC_ERROR);
 324  318          }
 325  319  
 326  320          rc = smbsr_encode_empty_result(sr);
 327  321          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 328  322  }
 329  323  
 330  324  /*
 331  325   * This SMB is used to verify that a path exists and is a directory.  No
 332  326   * error is returned if the given path exists and the client has read
 333  327   * access to it.  Client machines which maintain a concept of a "working
 334  328   * directory" will find this useful to verify the validity of a "change
 335  329   * working directory" command.  Note that the servers do NOT have a concept
 336  330   * of working directory for a particular client.  The client must always
 337  331   * supply full pathnames relative to the Tid in the SMB header.
 338  332   *
 339  333   * Client Request                     Description
 340  334   * ================================== =================================
 341  335   *
 342  336   * UCHAR WordCount;                   Count of parameter words = 0
 343  337   * USHORT ByteCount;                  Count of data bytes;    min = 2
 344  338   * UCHAR BufferFormat;                0x04
 345  339   * STRING DirectoryPath[];            Directory path
 346  340   *
 347  341   * Server Response                    Description
 348  342   * ================================== =================================
 349  343   *
 350  344   * UCHAR WordCount;                   Count of parameter words = 0
 351  345   * USHORT ByteCount;                  Count of data bytes = 0
 352  346   *
 353  347   * DOS clients, in particular, depend on ERRbadpath if the directory is
  
    | 
      ↓ open down ↓ | 
    84 lines elided | 
    
      ↑ open up ↑ | 
  
 354  348   * not found.
 355  349   */
 356  350  smb_sdrc_t
 357  351  smb_pre_check_directory(smb_request_t *sr)
 358  352  {
 359  353          int rc;
 360  354  
 361  355          rc = smbsr_decode_data(sr, "%S", sr,
 362  356              &sr->arg.dirop.fqi.fq_path.pn_path);
 363  357  
 364      -        DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr,
 365      -            struct dirop *, &sr->arg.dirop);
      358 +        DTRACE_SMB_START(op__CheckDirectory, smb_request_t *, sr);
 366  359  
 367  360          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 368  361  }
 369  362  
 370  363  void
 371  364  smb_post_check_directory(smb_request_t *sr)
 372  365  {
 373      -        DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr);
      366 +        DTRACE_SMB_DONE(op__CheckDirectory, smb_request_t *, sr);
 374  367  }
 375  368  
 376  369  smb_sdrc_t
 377  370  smb_com_check_directory(smb_request_t *sr)
 378  371  {
 379  372          int rc;
 380  373          smb_fqi_t *fqi;
 381  374          smb_node_t *tnode;
 382  375          smb_node_t *node;
 383  376          char *path;
 384  377          smb_pathname_t *pn;
 385  378  
 386  379          if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
 387  380                  smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
 388  381                      ERROR_ACCESS_DENIED);
 389  382                  return (SDRC_ERROR);
 390  383          }
 391  384  
 392  385          fqi = &sr->arg.dirop.fqi;
 393  386          pn = &fqi->fq_path;
 394  387  
 395  388          if (pn->pn_path[0] == '\0') {
 396  389                  rc = smbsr_encode_empty_result(sr);
 397  390                  return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 398  391          }
 399  392  
 400  393          smb_pathname_init(sr, pn, pn->pn_path);
 401  394          if (!smb_pathname_validate(sr, pn) ||
 402  395              !smb_validate_dirname(sr, pn)) {
 403  396                  return (SDRC_ERROR);
 404  397          }
 405  398  
 406  399          path = pn->pn_path;
 407  400          tnode = sr->tid_tree->t_snode;
 408  401  
 409  402          rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
  
    | 
      ↓ open down ↓ | 
    26 lines elided | 
    
      ↑ open up ↑ | 
  
 410  403              &fqi->fq_dnode, fqi->fq_last_comp);
 411  404          if (rc != 0) {
 412  405                  smbsr_errno(sr, rc);
 413  406                  return (SDRC_ERROR);
 414  407          }
 415  408  
 416  409          rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 417  410              tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
 418  411          smb_node_release(fqi->fq_dnode);
 419  412          if (rc != 0) {
 420      -                if (rc == ENOENT)
 421      -                        smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 422      -                            ERRDOS, ERROR_PATH_NOT_FOUND);
 423      -                else
 424      -                        smbsr_errno(sr, rc);
      413 +                smbsr_errno(sr, rc);
 425  414                  return (SDRC_ERROR);
 426  415          }
 427  416  
 428  417          node = fqi->fq_fnode;
 429  418          if (!smb_node_is_dir(node)) {
 430  419                  smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
 431  420                      ERRDOS, ERROR_PATH_NOT_FOUND);
 432  421                  smb_node_release(node);
 433  422                  return (SDRC_ERROR);
 434  423          }
 435  424  
 436  425          if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
 437  426                  smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
 438  427                  smb_node_release(node);
 439  428                  return (SDRC_ERROR);
 440  429          }
 441  430  
 442  431          rc = smb_fsop_access(sr, sr->user_cr, node, FILE_TRAVERSE);
 443  432  
 444  433          smb_node_release(node);
 445  434  
 446  435          if (rc != 0) {
 447  436                  smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 448  437                      ERRDOS, ERROR_ACCESS_DENIED);
 449  438                  return (SDRC_ERROR);
 450  439          }
 451  440  
 452  441          rc = smbsr_encode_empty_result(sr);
 453  442          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 454  443  }
  
    | 
      ↓ open down ↓ | 
    20 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX