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