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