1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
14  */
15 
16 /*
17  * Dispatch function for SMB2_SET_INFO
18  *
19  * [MS-FSCC 2.4] If a file system does not support ...
20  * an Information Classs, NT_STATUS_INVALID_PARAMETER...
21  */
22 
23 #include <smbsrv/smb2_kproto.h>
24 #include <smbsrv/smb_fsops.h>
25 #include <smbsrv/ntifs.h>
26 
27 static uint32_t smb2_setf_rename(smb_request_t *, smb_setinfo_t *);
28 static uint32_t smb2_setf_link(smb_request_t *, smb_setinfo_t *);
29 
30 static uint32_t smb2_setf_seek(smb_request_t *, smb_setinfo_t *);
31 static uint32_t smb2_setf_full_ea(smb_request_t *, smb_setinfo_t *);
32 static uint32_t smb2_setf_mode(smb_request_t *, smb_setinfo_t *);
33 
34 static uint32_t smb2_setf_pipe(smb_request_t *, smb_setinfo_t *);
35 static uint32_t smb2_setf_valid_len(smb_request_t *, smb_setinfo_t *);
36 static uint32_t smb2_setf_shortname(smb_request_t *, smb_setinfo_t *);
37 
38 
39 uint32_t
smb2_setinfo_file(smb_request_t * sr,smb_setinfo_t * si,int InfoClass)40 smb2_setinfo_file(smb_request_t *sr, smb_setinfo_t *si, int InfoClass)
41 {
42 	smb_ofile_t *of = sr->fid_ofile;
43 	uint32_t status;
44 
45 	si->si_node = of->f_node;
46 
47 	/* Most info levels need a disk file */
48 	switch (of->f_ftype) {
49 	case SMB_FTYPE_DISK:
50 	case SMB_FTYPE_PRINTER:
51 		break;
52 	case SMB_FTYPE_BYTE_PIPE:
53 	case SMB_FTYPE_MESG_PIPE:
54 		if (InfoClass != FilePipeInformation)
55 			return (NT_STATUS_INVALID_PARAMETER);
56 		break;
57 	default:
58 		return (NT_STATUS_INTERNAL_ERROR);
59 		break;
60 	}
61 
62 	switch (InfoClass) {
63 	case FileBasicInformation:		/* 4 */
64 		status = smb_set_basic_info(sr, si);
65 		break;
66 	case FileRenameInformation:		/* 10 */
67 		status = smb2_setf_rename(sr, si);
68 		break;
69 	case FileLinkInformation:		/* 11 */
70 		status = smb2_setf_link(sr, si);
71 		break;
72 	case FileDispositionInformation:	/* 13 */
73 		status = smb_set_disposition_info(sr, si);
74 		break;
75 	case FilePositionInformation:		/* 14 */
76 		status = smb2_setf_seek(sr, si);
77 		break;
78 	case FileFullEaInformation:		/* 15 */
79 		status = smb2_setf_full_ea(sr, si);
80 		break;
81 	case FileModeInformation:		/* 16 */
82 		status = smb2_setf_mode(sr, si);
83 		break;
84 	case FileAllocationInformation:		/* 19 */
85 		status = smb_set_alloc_info(sr, si);
86 		break;
87 	case FileEndOfFileInformation:		/* 20 */
88 		status = smb_set_eof_info(sr, si);
89 		break;
90 	case FilePipeInformation:		/* 23 */
91 		status = smb2_setf_pipe(sr, si);
92 		break;
93 	case FileValidDataLengthInformation:	/* 39 */
94 		status = smb2_setf_valid_len(sr, si);
95 		break;
96 	case FileShortNameInformation:		/* 40 */
97 		status = smb2_setf_shortname(sr, si);
98 		break;
99 	default:
100 		status = NT_STATUS_INVALID_INFO_CLASS;
101 		break;
102 	}
103 
104 	return (status);
105 }
106 
107 
108 /*
109  * FileRenameInformation
110  * See also: smb_set_rename_info()
111  */
112 static uint32_t
smb2_setf_rename(smb_request_t * sr,smb_setinfo_t * si)113 smb2_setf_rename(smb_request_t *sr, smb_setinfo_t *si)
114 {
115 	char *fname;
116 	uint8_t flags;
117 	uint64_t rootdir;
118 	uint32_t namelen;
119 	uint32_t status = 0;
120 	int rc;
121 
122 	rc = smb_mbc_decodef(&si->si_data, "b7.ql",
123 	    &flags, &rootdir, &namelen);
124 	if (rc == 0) {
125 		rc = smb_mbc_decodef(&si->si_data, "%#U",
126 		    sr, namelen, &fname);
127 	}
128 	if (rc != 0)
129 		return (NT_STATUS_INFO_LENGTH_MISMATCH);
130 
131 	if ((rootdir != 0) || (namelen == 0) || (namelen >= SMB_MAXPATHLEN)) {
132 		return (NT_STATUS_INVALID_PARAMETER);
133 	}
134 
135 	status = smb_setinfo_rename(sr, si->si_node, fname, flags);
136 
137 	return (status);
138 }
139 
140 /*
141  * FileLinkInformation
142  */
143 static uint32_t
smb2_setf_link(smb_request_t * sr,smb_setinfo_t * si)144 smb2_setf_link(smb_request_t *sr, smb_setinfo_t *si)
145 {
146 	char *fname;
147 	uint8_t flags;
148 	uint64_t rootdir;
149 	uint32_t namelen;
150 	uint32_t status = 0;
151 	int rc;
152 
153 	rc = smb_mbc_decodef(&si->si_data, "b7.ql",
154 	    &flags, &rootdir, &namelen);
155 	if (rc == 0) {
156 		rc = smb_mbc_decodef(&si->si_data, "%#U",
157 		    sr, namelen, &fname);
158 	}
159 	if (rc != 0)
160 		return (NT_STATUS_INFO_LENGTH_MISMATCH);
161 
162 	if ((rootdir != 0) || (namelen == 0) || (namelen >= SMB_MAXPATHLEN)) {
163 		return (NT_STATUS_INVALID_PARAMETER);
164 	}
165 
166 	status = smb_setinfo_link(sr, si->si_node, fname, flags);
167 
168 	return (status);
169 }
170 
171 
172 /*
173  * FilePositionInformation
174  */
175 static uint32_t
smb2_setf_seek(smb_request_t * sr,smb_setinfo_t * si)176 smb2_setf_seek(smb_request_t *sr, smb_setinfo_t *si)
177 {
178 	smb_ofile_t *of = sr->fid_ofile;
179 	uint64_t newoff;
180 
181 	if (smb_mbc_decodef(&si->si_data, "q", &newoff) != 0)
182 		return (NT_STATUS_INVALID_PARAMETER);
183 
184 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
185 	mutex_enter(&of->f_mutex);
186 	of->f_seek_pos = newoff;
187 	mutex_exit(&of->f_mutex);
188 
189 	return (0);
190 }
191 
192 /*
193  * FileFullEaInformation
194  * We could put EAs in a named stream...
195  */
196 /* ARGSUSED */
197 static uint32_t
smb2_setf_full_ea(smb_request_t * sr,smb_setinfo_t * si)198 smb2_setf_full_ea(smb_request_t *sr, smb_setinfo_t *si)
199 {
200 	return (NT_STATUS_EAS_NOT_SUPPORTED);
201 }
202 
203 /*
204  * FileModeInformation [MS-FSCC 2.4.24]
205  *	FILE_WRITE_THROUGH
206  *	FILE_SEQUENTIAL_ONLY
207  *	FILE_NO_INTERMEDIATE_BUFFERING
208  *	etc.
209  */
210 static uint32_t
smb2_setf_mode(smb_request_t * sr,smb_setinfo_t * si)211 smb2_setf_mode(smb_request_t *sr, smb_setinfo_t *si)
212 {
213 	_NOTE(ARGUNUSED(sr))
214 	uint32_t	Mode;
215 
216 	if (smb_mbc_decodef(&si->si_data, "l", &Mode) != 0)
217 		return (NT_STATUS_INVALID_PARAMETER);
218 
219 #if 0	/* XXX - todo */
220 	if (Mode & FILE_WRITE_THROUGH) {
221 		/* store this in the ofile */
222 	}
223 #endif
224 
225 	return (NT_STATUS_SUCCESS);
226 }
227 
228 
229 
230 /*
231  * FilePipeInformation
232  */
233 static uint32_t
smb2_setf_pipe(smb_request_t * sr,smb_setinfo_t * si)234 smb2_setf_pipe(smb_request_t *sr, smb_setinfo_t *si)
235 {
236 	_NOTE(ARGUNUSED(si))
237 	smb_ofile_t *of = sr->fid_ofile;
238 	uint32_t	ReadMode;
239 	uint32_t	CompletionMode;
240 	uint32_t	status;
241 
242 	if (smb_mbc_decodef(&si->si_data, "ll",
243 	    &ReadMode, &CompletionMode) != 0)
244 		return (NT_STATUS_INFO_LENGTH_MISMATCH);
245 
246 	switch (of->f_ftype) {
247 	case SMB_FTYPE_BYTE_PIPE:
248 	case SMB_FTYPE_MESG_PIPE:
249 		/*
250 		 * XXX: Do we need to actually do anything with
251 		 * ReadMode or CompletionMode?  If so, (later)
252 		 * store these in the opipe object.
253 		 *
254 		 * See also: smb2_sif_pipe()
255 		 */
256 		status = 0;
257 		break;
258 	case SMB_FTYPE_DISK:
259 	case SMB_FTYPE_PRINTER:
260 	default:
261 		status = NT_STATUS_INVALID_PARAMETER;
262 	}
263 
264 	return (status);
265 }
266 
267 /*
268  * FileValidDataLengthInformation
269  */
270 /* ARGSUSED */
271 static uint32_t
smb2_setf_valid_len(smb_request_t * sr,smb_setinfo_t * si)272 smb2_setf_valid_len(smb_request_t *sr, smb_setinfo_t *si)
273 {
274 	smb_ofile_t *of = sr->fid_ofile;
275 	uint64_t eod;
276 	int rc;
277 
278 	if (smb_mbc_decodef(&si->si_data, "q", &eod) != 0)
279 		return (NT_STATUS_INFO_LENGTH_MISMATCH);
280 
281 	/*
282 	 * Zero out data from EoD to end of file.
283 	 * (Passing len=0 covers to end of file)
284 	 */
285 	rc = smb_fsop_freesp(sr, of->f_cr, of, eod, 0);
286 	if (rc != 0)
287 		return (smb_errno2status(rc));
288 
289 	return (0);
290 }
291 
292 /*
293  * FileShortNameInformation
294  *	We can (optionally) support supply short names,
295  *	but you can't change them.
296  */
297 static uint32_t
smb2_setf_shortname(smb_request_t * sr,smb_setinfo_t * si)298 smb2_setf_shortname(smb_request_t *sr, smb_setinfo_t *si)
299 {
300 	_NOTE(ARGUNUSED(si))
301 	smb_ofile_t *of = sr->fid_ofile;
302 
303 	if (of->f_ftype != SMB_FTYPE_DISK)
304 		return (NT_STATUS_INVALID_PARAMETER);
305 	if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
306 		return (NT_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME);
307 
308 	return (NT_STATUS_ACCESS_DENIED);
309 }
310