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