xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c (revision 9e3493cb8a0cfe96c9aef9b7da42c6c9b5c24b43)
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 2019 Nexenta by DDN, 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 	int rc;
244 
245 	ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC);
246 
247 	rc = smb_mbc_encodef(
248 	    &sr->raw_data, "TTTTll",
249 	    &sa->sa_crtime,		/* T */
250 	    &sa->sa_vattr.va_atime,	/* T */
251 	    &sa->sa_vattr.va_mtime,	/* T */
252 	    &sa->sa_vattr.va_ctime,	/* T */
253 	    sa->sa_dosattr,		/* l */
254 	    0); /* reserved */		/* l */
255 	if (rc != 0)
256 		return (NT_STATUS_BUFFER_OVERFLOW);
257 
258 	return (0);
259 }
260 
261 /*
262  * FileStandardInformation
263  * See also:
264  *	SMB_QUERY_FILE_STANDARD_INFO
265  *	SMB_FILE_STANDARD_INFORMATION
266  */
267 static uint32_t
268 smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi)
269 {
270 	smb_attr_t *sa = &qi->qi_attr;
271 	int rc;
272 
273 	ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
274 
275 	rc = smb_mbc_encodef(
276 	    &sr->raw_data, "qqlbbw",
277 	    sa->sa_allocsz,		/* q */
278 	    sa->sa_vattr.va_size,	/* q */
279 	    sa->sa_vattr.va_nlink,	/* l */
280 	    qi->qi_delete_on_close,	/* b */
281 	    qi->qi_isdir,		/* b */
282 	    0); /* reserved */		/* w */
283 	if (rc != 0)
284 		return (NT_STATUS_BUFFER_OVERFLOW);
285 
286 	return (0);
287 }
288 
289 /*
290  * FileInternalInformation
291  * See also:
292  *	SMB_FILE_INTERNAL_INFORMATION
293  */
294 static uint32_t
295 smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi)
296 {
297 	smb_attr_t *sa = &qi->qi_attr;
298 	u_longlong_t nodeid;
299 	int rc;
300 
301 	ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID);
302 	nodeid = sa->sa_vattr.va_nodeid;
303 
304 	if (smb2_aapl_use_file_ids == 0 &&
305 	    (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0)
306 		nodeid = 0;
307 
308 	rc = smb_mbc_encodef(
309 	    &sr->raw_data, "q",
310 	    nodeid);	/* q */
311 	if (rc != 0)
312 		return (NT_STATUS_BUFFER_OVERFLOW);
313 
314 	return (0);
315 }
316 
317 /*
318  * FileEaInformation
319  * See also:
320  *	SMB_QUERY_FILE_EA_INFO
321  *	SMB_FILE_EA_INFORMATION
322  */
323 static uint32_t
324 smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi)
325 {
326 	_NOTE(ARGUNUSED(qi))
327 	int rc;
328 
329 	rc = smb_mbc_encodef(
330 	    &sr->raw_data, "l", 0);
331 	if (rc != 0)
332 		return (NT_STATUS_BUFFER_OVERFLOW);
333 
334 	return (0);
335 }
336 
337 /*
338  * FileFullEaInformation
339  * We could put EAs in a named stream...
340  */
341 /* ARGSUSED */
342 static uint32_t
343 smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi)
344 {
345 	return (NT_STATUS_NO_EAS_ON_FILE);
346 }
347 
348 /*
349  * FileAccessInformation
350  */
351 static uint32_t
352 smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi)
353 {
354 	_NOTE(ARGUNUSED(qi))
355 	smb_ofile_t *of = sr->fid_ofile;
356 	int rc;
357 
358 	rc = smb_mbc_encodef(
359 	    &sr->raw_data, "l",
360 	    of->f_granted_access);
361 	if (rc != 0)
362 		return (NT_STATUS_BUFFER_OVERFLOW);
363 
364 	return (0);
365 }
366 
367 /*
368  * FileNameInformation
369  * See also:
370  *	SMB_QUERY_FILE_NAME_INFO
371  *	SMB_FILE_NAME_INFORMATION
372  */
373 static uint32_t
374 smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi)
375 {
376 	int rc;
377 
378 	ASSERT(qi->qi_namelen > 0);
379 
380 	rc = smb_mbc_encodef(
381 	    &sr->raw_data, "llU",
382 	    0, /* FileIndex	 (l) */
383 	    qi->qi_namelen,	/* l */
384 	    qi->qi_name);	/* U */
385 	if (rc != 0)
386 		return (NT_STATUS_BUFFER_OVERFLOW);
387 
388 	return (0);
389 }
390 
391 /*
392  * FilePositionInformation
393  */
394 static uint32_t
395 smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi)
396 {
397 	_NOTE(ARGUNUSED(qi))
398 	smb_ofile_t *of = sr->fid_ofile;
399 	uint64_t pos;
400 	int rc;
401 
402 	mutex_enter(&of->f_mutex);
403 	pos = of->f_seek_pos;
404 	mutex_exit(&of->f_mutex);
405 
406 	rc = smb_mbc_encodef(
407 	    &sr->raw_data, "q", pos);
408 	if (rc != 0)
409 		return (NT_STATUS_BUFFER_OVERFLOW);
410 
411 	return (0);
412 }
413 
414 /*
415  * FileModeInformation [MS-FSA 2.4.24]
416  * XXX: These mode flags are supposed to be on the open handle,
417  * XXX: or I think so.  Not yet...  (just put zero for now)
418  */
419 static uint32_t
420 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi)
421 {
422 	_NOTE(ARGUNUSED(qi))
423 	int rc;
424 
425 	rc = smb_mbc_encodef(
426 	    &sr->raw_data, "l", 0);
427 	if (rc != 0)
428 		return (NT_STATUS_BUFFER_OVERFLOW);
429 
430 	return (0);
431 }
432 
433 /*
434  * FileAlignmentInformation
435  */
436 static uint32_t
437 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi)
438 {
439 	_NOTE(ARGUNUSED(qi))
440 	int rc;
441 
442 	rc = smb_mbc_encodef(
443 	    &sr->raw_data, "l", 0);
444 	if (rc != 0)
445 		return (NT_STATUS_BUFFER_OVERFLOW);
446 
447 	return (0);
448 }
449 
450 /*
451  * FileAlternateNameInformation
452  * See also:
453  *	SMB_QUERY_FILE_ALT_NAME_INFO
454  *	SMB_FILE_ALT_NAME_INFORMATION
455  */
456 static uint32_t
457 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi)
458 {
459 	smb_ofile_t *of = sr->fid_ofile;
460 	int rc;
461 
462 	ASSERT(qi->qi_namelen > 0);
463 	ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID);
464 
465 	if (of->f_ftype != SMB_FTYPE_DISK)
466 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
467 	if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
468 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
469 
470 	/* fill in qi->qi_shortname */
471 	smb_query_shortname(of->f_node, qi);
472 
473 	rc = smb_mbc_encodef(
474 	    &sr->raw_data, "%lU", sr,
475 	    smb_wcequiv_strlen(qi->qi_shortname),
476 	    qi->qi_shortname);
477 	if (rc != 0)
478 		return (NT_STATUS_BUFFER_OVERFLOW);
479 
480 	return (0);
481 }
482 
483 /*
484  * FileStreamInformation
485  */
486 static uint32_t
487 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi)
488 {
489 	smb_ofile_t *of = sr->fid_ofile;
490 	smb_attr_t *attr = &qi->qi_attr;
491 	uint32_t status;
492 
493 	ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
494 	if (of->f_ftype != SMB_FTYPE_DISK) {
495 		(void) smb_mbc_encodef(
496 		    &sr->raw_data, "l", 0);
497 		return (0);
498 	}
499 
500 	status = smb_query_stream_info(sr, &sr->raw_data, qi);
501 	return (status);
502 }
503 
504 /*
505  * FilePipeInformation
506  */
507 static uint32_t
508 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi)
509 {
510 	_NOTE(ARGUNUSED(qi))
511 	smb_ofile_t *of = sr->fid_ofile;
512 	uint32_t	pipe_mode;
513 	uint32_t	nonblock;
514 	int		rc;
515 
516 	switch (of->f_ftype) {
517 	case SMB_FTYPE_BYTE_PIPE:
518 		pipe_mode = 0;	/* FILE_PIPE_BYTE_STREAM_MODE */
519 		break;
520 	case SMB_FTYPE_MESG_PIPE:
521 		pipe_mode = 1;	/* FILE_PIPE_MESSAGE_MODE */
522 		break;
523 	case SMB_FTYPE_DISK:
524 	case SMB_FTYPE_PRINTER:
525 	default:
526 		return (NT_STATUS_INVALID_PARAMETER);
527 	}
528 	nonblock = 0;	/* XXX todo: Get this from the pipe handle. */
529 
530 	rc = smb_mbc_encodef(
531 	    &sr->raw_data, "ll",
532 	    pipe_mode, nonblock);
533 	if (rc != 0)
534 		return (NT_STATUS_BUFFER_OVERFLOW);
535 
536 	return (0);
537 }
538 
539 /*
540  * FilePipeLocalInformation
541  */
542 /* ARGSUSED */
543 static uint32_t
544 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi)
545 {
546 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
547 }
548 
549 /*
550  * FilePipeRemoteInformation
551  */
552 /* ARGSUSED */
553 static uint32_t
554 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi)
555 {
556 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
557 }
558 
559 /*
560  * FileCompressionInformation
561  * XXX: For now, just say "not compressed".
562  */
563 static uint32_t
564 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi)
565 {
566 	smb_attr_t *sa = &qi->qi_attr;
567 	uint16_t CompressionFormat = 0;	/* COMPRESSION_FORMAT_NONE */
568 	int rc;
569 
570 	ASSERT(sa->sa_mask & SMB_AT_SIZE);
571 
572 	rc = smb_mbc_encodef(
573 	    &sr->raw_data, "qw6.",
574 	    sa->sa_vattr.va_size,	/* q */
575 	    CompressionFormat);		/* w */
576 	if (rc != 0)
577 		return (NT_STATUS_BUFFER_OVERFLOW);
578 
579 	return (0);
580 }
581 
582 /*
583  * FileNetworkOpenInformation
584  */
585 static uint32_t
586 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi)
587 {
588 	smb_attr_t *sa = &qi->qi_attr;
589 	int rc;
590 
591 	rc = smb_mbc_encodef(
592 	    &sr->raw_data, "TTTTqqll",
593 	    &sa->sa_crtime,		/* T */
594 	    &sa->sa_vattr.va_atime,	/* T */
595 	    &sa->sa_vattr.va_mtime,	/* T */
596 	    &sa->sa_vattr.va_ctime,	/* T */
597 	    sa->sa_allocsz,		/* q */
598 	    sa->sa_vattr.va_size,	/* q */
599 	    sa->sa_dosattr,		/* l */
600 	    0); /* reserved */		/* l */
601 	if (rc != 0)
602 		return (NT_STATUS_BUFFER_OVERFLOW);
603 
604 	return (0);
605 }
606 
607 /*
608  * FileAttributeTagInformation
609  *
610  * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
611  * second dword should be the reparse tag.  Otherwise
612  * the tag value should be set to zero.
613  * We don't support reparse points, so we set the tag
614  * to zero.
615  */
616 static uint32_t
617 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi)
618 {
619 	_NOTE(ARGUNUSED(qi))
620 	int rc;
621 
622 	rc = smb_mbc_encodef(
623 	    &sr->raw_data, "ll", 0, 0);
624 	if (rc != 0)
625 		return (NT_STATUS_BUFFER_OVERFLOW);
626 
627 	return (0);
628 }
629