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-2023 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) { 82 if ((int64_t)atime < -2) 83 return (NT_STATUS_INVALID_PARAMETER); 84 85 smb_time_nt_to_unix(atime, &attr->sa_vattr.va_atime); 86 attr->sa_mask |= SMB_AT_ATIME; 87 } 88 if (mtime != 0) { 89 if ((int64_t)mtime < -2) 90 return (NT_STATUS_INVALID_PARAMETER); 91 92 smb_time_nt_to_unix(mtime, &attr->sa_vattr.va_mtime); 93 attr->sa_mask |= SMB_AT_MTIME; 94 } 95 if (ctime != 0) { 96 if ((int64_t)ctime < -2) 97 return (NT_STATUS_INVALID_PARAMETER); 98 99 smb_time_nt_to_unix(ctime, &attr->sa_vattr.va_ctime); 100 attr->sa_mask |= SMB_AT_CTIME; 101 } 102 if (crtime != 0) { 103 if ((int64_t)crtime < -2) 104 return (NT_STATUS_INVALID_PARAMETER); 105 106 smb_time_nt_to_unix(crtime, &attr->sa_crtime); 107 attr->sa_mask |= SMB_AT_CRTIME; 108 } 109 110 if (attributes != 0) { 111 attr->sa_dosattr = attributes; 112 attr->sa_mask |= SMB_AT_DOSATTR; 113 } 114 115 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr); 116 if (rc != 0) 117 return (smb_errno2status(rc)); 118 119 return (0); 120 } 121 122 /* 123 * smb_set_eof_info 124 * FileEndOfFileInformation 125 * SMB_SET_FILE_END_OF_FILE_INFO 126 * SMB_FILE_END_OF_FILE_INFORMATION 127 */ 128 uint32_t 129 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *si) 130 { 131 smb_attr_t *attr = &si->si_attr; 132 smb_node_t *node = si->si_node; 133 uint64_t eof; 134 uint32_t status; 135 int rc; 136 137 if (smb_mbc_decodef(&si->si_data, "q", &eof) != 0) 138 return (NT_STATUS_INFO_LENGTH_MISMATCH); 139 140 if (smb_node_is_dir(node)) 141 return (NT_STATUS_INVALID_PARAMETER); 142 143 status = smb_oplock_break_SETINFO(node, sr->fid_ofile, 144 FileEndOfFileInformation); 145 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 146 if (sr->session->dialect >= SMB_VERS_2_BASE) 147 (void) smb2sr_go_async(sr); 148 (void) smb_oplock_wait_break(sr, node, 0); 149 status = 0; 150 } 151 if (status != 0) 152 return (status); 153 154 bzero(attr, sizeof (*attr)); 155 attr->sa_mask = SMB_AT_SIZE; 156 attr->sa_vattr.va_size = (u_offset_t)eof; 157 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr); 158 if (rc != 0) 159 return (smb_errno2status(rc)); 160 161 return (0); 162 } 163 164 /* 165 * smb_set_alloc_info 166 * FileAllocationInformation 167 * SMB_SET_FILE_ALLOCATION_INFO 168 * SMB_FILE_ALLOCATION_INFORMATION 169 */ 170 uint32_t 171 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *si) 172 { 173 smb_attr_t *attr = &si->si_attr; 174 smb_node_t *node = si->si_node; 175 uint64_t allocsz; 176 uint32_t status; 177 int rc; 178 179 if (smb_mbc_decodef(&si->si_data, "q", &allocsz) != 0) 180 return (NT_STATUS_INFO_LENGTH_MISMATCH); 181 182 if (smb_node_is_dir(node)) 183 return (NT_STATUS_INVALID_PARAMETER); 184 185 status = smb_oplock_break_SETINFO(node, sr->fid_ofile, 186 FileAllocationInformation); 187 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 188 if (sr->session->dialect >= SMB_VERS_2_BASE) 189 (void) smb2sr_go_async(sr); 190 (void) smb_oplock_wait_break(sr, node, 0); 191 status = 0; 192 } 193 if (status != 0) 194 return (status); 195 196 bzero(attr, sizeof (*attr)); 197 attr->sa_mask = SMB_AT_ALLOCSZ; 198 attr->sa_allocsz = (u_offset_t)allocsz; 199 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr); 200 if (rc != 0) 201 return (smb_errno2status(rc)); 202 203 return (0); 204 } 205 206 /* 207 * smb_set_disposition_info 208 * See: 209 * FileDispositionInformation 210 * SMB_SET_FILE_DISPOSITION_INFO 211 * SMB_FILE_DISPOSITION_INFORMATION 212 * 213 * Set/Clear DELETE_ON_CLOSE flag for an open file. 214 * File should have been opened with DELETE access otherwise 215 * the operation is not permitted. 216 * 217 * NOTE: The node should be marked delete-on-close upon the receipt 218 * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set. 219 * It is different than both SmbNtCreateAndX and SmbNtTransact, which 220 * set delete-on-close on the ofile and defer setting the flag on the 221 * node until the file is closed. 222 * 223 * Observation of Windows 2000 indicates the following: 224 * 225 * 1) If a file is not opened with delete-on-close create options and 226 * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo) 227 * using that open file handle, any subsequent open requests will fail 228 * with DELETE_PENDING. 229 * 230 * 2) If a file is opened with delete-on-close create options and the 231 * client attempts to unset delete-on-close via Trans2SetFileInfo 232 * (SetDispositionInfo) prior to the file close, any subsequent open 233 * requests will still fail with DELETE_PENDING after the file is closed. 234 * 235 * 3) If a file is opened with delete-on-close create options and that 236 * file handle (not the last open handle and the only file handle 237 * with delete-on-close set) is closed. Any subsequent open requests 238 * will fail with DELETE_PENDING. Unsetting delete-on-close via 239 * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the 240 * node delete-on-close flag, which will result in the file not being 241 * removed even after the last file handle is closed. 242 */ 243 uint32_t 244 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *si) 245 { 246 smb_attr_t *attr = &si->si_attr; 247 smb_node_t *node = si->si_node; 248 smb_ofile_t *of = sr->fid_ofile; 249 uint8_t mark_delete; 250 uint32_t status; 251 uint32_t flags = 0; 252 253 if (smb_mbc_decodef(&si->si_data, "b", &mark_delete) != 0) 254 return (NT_STATUS_INFO_LENGTH_MISMATCH); 255 256 if ((of == NULL) || !(smb_ofile_granted_access(of) & DELETE)) 257 return (NT_STATUS_ACCESS_DENIED); 258 259 if (mark_delete == 0) { 260 smb_node_reset_delete_on_close(node); 261 return (NT_STATUS_SUCCESS); 262 } 263 264 /* 265 * MS-FSA 2.1.5.14.3 FileDispositionInformation 266 * If dosattr READONLY, STATUS_CANNOT_DELETE. 267 */ 268 attr->sa_mask = SMB_AT_DOSATTR; 269 status = smb2_ofile_getattr(sr, of, attr); 270 if (status != 0) 271 return (status); 272 if ((attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0) 273 return (NT_STATUS_CANNOT_DELETE); 274 275 /* 276 * Break any oplock handle caching. 277 */ 278 status = smb_oplock_break_SETINFO(node, of, 279 FileDispositionInformation); 280 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 281 if (sr->session->dialect >= SMB_VERS_2_BASE) 282 (void) smb2sr_go_async(sr); 283 (void) smb_oplock_wait_break(sr, node, 0); 284 status = 0; 285 } 286 if (status != 0) 287 return (status); 288 289 if (SMB_TREE_SUPPORTS_CATIA(sr)) 290 flags |= SMB_CATIA; 291 292 return (smb_node_set_delete_on_close(node, of->f_cr, flags)); 293 } 294