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
27static uint32_t smb2_setf_rename(smb_request_t *, smb_setinfo_t *);
28static uint32_t smb2_setf_link(smb_request_t *, smb_setinfo_t *);
29
30static uint32_t smb2_setf_seek(smb_request_t *, smb_setinfo_t *);
31static uint32_t smb2_setf_full_ea(smb_request_t *, smb_setinfo_t *);
32static uint32_t smb2_setf_mode(smb_request_t *, smb_setinfo_t *);
33
34static uint32_t smb2_setf_pipe(smb_request_t *, smb_setinfo_t *);
35static uint32_t smb2_setf_valid_len(smb_request_t *, smb_setinfo_t *);
36static uint32_t smb2_setf_shortname(smb_request_t *, smb_setinfo_t *);
37
38
39uint32_t
40smb2_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 */
112static uint32_t
113smb2_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 */
143static uint32_t
144smb2_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 */
175static uint32_t
176smb2_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 */
197static uint32_t
198smb2_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 */
210static uint32_t
211smb2_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 */
233static uint32_t
234smb2_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 */
271static uint32_t
272smb2_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 */
297static uint32_t
298smb2_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