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