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
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 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
smb2_setf_rename(smb_request_t * sr,smb_setinfo_t * si)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
smb2_setf_link(smb_request_t * sr,smb_setinfo_t * si)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
smb2_setf_seek(smb_request_t * sr,smb_setinfo_t * si)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
smb2_setf_full_ea(smb_request_t * sr,smb_setinfo_t * si)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
smb2_setf_mode(smb_request_t * sr,smb_setinfo_t * si)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
smb2_setf_pipe(smb_request_t * sr,smb_setinfo_t * si)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
smb2_setf_valid_len(smb_request_t * sr,smb_setinfo_t * si)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
smb2_setf_shortname(smb_request_t * sr,smb_setinfo_t * si)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