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
smb_set_basic_info(smb_request_t * sr,smb_setinfo_t * si)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
smb_set_eof_info(smb_request_t * sr,smb_setinfo_t * si)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
smb_set_alloc_info(smb_request_t * sr,smb_setinfo_t * si)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
smb_set_disposition_info(smb_request_t * sr,smb_setinfo_t * si)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