xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c (revision 4c28a617e3922d92a58e813a5b955eb526b9c386)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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