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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * Common functions supporting both:
  28  * SMB1 Trans2 Set File/Path Info,
  29  * SMB2 Set File Info
  30  */
  31 
  32 #include <smbsrv/smb2_kproto.h>
  33 #include <smbsrv/smb_fsops.h>
  34 
  35 /*
  36  * smb_set_basic_info
  37  * [MS-FSCC] 2.4.7
  38  *      FileBasicInformation
  39  *      SMB_SET_FILE_BASIC_INFO
  40  *      SMB_FILE_BASIC_INFORMATION
  41  *
  42  * Sets basic file/path information.
  43  *
  44  * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
  45  * target is not a directory.
  46  *
  47  * For compatibility with windows servers:
  48  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
  49  *   clear (0) the file's attributes.
  50  * - if the specified attributes are 0 do NOT change the file's attributes.
  51  */
  52 uint32_t
  53 smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *si)
  54 {
  55         smb_attr_t *attr = &si->si_attr;
  56         smb_node_t *node = si->si_node;
  57         uint64_t crtime, atime, mtime, ctime;
  58         uint32_t attributes;
  59         int rc;
  60 
  61         if (smb_mbc_decodef(&si->si_data, "qqqql",
  62             &crtime, &atime, &mtime, &ctime, &attributes) != 0)
  63                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
  64 
  65         if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
  66             (!smb_node_is_dir(node)))
  67                 return (NT_STATUS_INVALID_PARAMETER);
  68 
  69         bzero(attr, sizeof (*attr));
  70         if (atime != 0 && atime != (uint64_t)-1) {
  71                 smb_time_nt_to_unix(atime, &attr->sa_vattr.va_atime);
  72                 attr->sa_mask |= SMB_AT_ATIME;
  73         }
  74         if (mtime != 0 && mtime != (uint64_t)-1) {
  75                 smb_time_nt_to_unix(mtime, &attr->sa_vattr.va_mtime);
  76                 attr->sa_mask |= SMB_AT_MTIME;
  77         }
  78         if (ctime != 0 && ctime != (uint64_t)-1) {
  79                 smb_time_nt_to_unix(ctime, &attr->sa_vattr.va_ctime);
  80                 attr->sa_mask |= SMB_AT_CTIME;
  81         }
  82         if (crtime != 0 && crtime != (uint64_t)-1) {
  83                 smb_time_nt_to_unix(crtime, &attr->sa_crtime);
  84                 attr->sa_mask |= SMB_AT_CRTIME;
  85         }
  86 
  87         if (attributes != 0) {
  88                 attr->sa_dosattr = attributes;
  89                 attr->sa_mask |= SMB_AT_DOSATTR;
  90         }
  91 
  92         rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
  93         if (rc != 0)
  94                 return (smb_errno2status(rc));
  95 
  96         return (0);
  97 }
  98 
  99 /*
 100  * smb_set_eof_info
 101  *      FileEndOfFileInformation
 102  *      SMB_SET_FILE_END_OF_FILE_INFO
 103  *      SMB_FILE_END_OF_FILE_INFORMATION
 104  */
 105 uint32_t
 106 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *si)
 107 {
 108         smb_attr_t *attr = &si->si_attr;
 109         smb_node_t *node = si->si_node;
 110         uint64_t eof;
 111         uint32_t status;
 112         int rc;
 113 
 114         if (smb_mbc_decodef(&si->si_data, "q", &eof) != 0)
 115                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
 116 
 117         if (smb_node_is_dir(node))
 118                 return (NT_STATUS_INVALID_PARAMETER);
 119 
 120         status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
 121             FileEndOfFileInformation);
 122         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 123                 if (sr->session->dialect >= SMB_VERS_2_BASE)
 124                         (void) smb2sr_go_async(sr);
 125                 (void) smb_oplock_wait_break(node, 0);
 126                 status = 0;
 127         }
 128         if (status != 0)
 129                 return (status);
 130 
 131         bzero(attr, sizeof (*attr));
 132         attr->sa_mask = SMB_AT_SIZE;
 133         attr->sa_vattr.va_size = (u_offset_t)eof;
 134         rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
 135         if (rc != 0)
 136                 return (smb_errno2status(rc));
 137 
 138         return (0);
 139 }
 140 
 141 /*
 142  * smb_set_alloc_info
 143  *      FileAllocationInformation
 144  *      SMB_SET_FILE_ALLOCATION_INFO
 145  *      SMB_FILE_ALLOCATION_INFORMATION
 146  */
 147 uint32_t
 148 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *si)
 149 {
 150         smb_attr_t *attr = &si->si_attr;
 151         smb_node_t *node = si->si_node;
 152         uint64_t allocsz;
 153         uint32_t status;
 154         int rc;
 155 
 156         if (smb_mbc_decodef(&si->si_data, "q", &allocsz) != 0)
 157                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
 158 
 159         if (smb_node_is_dir(node))
 160                 return (NT_STATUS_INVALID_PARAMETER);
 161 
 162         status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
 163             FileAllocationInformation);
 164         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 165                 if (sr->session->dialect >= SMB_VERS_2_BASE)
 166                         (void) smb2sr_go_async(sr);
 167                 (void) smb_oplock_wait_break(node, 0);
 168                 status = 0;
 169         }
 170         if (status != 0)
 171                 return (status);
 172 
 173         bzero(attr, sizeof (*attr));
 174         attr->sa_mask = SMB_AT_ALLOCSZ;
 175         attr->sa_allocsz = (u_offset_t)allocsz;
 176         rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
 177         if (rc != 0)
 178                 return (smb_errno2status(rc));
 179 
 180         return (0);
 181 }
 182 
 183 /*
 184  * smb_set_disposition_info
 185  * See:
 186  *      FileDispositionInformation
 187  *      SMB_SET_FILE_DISPOSITION_INFO
 188  *      SMB_FILE_DISPOSITION_INFORMATION
 189  *
 190  * Set/Clear DELETE_ON_CLOSE flag for an open file.
 191  * File should have been opened with DELETE access otherwise
 192  * the operation is not permitted.
 193  *
 194  * NOTE: The node should be marked delete-on-close upon the receipt
 195  * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
 196  * It is different than both SmbNtCreateAndX and SmbNtTransact, which
 197  * set delete-on-close on the ofile and defer setting the flag on the
 198  * node until the file is closed.
 199  *
 200  * Observation of Windows 2000 indicates the following:
 201  *
 202  * 1) If a file is not opened with delete-on-close create options and
 203  * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
 204  * using that open file handle, any subsequent open requests will fail
 205  * with DELETE_PENDING.
 206  *
 207  * 2) If a file is opened with delete-on-close create options and the
 208  * client attempts to unset delete-on-close via Trans2SetFileInfo
 209  * (SetDispositionInfo) prior to the file close, any subsequent open
 210  * requests will still fail with DELETE_PENDING after the file is closed.
 211  *
 212  * 3) If a file is opened with delete-on-close create options and that
 213  * file handle (not the last open handle and the only file handle
 214  * with delete-on-close set) is closed. Any subsequent open requests
 215  * will fail with DELETE_PENDING. Unsetting delete-on-close via
 216  * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
 217  * node delete-on-close flag, which will result in the file not being
 218  * removed even after the last file handle is closed.
 219  */
 220 uint32_t
 221 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *si)
 222 {
 223         smb_node_t *node = si->si_node;
 224         smb_ofile_t *of = sr->fid_ofile;
 225         uint8_t         mark_delete;
 226         uint32_t        status;
 227         uint32_t        flags = 0;
 228 
 229         if (smb_mbc_decodef(&si->si_data, "b", &mark_delete) != 0)
 230                 return (NT_STATUS_INFO_LENGTH_MISMATCH);
 231 
 232         if ((of == NULL) || !(smb_ofile_granted_access(of) & DELETE))
 233                 return (NT_STATUS_ACCESS_DENIED);
 234 
 235         if (mark_delete == 0) {
 236                 smb_node_reset_delete_on_close(node);
 237                 return (NT_STATUS_SUCCESS);
 238         }
 239 
 240         /*
 241          * Break any oplock handle caching.
 242          */
 243         status = smb_oplock_break_SETINFO(node, of,
 244             FileDispositionInformation);
 245         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 246                 if (sr->session->dialect >= SMB_VERS_2_BASE)
 247                         (void) smb2sr_go_async(sr);
 248                 (void) smb_oplock_wait_break(node, 0);
 249                 status = 0;
 250         }
 251         if (status != 0)
 252                 return (status);
 253 
 254         if (SMB_TREE_SUPPORTS_CATIA(sr))
 255                 flags |= SMB_CATIA;
 256 
 257         return (smb_node_set_delete_on_close(node, of->f_cr, flags));
 258 }