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_QUERY_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_qif_all(smb_request_t *, smb_queryinfo_t *);
28 static uint32_t smb2_qif_basic(smb_request_t *, smb_queryinfo_t *);
29 static uint32_t smb2_qif_standard(smb_request_t *, smb_queryinfo_t *);
30 static uint32_t smb2_qif_internal(smb_request_t *, smb_queryinfo_t *);
31 static uint32_t smb2_qif_ea_size(smb_request_t *, smb_queryinfo_t *);
32 static uint32_t smb2_qif_access(smb_request_t *, smb_queryinfo_t *);
33 static uint32_t smb2_qif_name(smb_request_t *, smb_queryinfo_t *);
34 static uint32_t smb2_qif_position(smb_request_t *, smb_queryinfo_t *);
35 static uint32_t smb2_qif_full_ea(smb_request_t *, smb_queryinfo_t *);
36 static uint32_t smb2_qif_mode(smb_request_t *, smb_queryinfo_t *);
37 static uint32_t smb2_qif_alignment(smb_request_t *, smb_queryinfo_t *);
38 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *);
39 static uint32_t smb2_qif_altname(smb_request_t *, smb_queryinfo_t *);
40 static uint32_t smb2_qif_stream(smb_request_t *, smb_queryinfo_t *);
41 static uint32_t smb2_qif_pipe(smb_request_t *, smb_queryinfo_t *);
42 static uint32_t smb2_qif_pipe_lcl(smb_request_t *, smb_queryinfo_t *);
43 static uint32_t smb2_qif_pipe_rem(smb_request_t *, smb_queryinfo_t *);
44 static uint32_t smb2_qif_compr(smb_request_t *, smb_queryinfo_t *);
45 static uint32_t smb2_qif_opens(smb_request_t *, smb_queryinfo_t *);
46 static uint32_t smb2_qif_tags(smb_request_t *, smb_queryinfo_t *);
47
48
49 uint32_t
smb2_qinfo_file(smb_request_t * sr,smb_queryinfo_t * qi)50 smb2_qinfo_file(smb_request_t *sr, smb_queryinfo_t *qi)
51 {
52 smb_ofile_t *of = sr->fid_ofile;
53 uint_t mask = 0;
54 boolean_t getstd = B_FALSE;
55 boolean_t getname = B_FALSE;
56 uint32_t status;
57
58 /*
59 * Which attributes do we need from the FS?
60 */
61 switch (qi->qi_InfoClass) {
62 case FileBasicInformation:
63 mask = SMB_AT_BASIC;
64 break;
65 case FileStandardInformation:
66 mask = SMB_AT_STANDARD;
67 getstd = B_TRUE;
68 break;
69 case FileInternalInformation:
70 mask = SMB_AT_NODEID;
71 break;
72 case FileAllInformation:
73 mask = SMB_AT_ALL;
74 getstd = B_TRUE;
75 getname = B_TRUE;
76 break;
77
78 case FileNameInformation:
79 getname = B_TRUE;
80 break;
81
82 case FileAlternateNameInformation:
83 mask = SMB_AT_NODEID;
84 getname = B_TRUE;
85 break;
86
87 case FileStreamInformation:
88 mask = SMB_AT_STANDARD;
89 break;
90
91 case FileCompressionInformation:
92 mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ;
93 break;
94
95 case FileNetworkOpenInformation:
96 mask = SMB_AT_BASIC | SMB_AT_STANDARD;
97
98 default:
99 break;
100 }
101
102 qi->qi_attr.sa_mask = mask;
103 qi->qi_node = of->f_node;
104 if (mask & SMB_AT_ALL) {
105 status = smb2_ofile_getattr(sr, of, &qi->qi_attr);
106 if (status)
107 return (status);
108 }
109 if (getstd) {
110 status = smb2_ofile_getstd(of, qi);
111 if (status)
112 return (status);
113 }
114 if (getname) {
115 status = smb2_ofile_getname(of, qi);
116 if (status)
117 return (status);
118 }
119
120 switch (qi->qi_InfoClass) {
121 case FileBasicInformation:
122 status = smb2_qif_basic(sr, qi);
123 break;
124 case FileStandardInformation:
125 status = smb2_qif_standard(sr, qi);
126 break;
127 case FileInternalInformation:
128 status = smb2_qif_internal(sr, qi);
129 break;
130 case FileEaInformation:
131 status = smb2_qif_ea_size(sr, qi);
132 break;
133 case FileAccessInformation:
134 status = smb2_qif_access(sr, qi);
135 break;
136 case FileNameInformation:
137 status = smb2_qif_name(sr, qi);
138 break;
139 case FilePositionInformation:
140 status = smb2_qif_position(sr, qi);
141 break;
142 case FileFullEaInformation:
143 status = smb2_qif_full_ea(sr, qi);
144 break;
145 case FileModeInformation:
146 status = smb2_qif_mode(sr, qi);
147 break;
148 case FileAlignmentInformation:
149 status = smb2_qif_alignment(sr, qi);
150 break;
151 case FileAllInformation:
152 status = smb2_qif_all(sr, qi);
153 break;
154 case FileAlternateNameInformation:
155 status = smb2_qif_altname(sr, qi);
156 break;
157 case FileStreamInformation:
158 status = smb2_qif_stream(sr, qi);
159 break;
160 case FilePipeInformation:
161 status = smb2_qif_pipe(sr, qi);
162 break;
163 case FilePipeLocalInformation:
164 status = smb2_qif_pipe_lcl(sr, qi);
165 break;
166 case FilePipeRemoteInformation:
167 status = smb2_qif_pipe_rem(sr, qi);
168 break;
169 case FileCompressionInformation:
170 status = smb2_qif_compr(sr, qi);
171 break;
172 case FileNetworkOpenInformation:
173 status = smb2_qif_opens(sr, qi);
174 break;
175 case FileAttributeTagInformation:
176 status = smb2_qif_tags(sr, qi);
177 break;
178 default:
179 status = NT_STATUS_INVALID_INFO_CLASS;
180 break;
181 }
182
183 return (status);
184 }
185
186 /*
187 * FileAllInformation
188 *
189 * This returns a concatenation of:
190 * FileBasicInformation
191 * FileStandardInformation
192 * FileInternalInformation
193 * FileEaInformation
194 * FilePositionInformation
195 * FileModeInformation
196 * FileAlignmentInformation
197 * FileNameInformation
198 */
199 static uint32_t
smb2_qif_all(smb_request_t * sr,smb_queryinfo_t * qi)200 smb2_qif_all(smb_request_t *sr, smb_queryinfo_t *qi)
201 {
202 uint32_t status;
203
204 status = smb2_qif_basic(sr, qi);
205 if (status)
206 return (status);
207 status = smb2_qif_standard(sr, qi);
208 if (status)
209 return (status);
210 status = smb2_qif_internal(sr, qi);
211 if (status)
212 return (status);
213 status = smb2_qif_ea_size(sr, qi);
214 if (status)
215 return (status);
216 status = smb2_qif_position(sr, qi);
217 if (status)
218 return (status);
219 status = smb2_qif_mode(sr, qi);
220 if (status)
221 return (status);
222 status = smb2_qif_alignment(sr, qi);
223 if (status)
224 return (status);
225 status = smb2_qif_name(sr, qi);
226 if (status)
227 return (status);
228
229 return (0);
230 }
231
232 /*
233 * FileBasicInformation
234 * See also:
235 * case SMB_QUERY_FILE_BASIC_INFO:
236 * case SMB_FILE_BASIC_INFORMATION:
237 */
238 static uint32_t
smb2_qif_basic(smb_request_t * sr,smb_queryinfo_t * qi)239 smb2_qif_basic(smb_request_t *sr, smb_queryinfo_t *qi)
240 {
241 smb_attr_t *sa = &qi->qi_attr;
242
243 ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC);
244
245 (void) smb_mbc_encodef(
246 &sr->raw_data, "TTTTll",
247 &sa->sa_crtime, /* T */
248 &sa->sa_vattr.va_atime, /* T */
249 &sa->sa_vattr.va_mtime, /* T */
250 &sa->sa_vattr.va_ctime, /* T */
251 sa->sa_dosattr, /* l */
252 0); /* reserved */ /* l */
253
254 return (0);
255 }
256
257 /*
258 * FileStandardInformation
259 * See also:
260 * SMB_QUERY_FILE_STANDARD_INFO
261 * SMB_FILE_STANDARD_INFORMATION
262 */
263 static uint32_t
smb2_qif_standard(smb_request_t * sr,smb_queryinfo_t * qi)264 smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi)
265 {
266 smb_attr_t *sa = &qi->qi_attr;
267
268 ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
269
270 (void) smb_mbc_encodef(
271 &sr->raw_data, "qqlbbw",
272 sa->sa_allocsz, /* q */
273 sa->sa_vattr.va_size, /* q */
274 sa->sa_vattr.va_nlink, /* l */
275 qi->qi_delete_on_close, /* b */
276 qi->qi_isdir, /* b */
277 0); /* reserved */ /* w */
278
279 return (0);
280 }
281
282 /*
283 * FileInternalInformation
284 * See also:
285 * SMB_FILE_INTERNAL_INFORMATION
286 */
287 static uint32_t
smb2_qif_internal(smb_request_t * sr,smb_queryinfo_t * qi)288 smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi)
289 {
290 smb_attr_t *sa = &qi->qi_attr;
291
292 ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID);
293
294 (void) smb_mbc_encodef(
295 &sr->raw_data, "q",
296 sa->sa_vattr.va_nodeid); /* q */
297
298 return (0);
299 }
300
301 /*
302 * FileEaInformation
303 * See also:
304 * SMB_QUERY_FILE_EA_INFO
305 * SMB_FILE_EA_INFORMATION
306 */
307 static uint32_t
smb2_qif_ea_size(smb_request_t * sr,smb_queryinfo_t * qi)308 smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi)
309 {
310 _NOTE(ARGUNUSED(qi))
311
312 (void) smb_mbc_encodef(
313 &sr->raw_data, "l", 0);
314
315 return (0);
316 }
317
318 /*
319 * FileFullEaInformation
320 * We could put EAs in a named stream...
321 */
322 /* ARGSUSED */
323 static uint32_t
smb2_qif_full_ea(smb_request_t * sr,smb_queryinfo_t * qi)324 smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi)
325 {
326 return (NT_STATUS_NO_EAS_ON_FILE);
327 }
328
329 /*
330 * FileAccessInformation
331 */
332 static uint32_t
smb2_qif_access(smb_request_t * sr,smb_queryinfo_t * qi)333 smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi)
334 {
335 _NOTE(ARGUNUSED(qi))
336 smb_ofile_t *of = sr->fid_ofile;
337
338 (void) smb_mbc_encodef(
339 &sr->raw_data, "l",
340 of->f_granted_access);
341
342 return (0);
343 }
344
345 /*
346 * FileNameInformation
347 * See also:
348 * SMB_QUERY_FILE_NAME_INFO
349 * SMB_FILE_NAME_INFORMATION
350 */
351 static uint32_t
smb2_qif_name(smb_request_t * sr,smb_queryinfo_t * qi)352 smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi)
353 {
354
355 ASSERT(qi->qi_namelen > 0);
356
357 (void) smb_mbc_encodef(
358 &sr->raw_data, "llU",
359 0, /* FileIndex (l) */
360 qi->qi_namelen, /* l */
361 qi->qi_name); /* U */
362
363 return (0);
364 }
365
366 /*
367 * FilePositionInformation
368 */
369 static uint32_t
smb2_qif_position(smb_request_t * sr,smb_queryinfo_t * qi)370 smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi)
371 {
372 _NOTE(ARGUNUSED(qi))
373 smb_ofile_t *of = sr->fid_ofile;
374 uint64_t pos;
375
376 mutex_enter(&of->f_mutex);
377 pos = of->f_seek_pos;
378 mutex_exit(&of->f_mutex);
379
380 (void) smb_mbc_encodef(
381 &sr->raw_data, "q", pos);
382
383 return (0);
384 }
385
386 /*
387 * FileModeInformation [MS-FSA 2.4.24]
388 * XXX: These mode flags are supposed to be on the open handle,
389 * XXX: or I think so. Not yet... (just put zero for now)
390 */
391 static uint32_t
smb2_qif_mode(smb_request_t * sr,smb_queryinfo_t * qi)392 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi)
393 {
394 _NOTE(ARGUNUSED(qi))
395
396 (void) smb_mbc_encodef(
397 &sr->raw_data, "l", 0);
398
399 return (0);
400 }
401
402 /*
403 * FileAlignmentInformation
404 */
405 static uint32_t
smb2_qif_alignment(smb_request_t * sr,smb_queryinfo_t * qi)406 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi)
407 {
408 _NOTE(ARGUNUSED(qi))
409
410 (void) smb_mbc_encodef(
411 &sr->raw_data, "l", 0);
412
413 return (0);
414 }
415
416 /*
417 * FileAlternateNameInformation
418 * See also:
419 * SMB_QUERY_FILE_ALT_NAME_INFO
420 * SMB_FILE_ALT_NAME_INFORMATION
421 */
422 static uint32_t
smb2_qif_altname(smb_request_t * sr,smb_queryinfo_t * qi)423 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi)
424 {
425 smb_ofile_t *of = sr->fid_ofile;
426
427 ASSERT(qi->qi_namelen > 0);
428 ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID);
429
430 if (of->f_ftype != SMB_FTYPE_DISK)
431 return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
432 if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
433 return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
434
435 /* fill in qi->qi_shortname */
436 smb_query_shortname(of->f_node, qi);
437
438 (void) smb_mbc_encodef(
439 &sr->raw_data, "%lU", sr,
440 smb_wcequiv_strlen(qi->qi_shortname),
441 qi->qi_shortname);
442
443 return (0);
444 }
445
446 /*
447 * FileStreamInformation
448 */
449 static uint32_t
smb2_qif_stream(smb_request_t * sr,smb_queryinfo_t * qi)450 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi)
451 {
452 smb_ofile_t *of = sr->fid_ofile;
453 smb_attr_t *attr = &qi->qi_attr;
454 uint32_t status;
455
456 ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
457 if (of->f_ftype != SMB_FTYPE_DISK) {
458 (void) smb_mbc_encodef(
459 &sr->raw_data, "l", 0);
460 return (0);
461 }
462
463 status = smb_query_stream_info(sr, &sr->raw_data, qi);
464 return (status);
465 }
466
467 /*
468 * FilePipeInformation
469 */
470 static uint32_t
smb2_qif_pipe(smb_request_t * sr,smb_queryinfo_t * qi)471 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi)
472 {
473 _NOTE(ARGUNUSED(qi))
474 smb_ofile_t *of = sr->fid_ofile;
475 uint32_t pipe_mode;
476 uint32_t nonblock;
477
478 switch (of->f_ftype) {
479 case SMB_FTYPE_BYTE_PIPE:
480 pipe_mode = 0; /* FILE_PIPE_BYTE_STREAM_MODE */
481 break;
482 case SMB_FTYPE_MESG_PIPE:
483 pipe_mode = 1; /* FILE_PIPE_MESSAGE_MODE */
484 break;
485 case SMB_FTYPE_DISK:
486 case SMB_FTYPE_PRINTER:
487 default:
488 return (NT_STATUS_INVALID_PARAMETER);
489 }
490 nonblock = 0; /* XXX todo: Get this from the pipe handle. */
491
492 (void) smb_mbc_encodef(
493 &sr->raw_data, "ll",
494 pipe_mode, nonblock);
495
496 return (0);
497 }
498
499 /*
500 * FilePipeLocalInformation
501 */
502 /* ARGSUSED */
503 static uint32_t
smb2_qif_pipe_lcl(smb_request_t * sr,smb_queryinfo_t * qi)504 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi)
505 {
506 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
507 }
508
509 /*
510 * FilePipeRemoteInformation
511 */
512 /* ARGSUSED */
513 static uint32_t
smb2_qif_pipe_rem(smb_request_t * sr,smb_queryinfo_t * qi)514 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi)
515 {
516 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
517 }
518
519 /*
520 * FileCompressionInformation
521 * XXX: For now, just say "not compressed".
522 */
523 static uint32_t
smb2_qif_compr(smb_request_t * sr,smb_queryinfo_t * qi)524 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi)
525 {
526 smb_attr_t *sa = &qi->qi_attr;
527 uint16_t CompressionFormat = 0; /* COMPRESSION_FORMAT_NONE */
528
529 ASSERT(sa->sa_mask & SMB_AT_SIZE);
530
531 (void) smb_mbc_encodef(
532 &sr->raw_data, "qw6.",
533 sa->sa_vattr.va_size, /* q */
534 CompressionFormat); /* w */
535
536 return (0);
537 }
538
539 /*
540 * FileNetworkOpenInformation
541 */
542 static uint32_t
smb2_qif_opens(smb_request_t * sr,smb_queryinfo_t * qi)543 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi)
544 {
545 smb_attr_t *sa = &qi->qi_attr;
546
547 (void) smb_mbc_encodef(
548 &sr->raw_data, "TTTTqqll",
549 &sa->sa_crtime, /* T */
550 &sa->sa_vattr.va_atime, /* T */
551 &sa->sa_vattr.va_mtime, /* T */
552 &sa->sa_vattr.va_ctime, /* T */
553 sa->sa_allocsz, /* q */
554 sa->sa_vattr.va_size, /* q */
555 sa->sa_dosattr, /* l */
556 0); /* reserved */ /* l */
557
558 return (0);
559 }
560
561 /*
562 * FileAttributeTagInformation
563 *
564 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
565 * second dword should be the reparse tag. Otherwise
566 * the tag value should be set to zero.
567 * We don't support reparse points, so we set the tag
568 * to zero.
569 */
570 static uint32_t
smb2_qif_tags(smb_request_t * sr,smb_queryinfo_t * qi)571 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi)
572 {
573 _NOTE(ARGUNUSED(qi))
574 (void) smb_mbc_encodef(
575 &sr->raw_data, "ll", 0, 0);
576
577 return (0);
578 }
579