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