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