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_2(op__CreateDirectory__start, smb_request_t *, sr,
  63             struct dirop *, &sr->arg.dirop);
  64 
  65         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  66 }
  67 
  68 void
  69 smb_post_create_directory(smb_request_t *sr)
  70 {
  71         DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, sr);
  72 }
  73 
  74 smb_sdrc_t
  75 smb_com_create_directory(smb_request_t *sr)
  76 {
  77         int rc = 0;
  78         smb_pathname_t *pn = &sr->arg.dirop.fqi.fq_path;
  79 
  80         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
  81                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
  82                     ERRDOS, ERROR_ACCESS_DENIED);
  83                 return (SDRC_ERROR);
  84         }
  85 
  86         smb_pathname_init(sr, pn, pn->pn_path);
  87         if (!smb_pathname_validate(sr, pn) ||
  88             !smb_validate_dirname(sr, pn)) {
  89                 return (SDRC_ERROR);
  90         }
  91 
  92         if ((rc = smb_common_create_directory(sr)) != 0) {
  93                 smbsr_errno(sr, rc);
  94                 return (SDRC_ERROR);
  95         }
  96 
  97         rc = smbsr_encode_empty_result(sr);
  98         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  99 }
 100 
 101 /*
 102  * smb_common_create_directory
 103  *
 104  * Currently called from:
 105  *              smb_com_create_directory
 106  *              smb_com_trans2_create_directory
 107  *
 108  * Returns errno values.
 109  */
 110 int
 111 smb_common_create_directory(smb_request_t *sr)
 112 {
 113         int rc;
 114         smb_attr_t new_attr;
 115         smb_fqi_t *fqi;
 116         smb_node_t *tnode;
 117 
 118         fqi = &sr->arg.dirop.fqi;
 119         tnode = sr->tid_tree->t_snode;
 120 
 121         rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
 122             tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
 123         if (rc != 0)
 124                 return (rc);
 125 
 126         if (smb_is_invalid_filename(fqi->fq_last_comp)) {
 127                 smb_node_release(fqi->fq_dnode);
 128                 return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */
 129         }
 130 
 131         /* lookup node - to ensure that it does NOT exist */
 132         rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 133             tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
 134         if (rc == 0) {
 135                 smb_node_release(fqi->fq_dnode);
 136                 smb_node_release(fqi->fq_fnode);
 137                 return (EEXIST);
 138         }
 139         if (rc != ENOENT) {
 140                 smb_node_release(fqi->fq_dnode);
 141                 return (rc);
 142         }
 143 
 144         rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
 145             FILE_ADD_SUBDIRECTORY);
 146         if (rc != NT_STATUS_SUCCESS) {
 147                 smb_node_release(fqi->fq_dnode);
 148                 return (EACCES);
 149         }
 150 
 151         /*
 152          * Explicitly set sa_dosattr, otherwise the file system may
 153          * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for
 154          * compatibility with windows servers, should not be set.
 155          */
 156         bzero(&new_attr, sizeof (new_attr));
 157         new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY;
 158         new_attr.sa_vattr.va_type = VDIR;
 159         new_attr.sa_vattr.va_mode = 0777;
 160         new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
 161 
 162         rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp,
 163             &new_attr, &fqi->fq_fnode);
 164         if (rc != 0) {
 165                 smb_node_release(fqi->fq_dnode);
 166                 return (rc);
 167         }
 168 
 169         sr->arg.open.create_options = FILE_DIRECTORY_FILE;
 170 
 171         smb_node_release(fqi->fq_dnode);
 172         smb_node_release(fqi->fq_fnode);
 173         return (0);
 174 }
 175 
 176 /*
 177  * The delete directory message is sent to delete an empty directory. The
 178  * appropriate Tid and additional pathname are passed. The directory must
 179  * be empty for it to be deleted.
 180  *
 181  * NT supports a hidden permission known as File Delete Child (FDC). If
 182  * the user has FullControl access to a directory, the user is permitted
 183  * to delete any object in the directory regardless of the permissions
 184  * on the object.
 185  *
 186  * Client Request                     Description
 187  * ================================== =================================
 188  * UCHAR WordCount;                   Count of parameter words = 0
 189  * USHORT ByteCount;                  Count of data bytes; min = 2
 190  * UCHAR BufferFormat;                0x04
 191  * STRING DirectoryName[];            Directory name
 192  *
 193  * The directory to be deleted cannot be the root of the share specified
 194  * by Tid.
 195  *
 196  * Server Response                    Description
 197  * ================================== =================================
 198  * UCHAR WordCount;                   Count of parameter words = 0
 199  * USHORT ByteCount;                  Count of data bytes = 0
 200  */
 201 smb_sdrc_t
 202 smb_pre_delete_directory(smb_request_t *sr)
 203 {
 204         int rc;
 205 
 206         rc = smbsr_decode_data(sr, "%S", sr,
 207             &sr->arg.dirop.fqi.fq_path.pn_path);
 208 
 209         DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr,
 210             struct dirop *, &sr->arg.dirop);
 211 
 212         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 213 }
 214 
 215 void
 216 smb_post_delete_directory(smb_request_t *sr)
 217 {
 218         DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr);
 219 }
 220 
 221 smb_sdrc_t
 222 smb_com_delete_directory(smb_request_t *sr)
 223 {
 224         int rc;
 225         uint32_t flags = 0;
 226         smb_fqi_t *fqi;
 227         smb_node_t *tnode;
 228 
 229         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 230                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 231                     ERRDOS, ERROR_ACCESS_DENIED);
 232                 return (SDRC_ERROR);
 233         }
 234 
 235         fqi = &sr->arg.dirop.fqi;
 236         tnode = sr->tid_tree->t_snode;
 237 
 238         smb_pathname_init(sr, &fqi->fq_path, fqi->fq_path.pn_path);
 239         if (!smb_pathname_validate(sr, &fqi->fq_path) ||
 240             !smb_validate_dirname(sr, &fqi->fq_path)) {
 241                 return (SDRC_ERROR);
 242         }
 243 
 244         rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
 245             tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
 246 
 247         if (rc != 0) {
 248                 smbsr_errno(sr, rc);
 249                 return (SDRC_ERROR);
 250         }
 251 
 252         rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 253             tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
 254         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);
 260                 smb_node_release(fqi->fq_dnode);
 261                 return (SDRC_ERROR);
 262         }
 263 
 264         /*
 265          * Delete should fail if this is the root of a share
 266          * or a DFS link
 267          */
 268         if ((fqi->fq_fnode == tnode) || smb_node_is_dfslink(fqi->fq_fnode)) {
 269                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 270                     ERRDOS, ERROR_ACCESS_DENIED);
 271                 smb_node_release(fqi->fq_dnode);
 272                 smb_node_release(fqi->fq_fnode);
 273                 return (SDRC_ERROR);
 274         }
 275 
 276         if (!smb_node_is_dir(fqi->fq_fnode)) {
 277                 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
 278                     ERRDOS, ERROR_PATH_NOT_FOUND);
 279                 smb_node_release(fqi->fq_dnode);
 280                 smb_node_release(fqi->fq_fnode);
 281                 return (SDRC_ERROR);
 282         }
 283 
 284         /*
 285          * Using kcred because we just want the DOS attrs
 286          * and don't want access errors for this.
 287          */
 288         fqi->fq_fattr.sa_mask = SMB_AT_DOSATTR;
 289         rc = smb_node_getattr(sr, fqi->fq_fnode, zone_kcred(), NULL,
 290             &fqi->fq_fattr);
 291         if (rc != 0) {
 292                 smbsr_errno(sr, rc);
 293                 smb_node_release(fqi->fq_dnode);
 294                 smb_node_release(fqi->fq_fnode);
 295                 return (SDRC_ERROR);
 296         }
 297 
 298         if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
 299             (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
 300             != NT_STATUS_SUCCESS)) {
 301                 smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
 302                     ERRDOS, ERROR_ACCESS_DENIED);
 303                 smb_node_release(fqi->fq_dnode);
 304                 smb_node_release(fqi->fq_fnode);
 305                 return (SDRC_ERROR);
 306         }
 307 
 308         if (SMB_TREE_SUPPORTS_CATIA(sr))
 309                 flags |= SMB_CATIA;
 310 
 311         rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
 312             fqi->fq_fnode->od_name, flags);
 313 
 314         smb_node_release(fqi->fq_fnode);
 315         smb_node_release(fqi->fq_dnode);
 316 
 317         if (rc != 0) {
 318                 if (rc == EEXIST)
 319                         smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
 320                             ERRDOS, ERROR_DIR_NOT_EMPTY);
 321                 else
 322                         smbsr_errno(sr, rc);
 323                 return (SDRC_ERROR);
 324         }
 325 
 326         rc = smbsr_encode_empty_result(sr);
 327         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 328 }
 329 
 330 /*
 331  * This SMB is used to verify that a path exists and is a directory.  No
 332  * error is returned if the given path exists and the client has read
 333  * access to it.  Client machines which maintain a concept of a "working
 334  * directory" will find this useful to verify the validity of a "change
 335  * working directory" command.  Note that the servers do NOT have a concept
 336  * of working directory for a particular client.  The client must always
 337  * supply full pathnames relative to the Tid in the SMB header.
 338  *
 339  * Client Request                     Description
 340  * ================================== =================================
 341  *
 342  * UCHAR WordCount;                   Count of parameter words = 0
 343  * USHORT ByteCount;                  Count of data bytes;    min = 2
 344  * UCHAR BufferFormat;                0x04
 345  * STRING DirectoryPath[];            Directory path
 346  *
 347  * Server Response                    Description
 348  * ================================== =================================
 349  *
 350  * UCHAR WordCount;                   Count of parameter words = 0
 351  * USHORT ByteCount;                  Count of data bytes = 0
 352  *
 353  * DOS clients, in particular, depend on ERRbadpath if the directory is
 354  * not found.
 355  */
 356 smb_sdrc_t
 357 smb_pre_check_directory(smb_request_t *sr)
 358 {
 359         int rc;
 360 
 361         rc = smbsr_decode_data(sr, "%S", sr,
 362             &sr->arg.dirop.fqi.fq_path.pn_path);
 363 
 364         DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr,
 365             struct dirop *, &sr->arg.dirop);
 366 
 367         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 368 }
 369 
 370 void
 371 smb_post_check_directory(smb_request_t *sr)
 372 {
 373         DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr);
 374 }
 375 
 376 smb_sdrc_t
 377 smb_com_check_directory(smb_request_t *sr)
 378 {
 379         int rc;
 380         smb_fqi_t *fqi;
 381         smb_node_t *tnode;
 382         smb_node_t *node;
 383         char *path;
 384         smb_pathname_t *pn;
 385 
 386         if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
 387                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
 388                     ERROR_ACCESS_DENIED);
 389                 return (SDRC_ERROR);
 390         }
 391 
 392         fqi = &sr->arg.dirop.fqi;
 393         pn = &fqi->fq_path;
 394 
 395         if (pn->pn_path[0] == '\0') {
 396                 rc = smbsr_encode_empty_result(sr);
 397                 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 398         }
 399 
 400         smb_pathname_init(sr, pn, pn->pn_path);
 401         if (!smb_pathname_validate(sr, pn) ||
 402             !smb_validate_dirname(sr, pn)) {
 403                 return (SDRC_ERROR);
 404         }
 405 
 406         path = pn->pn_path;
 407         tnode = sr->tid_tree->t_snode;
 408 
 409         rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 410             &fqi->fq_dnode, fqi->fq_last_comp);
 411         if (rc != 0) {
 412                 smbsr_errno(sr, rc);
 413                 return (SDRC_ERROR);
 414         }
 415 
 416         rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 417             tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
 418         smb_node_release(fqi->fq_dnode);
 419         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);
 425                 return (SDRC_ERROR);
 426         }
 427 
 428         node = fqi->fq_fnode;
 429         if (!smb_node_is_dir(node)) {
 430                 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
 431                     ERRDOS, ERROR_PATH_NOT_FOUND);
 432                 smb_node_release(node);
 433                 return (SDRC_ERROR);
 434         }
 435 
 436         if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
 437                 smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
 438                 smb_node_release(node);
 439                 return (SDRC_ERROR);
 440         }
 441 
 442         rc = smb_fsop_access(sr, sr->user_cr, node, FILE_TRAVERSE);
 443 
 444         smb_node_release(node);
 445 
 446         if (rc != 0) {
 447                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 448                     ERRDOS, ERROR_ACCESS_DENIED);
 449                 return (SDRC_ERROR);
 450         }
 451 
 452         rc = smbsr_encode_empty_result(sr);
 453         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 454 }