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 2013 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_1(op__CreateDirectory__start, smb_request_t *, sr); /* arg.dirop */
  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_1(op__CreateDirectory__done, 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_1(op__DeleteDirectory__start, smb_request_t *, sr); /* arg.dirop */
 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_1(op__DeleteDirectory__done, 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                 if (rc == ENOENT)
 254                         smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 255                             ERRDOS, ERROR_FILE_NOT_FOUND);
 256                 else
 257                         smbsr_errno(sr, rc);
 258                 smb_node_release(fqi->fq_dnode);
 259                 return (SDRC_ERROR);
 260         }
 261 
 262         /*
 263          * Delete should fail if this is the root of a share
 264          * or a DFS link
 265          */
 266         if ((fqi->fq_fnode == tnode) || smb_node_is_dfslink(fqi->fq_fnode)) {
 267                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 268                     ERRDOS, ERROR_ACCESS_DENIED);
 269                 smb_node_release(fqi->fq_dnode);
 270                 smb_node_release(fqi->fq_fnode);
 271                 return (SDRC_ERROR);
 272         }
 273 
 274         if (!smb_node_is_dir(fqi->fq_fnode)) {
 275                 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
 276                     ERRDOS, ERROR_PATH_NOT_FOUND);
 277                 smb_node_release(fqi->fq_dnode);
 278                 smb_node_release(fqi->fq_fnode);
 279                 return (SDRC_ERROR);
 280         }
 281 
 282         /*
 283          * Using kcred because we just want the DOS attrs
 284          * and don't want access errors for this.
 285          */
 286         fqi->fq_fattr.sa_mask = SMB_AT_DOSATTR;
 287         rc = smb_node_getattr(sr, fqi->fq_fnode, zone_kcred(), NULL,
 288             &fqi->fq_fattr);
 289         if (rc != 0) {
 290                 smbsr_errno(sr, rc);
 291                 smb_node_release(fqi->fq_dnode);
 292                 smb_node_release(fqi->fq_fnode);
 293                 return (SDRC_ERROR);
 294         }
 295 
 296         if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
 297             (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
 298             != NT_STATUS_SUCCESS)) {
 299                 smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
 300                     ERRDOS, ERROR_ACCESS_DENIED);
 301                 smb_node_release(fqi->fq_dnode);
 302                 smb_node_release(fqi->fq_fnode);
 303                 return (SDRC_ERROR);
 304         }
 305 
 306         if (SMB_TREE_SUPPORTS_CATIA(sr))
 307                 flags |= SMB_CATIA;
 308 
 309         rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
 310             fqi->fq_fnode->od_name, flags);
 311 
 312         smb_node_release(fqi->fq_fnode);
 313         smb_node_release(fqi->fq_dnode);
 314 
 315         if (rc != 0) {
 316                 if (rc == EEXIST)
 317                         smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
 318                             ERRDOS, ERROR_DIR_NOT_EMPTY);
 319                 else
 320                         smbsr_errno(sr, rc);
 321                 return (SDRC_ERROR);
 322         }
 323 
 324         rc = smbsr_encode_empty_result(sr);
 325         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 326 }
 327 
 328 /*
 329  * This SMB is used to verify that a path exists and is a directory.  No
 330  * error is returned if the given path exists and the client has read
 331  * access to it.  Client machines which maintain a concept of a "working
 332  * directory" will find this useful to verify the validity of a "change
 333  * working directory" command.  Note that the servers do NOT have a concept
 334  * of working directory for a particular client.  The client must always
 335  * supply full pathnames relative to the Tid in the SMB header.
 336  *
 337  * Client Request                     Description
 338  * ================================== =================================
 339  *
 340  * UCHAR WordCount;                   Count of parameter words = 0
 341  * USHORT ByteCount;                  Count of data bytes;    min = 2
 342  * UCHAR BufferFormat;                0x04
 343  * STRING DirectoryPath[];            Directory path
 344  *
 345  * Server Response                    Description
 346  * ================================== =================================
 347  *
 348  * UCHAR WordCount;                   Count of parameter words = 0
 349  * USHORT ByteCount;                  Count of data bytes = 0
 350  *
 351  * DOS clients, in particular, depend on ERRbadpath if the directory is
 352  * not found.
 353  */
 354 smb_sdrc_t
 355 smb_pre_check_directory(smb_request_t *sr)
 356 {
 357         int rc;
 358 
 359         rc = smbsr_decode_data(sr, "%S", sr,
 360             &sr->arg.dirop.fqi.fq_path.pn_path);
 361 
 362         DTRACE_SMB_1(op__CheckDirectory__start, smb_request_t *, sr); /* arg.dirop */
 363 
 364         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 365 }
 366 
 367 void
 368 smb_post_check_directory(smb_request_t *sr)
 369 {
 370         DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr);
 371 }
 372 
 373 smb_sdrc_t
 374 smb_com_check_directory(smb_request_t *sr)
 375 {
 376         int rc;
 377         smb_fqi_t *fqi;
 378         smb_node_t *tnode;
 379         smb_node_t *node;
 380         char *path;
 381         smb_pathname_t *pn;
 382 
 383         if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
 384                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
 385                     ERROR_ACCESS_DENIED);
 386                 return (SDRC_ERROR);
 387         }
 388 
 389         fqi = &sr->arg.dirop.fqi;
 390         pn = &fqi->fq_path;
 391 
 392         if (pn->pn_path[0] == '\0') {
 393                 rc = smbsr_encode_empty_result(sr);
 394                 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 395         }
 396 
 397         smb_pathname_init(sr, pn, pn->pn_path);
 398         if (!smb_pathname_validate(sr, pn) ||
 399             !smb_validate_dirname(sr, pn)) {
 400                 return (SDRC_ERROR);
 401         }
 402 
 403         path = pn->pn_path;
 404         tnode = sr->tid_tree->t_snode;
 405 
 406         rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 407             &fqi->fq_dnode, fqi->fq_last_comp);
 408         if (rc != 0) {
 409                 smbsr_errno(sr, rc);
 410                 return (SDRC_ERROR);
 411         }
 412 
 413         rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 414             tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
 415         smb_node_release(fqi->fq_dnode);
 416         if (rc != 0) {
 417                 if (rc == ENOENT)
 418                         smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 419                             ERRDOS, ERROR_PATH_NOT_FOUND);
 420                 else
 421                         smbsr_errno(sr, rc);
 422                 return (SDRC_ERROR);
 423         }
 424 
 425         node = fqi->fq_fnode;
 426         if (!smb_node_is_dir(node)) {
 427                 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
 428                     ERRDOS, ERROR_PATH_NOT_FOUND);
 429                 smb_node_release(node);
 430                 return (SDRC_ERROR);
 431         }
 432 
 433         if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
 434                 smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
 435                 smb_node_release(node);
 436                 return (SDRC_ERROR);
 437         }
 438 
 439         rc = smb_fsop_access(sr, sr->user_cr, node, FILE_TRAVERSE);
 440 
 441         smb_node_release(node);
 442 
 443         if (rc != 0) {
 444                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 445                     ERRDOS, ERROR_ACCESS_DENIED);
 446                 return (SDRC_ERROR);
 447         }
 448 
 449         rc = smbsr_encode_empty_result(sr);
 450         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 451 }