xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_cmn_setfile.c (revision b62fa64bd1b93f15d05f01b9f01842071f059a30)
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