1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross * CDDL HEADER START
3a90cf9f2SGordon Ross *
4a90cf9f2SGordon Ross * The contents of this file are subject to the terms of the
5a90cf9f2SGordon Ross * Common Development and Distribution License (the "License").
6a90cf9f2SGordon Ross * You may not use this file except in compliance with the License.
7a90cf9f2SGordon Ross *
8a90cf9f2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a90cf9f2SGordon Ross * or http://www.opensolaris.org/os/licensing.
10a90cf9f2SGordon Ross * See the License for the specific language governing permissions
11a90cf9f2SGordon Ross * and limitations under the License.
12a90cf9f2SGordon Ross *
13a90cf9f2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14a90cf9f2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a90cf9f2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16a90cf9f2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17a90cf9f2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18a90cf9f2SGordon Ross *
19a90cf9f2SGordon Ross * CDDL HEADER END
20a90cf9f2SGordon Ross */
21a90cf9f2SGordon Ross /*
22a90cf9f2SGordon Ross * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23525641e8SGordon Ross * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
24*b62fa64bSToomas Soome * Copyright 2022-2023 RackTop Systems, Inc.
25a90cf9f2SGordon Ross */
26a90cf9f2SGordon Ross
27a90cf9f2SGordon Ross /*
28a90cf9f2SGordon Ross * Common functions supporting both:
29a90cf9f2SGordon Ross * SMB1 Trans2 Set File/Path Info,
30a90cf9f2SGordon Ross * SMB2 Set File Info
31a90cf9f2SGordon Ross */
32a90cf9f2SGordon Ross
3394047d49SGordon Ross #include <smbsrv/smb2_kproto.h>
34a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h>
35a90cf9f2SGordon Ross
36a90cf9f2SGordon Ross /*
37a90cf9f2SGordon Ross * smb_set_basic_info
38a90cf9f2SGordon Ross * [MS-FSCC] 2.4.7
39a90cf9f2SGordon Ross * FileBasicInformation
40a90cf9f2SGordon Ross * SMB_SET_FILE_BASIC_INFO
41a90cf9f2SGordon Ross * SMB_FILE_BASIC_INFORMATION
42a90cf9f2SGordon Ross *
43a90cf9f2SGordon Ross * Sets basic file/path information.
44a90cf9f2SGordon Ross *
45a90cf9f2SGordon Ross * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
46a90cf9f2SGordon Ross * target is not a directory.
47a90cf9f2SGordon Ross *
48a90cf9f2SGordon Ross * For compatibility with windows servers:
49a90cf9f2SGordon Ross * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
50a90cf9f2SGordon Ross * clear (0) the file's attributes.
51a90cf9f2SGordon Ross * - if the specified attributes are 0 do NOT change the file's attributes.
52a90cf9f2SGordon Ross */
53a90cf9f2SGordon Ross uint32_t
smb_set_basic_info(smb_request_t * sr,smb_setinfo_t * si)54a90cf9f2SGordon Ross smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *si)
55a90cf9f2SGordon Ross {
56a90cf9f2SGordon Ross smb_attr_t *attr = &si->si_attr;
57a90cf9f2SGordon Ross smb_node_t *node = si->si_node;
58a90cf9f2SGordon Ross uint64_t crtime, atime, mtime, ctime;
59a90cf9f2SGordon Ross uint32_t attributes;
60a90cf9f2SGordon Ross int rc;
61a90cf9f2SGordon Ross
62a90cf9f2SGordon Ross if (smb_mbc_decodef(&si->si_data, "qqqql",
63a90cf9f2SGordon Ross &crtime, &atime, &mtime, &ctime, &attributes) != 0)
64a90cf9f2SGordon Ross return (NT_STATUS_INFO_LENGTH_MISMATCH);
65a90cf9f2SGordon Ross
660cab3dcdSGordon Ross /*
670cab3dcdSGordon Ross * MS-FSA 2.1.5.14.2 FileBasicInformation
680cab3dcdSGordon Ross * Return STATUS_INVALID_PARAMETER if:
690cab3dcdSGordon Ross * FILE_ATTRIBUTE_TEMPORARY on a directory,
700cab3dcdSGordon Ross * FILE_ATTRIBUTE_DIRECTORY on a non-directory.
710cab3dcdSGordon Ross */
720cab3dcdSGordon Ross if (smb_node_is_dir(node)) {
730cab3dcdSGordon Ross if ((attributes & FILE_ATTRIBUTE_TEMPORARY) != 0)
74a90cf9f2SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
750cab3dcdSGordon Ross } else {
760cab3dcdSGordon Ross if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
770cab3dcdSGordon Ross return (NT_STATUS_INVALID_PARAMETER);
780cab3dcdSGordon Ross }
79a90cf9f2SGordon Ross
80a90cf9f2SGordon Ross bzero(attr, sizeof (*attr));
81*b62fa64bSToomas Soome if (atime != 0) {
82*b62fa64bSToomas Soome if ((int64_t)atime < -2)
83*b62fa64bSToomas Soome return (NT_STATUS_INVALID_PARAMETER);
84*b62fa64bSToomas Soome
85a90cf9f2SGordon Ross smb_time_nt_to_unix(atime, &attr->sa_vattr.va_atime);
86a90cf9f2SGordon Ross attr->sa_mask |= SMB_AT_ATIME;
87a90cf9f2SGordon Ross }
88*b62fa64bSToomas Soome if (mtime != 0) {
89*b62fa64bSToomas Soome if ((int64_t)mtime < -2)
90*b62fa64bSToomas Soome return (NT_STATUS_INVALID_PARAMETER);
91*b62fa64bSToomas Soome
92a90cf9f2SGordon Ross smb_time_nt_to_unix(mtime, &attr->sa_vattr.va_mtime);
93a90cf9f2SGordon Ross attr->sa_mask |= SMB_AT_MTIME;
94a90cf9f2SGordon Ross }
95*b62fa64bSToomas Soome if (ctime != 0) {
96*b62fa64bSToomas Soome if ((int64_t)ctime < -2)
97*b62fa64bSToomas Soome return (NT_STATUS_INVALID_PARAMETER);
98*b62fa64bSToomas Soome
99a90cf9f2SGordon Ross smb_time_nt_to_unix(ctime, &attr->sa_vattr.va_ctime);
100a90cf9f2SGordon Ross attr->sa_mask |= SMB_AT_CTIME;
101a90cf9f2SGordon Ross }
102*b62fa64bSToomas Soome if (crtime != 0) {
103*b62fa64bSToomas Soome if ((int64_t)crtime < -2)
104*b62fa64bSToomas Soome return (NT_STATUS_INVALID_PARAMETER);
105*b62fa64bSToomas Soome
106a90cf9f2SGordon Ross smb_time_nt_to_unix(crtime, &attr->sa_crtime);
107a90cf9f2SGordon Ross attr->sa_mask |= SMB_AT_CRTIME;
108a90cf9f2SGordon Ross }
109a90cf9f2SGordon Ross
110a90cf9f2SGordon Ross if (attributes != 0) {
111a90cf9f2SGordon Ross attr->sa_dosattr = attributes;
112a90cf9f2SGordon Ross attr->sa_mask |= SMB_AT_DOSATTR;
113a90cf9f2SGordon Ross }
114a90cf9f2SGordon Ross
115a90cf9f2SGordon Ross rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
116a90cf9f2SGordon Ross if (rc != 0)
117a90cf9f2SGordon Ross return (smb_errno2status(rc));
118a90cf9f2SGordon Ross
119a90cf9f2SGordon Ross return (0);
120a90cf9f2SGordon Ross }
121a90cf9f2SGordon Ross
122a90cf9f2SGordon Ross /*
123a90cf9f2SGordon Ross * smb_set_eof_info
124a90cf9f2SGordon Ross * FileEndOfFileInformation
125a90cf9f2SGordon Ross * SMB_SET_FILE_END_OF_FILE_INFO
126a90cf9f2SGordon Ross * SMB_FILE_END_OF_FILE_INFORMATION
127a90cf9f2SGordon Ross */
128a90cf9f2SGordon Ross uint32_t
smb_set_eof_info(smb_request_t * sr,smb_setinfo_t * si)129a90cf9f2SGordon Ross smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *si)
130a90cf9f2SGordon Ross {
131a90cf9f2SGordon Ross smb_attr_t *attr = &si->si_attr;
132a90cf9f2SGordon Ross smb_node_t *node = si->si_node;
133a90cf9f2SGordon Ross uint64_t eof;
13494047d49SGordon Ross uint32_t status;
135a90cf9f2SGordon Ross int rc;
136a90cf9f2SGordon Ross
137a90cf9f2SGordon Ross if (smb_mbc_decodef(&si->si_data, "q", &eof) != 0)
138a90cf9f2SGordon Ross return (NT_STATUS_INFO_LENGTH_MISMATCH);
139a90cf9f2SGordon Ross
140a90cf9f2SGordon Ross if (smb_node_is_dir(node))
141a90cf9f2SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
142a90cf9f2SGordon Ross
14394047d49SGordon Ross status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
14494047d49SGordon Ross FileEndOfFileInformation);
14594047d49SGordon Ross if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
14694047d49SGordon Ross if (sr->session->dialect >= SMB_VERS_2_BASE)
14794047d49SGordon Ross (void) smb2sr_go_async(sr);
148525641e8SGordon Ross (void) smb_oplock_wait_break(sr, node, 0);
14994047d49SGordon Ross status = 0;
15094047d49SGordon Ross }
15194047d49SGordon Ross if (status != 0)
15294047d49SGordon Ross return (status);
153a90cf9f2SGordon Ross
154a90cf9f2SGordon Ross bzero(attr, sizeof (*attr));
155a90cf9f2SGordon Ross attr->sa_mask = SMB_AT_SIZE;
156a90cf9f2SGordon Ross attr->sa_vattr.va_size = (u_offset_t)eof;
157a90cf9f2SGordon Ross rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
158a90cf9f2SGordon Ross if (rc != 0)
159a90cf9f2SGordon Ross return (smb_errno2status(rc));
160a90cf9f2SGordon Ross
161a90cf9f2SGordon Ross return (0);
162a90cf9f2SGordon Ross }
163a90cf9f2SGordon Ross
164a90cf9f2SGordon Ross /*
165a90cf9f2SGordon Ross * smb_set_alloc_info
166a90cf9f2SGordon Ross * FileAllocationInformation
167a90cf9f2SGordon Ross * SMB_SET_FILE_ALLOCATION_INFO
168a90cf9f2SGordon Ross * SMB_FILE_ALLOCATION_INFORMATION
169a90cf9f2SGordon Ross */
170a90cf9f2SGordon Ross uint32_t
smb_set_alloc_info(smb_request_t * sr,smb_setinfo_t * si)171a90cf9f2SGordon Ross smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *si)
172a90cf9f2SGordon Ross {
173a90cf9f2SGordon Ross smb_attr_t *attr = &si->si_attr;
174a90cf9f2SGordon Ross smb_node_t *node = si->si_node;
175a90cf9f2SGordon Ross uint64_t allocsz;
17694047d49SGordon Ross uint32_t status;
177a90cf9f2SGordon Ross int rc;
178a90cf9f2SGordon Ross
179a90cf9f2SGordon Ross if (smb_mbc_decodef(&si->si_data, "q", &allocsz) != 0)
180a90cf9f2SGordon Ross return (NT_STATUS_INFO_LENGTH_MISMATCH);
181a90cf9f2SGordon Ross
182a90cf9f2SGordon Ross if (smb_node_is_dir(node))
183a90cf9f2SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
184a90cf9f2SGordon Ross
18594047d49SGordon Ross status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
18694047d49SGordon Ross FileAllocationInformation);
18794047d49SGordon Ross if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
18894047d49SGordon Ross if (sr->session->dialect >= SMB_VERS_2_BASE)
18994047d49SGordon Ross (void) smb2sr_go_async(sr);
190525641e8SGordon Ross (void) smb_oplock_wait_break(sr, node, 0);
19194047d49SGordon Ross status = 0;
19294047d49SGordon Ross }
19394047d49SGordon Ross if (status != 0)
19494047d49SGordon Ross return (status);
195a90cf9f2SGordon Ross
196a90cf9f2SGordon Ross bzero(attr, sizeof (*attr));
197a90cf9f2SGordon Ross attr->sa_mask = SMB_AT_ALLOCSZ;
198a90cf9f2SGordon Ross attr->sa_allocsz = (u_offset_t)allocsz;
199a90cf9f2SGordon Ross rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
200a90cf9f2SGordon Ross if (rc != 0)
201a90cf9f2SGordon Ross return (smb_errno2status(rc));
202a90cf9f2SGordon Ross
203a90cf9f2SGordon Ross return (0);
204a90cf9f2SGordon Ross }
205a90cf9f2SGordon Ross
206a90cf9f2SGordon Ross /*
207a90cf9f2SGordon Ross * smb_set_disposition_info
208a90cf9f2SGordon Ross * See:
209a90cf9f2SGordon Ross * FileDispositionInformation
210a90cf9f2SGordon Ross * SMB_SET_FILE_DISPOSITION_INFO
211a90cf9f2SGordon Ross * SMB_FILE_DISPOSITION_INFORMATION
212a90cf9f2SGordon Ross *
213a90cf9f2SGordon Ross * Set/Clear DELETE_ON_CLOSE flag for an open file.
214a90cf9f2SGordon Ross * File should have been opened with DELETE access otherwise
215a90cf9f2SGordon Ross * the operation is not permitted.
216a90cf9f2SGordon Ross *
217a90cf9f2SGordon Ross * NOTE: The node should be marked delete-on-close upon the receipt
218a90cf9f2SGordon Ross * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
219a90cf9f2SGordon Ross * It is different than both SmbNtCreateAndX and SmbNtTransact, which
220a90cf9f2SGordon Ross * set delete-on-close on the ofile and defer setting the flag on the
221a90cf9f2SGordon Ross * node until the file is closed.
222a90cf9f2SGordon Ross *
223a90cf9f2SGordon Ross * Observation of Windows 2000 indicates the following:
224a90cf9f2SGordon Ross *
225a90cf9f2SGordon Ross * 1) If a file is not opened with delete-on-close create options and
226a90cf9f2SGordon Ross * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
227a90cf9f2SGordon Ross * using that open file handle, any subsequent open requests will fail
228a90cf9f2SGordon Ross * with DELETE_PENDING.
229a90cf9f2SGordon Ross *
230a90cf9f2SGordon Ross * 2) If a file is opened with delete-on-close create options and the
231a90cf9f2SGordon Ross * client attempts to unset delete-on-close via Trans2SetFileInfo
232a90cf9f2SGordon Ross * (SetDispositionInfo) prior to the file close, any subsequent open
233a90cf9f2SGordon Ross * requests will still fail with DELETE_PENDING after the file is closed.
234a90cf9f2SGordon Ross *
235a90cf9f2SGordon Ross * 3) If a file is opened with delete-on-close create options and that
236a90cf9f2SGordon Ross * file handle (not the last open handle and the only file handle
237a90cf9f2SGordon Ross * with delete-on-close set) is closed. Any subsequent open requests
238a90cf9f2SGordon Ross * will fail with DELETE_PENDING. Unsetting delete-on-close via
239a90cf9f2SGordon Ross * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
240a90cf9f2SGordon Ross * node delete-on-close flag, which will result in the file not being
241a90cf9f2SGordon Ross * removed even after the last file handle is closed.
242a90cf9f2SGordon Ross */
243a90cf9f2SGordon Ross uint32_t
smb_set_disposition_info(smb_request_t * sr,smb_setinfo_t * si)244a90cf9f2SGordon Ross smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *si)
245a90cf9f2SGordon Ross {
246abd30308SGordon Ross smb_attr_t *attr = &si->si_attr;
247a90cf9f2SGordon Ross smb_node_t *node = si->si_node;
248a90cf9f2SGordon Ross smb_ofile_t *of = sr->fid_ofile;
249a90cf9f2SGordon Ross uint8_t mark_delete;
25094047d49SGordon Ross uint32_t status;
251a90cf9f2SGordon Ross uint32_t flags = 0;
252a90cf9f2SGordon Ross
253a90cf9f2SGordon Ross if (smb_mbc_decodef(&si->si_data, "b", &mark_delete) != 0)
254a90cf9f2SGordon Ross return (NT_STATUS_INFO_LENGTH_MISMATCH);
255a90cf9f2SGordon Ross
256a90cf9f2SGordon Ross if ((of == NULL) || !(smb_ofile_granted_access(of) & DELETE))
257a90cf9f2SGordon Ross return (NT_STATUS_ACCESS_DENIED);
258a90cf9f2SGordon Ross
25994047d49SGordon Ross if (mark_delete == 0) {
260a90cf9f2SGordon Ross smb_node_reset_delete_on_close(node);
26194047d49SGordon Ross return (NT_STATUS_SUCCESS);
262a90cf9f2SGordon Ross }
263a90cf9f2SGordon Ross
26494047d49SGordon Ross /*
265abd30308SGordon Ross * MS-FSA 2.1.5.14.3 FileDispositionInformation
266abd30308SGordon Ross * If dosattr READONLY, STATUS_CANNOT_DELETE.
267abd30308SGordon Ross */
268abd30308SGordon Ross attr->sa_mask = SMB_AT_DOSATTR;
269abd30308SGordon Ross status = smb2_ofile_getattr(sr, of, attr);
270abd30308SGordon Ross if (status != 0)
271abd30308SGordon Ross return (status);
272abd30308SGordon Ross if ((attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0)
273abd30308SGordon Ross return (NT_STATUS_CANNOT_DELETE);
274abd30308SGordon Ross
275abd30308SGordon Ross /*
27694047d49SGordon Ross * Break any oplock handle caching.
27794047d49SGordon Ross */
27894047d49SGordon Ross status = smb_oplock_break_SETINFO(node, of,
27994047d49SGordon Ross FileDispositionInformation);
28094047d49SGordon Ross if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
28194047d49SGordon Ross if (sr->session->dialect >= SMB_VERS_2_BASE)
28294047d49SGordon Ross (void) smb2sr_go_async(sr);
283525641e8SGordon Ross (void) smb_oplock_wait_break(sr, node, 0);
28494047d49SGordon Ross status = 0;
28594047d49SGordon Ross }
28694047d49SGordon Ross if (status != 0)
28794047d49SGordon Ross return (status);
28894047d49SGordon Ross
28994047d49SGordon Ross if (SMB_TREE_SUPPORTS_CATIA(sr))
29094047d49SGordon Ross flags |= SMB_CATIA;
29194047d49SGordon Ross
29294047d49SGordon Ross return (smb_node_set_delete_on_close(node, of->f_cr, flags));
293a90cf9f2SGordon Ross }
294