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  * Copyright 2022-2023 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Dispatch function for SMB2_QUERY_INFO
19  *
20  * [MS-FSCC 2.4] If a file system does not support ...
21  * an Information Classs, NT_STATUS_INVALID_PARAMETER...
22  */
23 
24 #include <smbsrv/smb2_kproto.h>
25 #include <smbsrv/smb_fsops.h>
26 #include <smbsrv/ntifs.h>
27 
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_normalized_name(smb_request_t *, smb_queryinfo_t *);
35 static uint32_t smb2_qif_position(smb_request_t *, smb_queryinfo_t *);
36 static uint32_t smb2_qif_full_ea(smb_request_t *, smb_queryinfo_t *);
37 static uint32_t smb2_qif_mode(smb_request_t *, smb_queryinfo_t *);
38 static uint32_t smb2_qif_alignment(smb_request_t *, smb_queryinfo_t *);
39 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *);
40 static uint32_t smb2_qif_altname(smb_request_t *, smb_queryinfo_t *);
41 static uint32_t smb2_qif_stream(smb_request_t *, smb_queryinfo_t *);
42 static uint32_t smb2_qif_pipe(smb_request_t *, smb_queryinfo_t *);
43 static uint32_t smb2_qif_pipe_lcl(smb_request_t *, smb_queryinfo_t *);
44 static uint32_t smb2_qif_pipe_rem(smb_request_t *, smb_queryinfo_t *);
45 static uint32_t smb2_qif_compr(smb_request_t *, smb_queryinfo_t *);
46 static uint32_t smb2_qif_opens(smb_request_t *, smb_queryinfo_t *);
47 static uint32_t smb2_qif_tags(smb_request_t *, smb_queryinfo_t *);
48 static uint32_t smb2_qif_id_info(smb_request_t *, smb_queryinfo_t *);
49 
50 /*
51  * MS-SMB2 3.3.5.20.1 says (in a windows behavior note) that
52  * 2012R2 and older fill in the FileNameInformation.
53  * Default to the new behavior.
54  */
55 boolean_t smb2_qif_all_get_name = B_FALSE;
56 
57 uint32_t
58 smb2_qinfo_file(smb_request_t *sr, smb_queryinfo_t *qi)
59 {
60 	smb_ofile_t *of = sr->fid_ofile;
61 	uint_t mask = 0;
62 	boolean_t getstd = B_FALSE;
63 	boolean_t getname = B_FALSE;
64 	uint32_t status;
65 
66 	/*
67 	 * Which attributes do we need from the FS?
68 	 */
69 	switch (qi->qi_InfoClass) {
70 	case FileBasicInformation:
71 		mask = SMB_AT_BASIC;
72 		break;
73 	case FileStandardInformation:
74 		mask = SMB_AT_STANDARD;
75 		getstd = B_TRUE;
76 		break;
77 	case FileInternalInformation:
78 		mask = SMB_AT_NODEID;
79 		break;
80 	case FileAllInformation:
81 		mask = SMB_AT_ALL;
82 		getstd = B_TRUE;
83 		if (smb2_qif_all_get_name)
84 			getname = B_TRUE;
85 		break;
86 
87 	case FileNameInformation:
88 	case FileNormalizedNameInformation:
89 		getname = B_TRUE;
90 		break;
91 
92 	case FileAlternateNameInformation:
93 		mask = SMB_AT_NODEID;
94 		getname = B_TRUE;
95 		break;
96 
97 	case FileStreamInformation:
98 		mask = SMB_AT_STANDARD;
99 		getstd = B_TRUE;
100 		break;
101 
102 	case FileCompressionInformation:
103 		mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ;
104 		break;
105 
106 	case FileNetworkOpenInformation:
107 		mask = SMB_AT_BASIC | SMB_AT_STANDARD;
108 		break;
109 
110 	case FileIdInformation:
111 		mask = SMB_AT_NODEID;
112 		break;
113 
114 	default:
115 		break;
116 	}
117 
118 	qi->qi_attr.sa_mask = mask;
119 	qi->qi_node = of->f_node;
120 	if (mask & SMB_AT_ALL) {
121 		status = smb2_ofile_getattr(sr, of, &qi->qi_attr);
122 		if (status)
123 			return (status);
124 	}
125 	if (getstd) {
126 		status = smb2_ofile_getstd(of, qi);
127 		if (status)
128 			return (status);
129 	}
130 	if (getname) {
131 		status = smb2_ofile_getname(of, qi);
132 		if (status)
133 			return (status);
134 	}
135 
136 	switch (qi->qi_InfoClass) {
137 	case FileBasicInformation:
138 		status = smb2_qif_basic(sr, qi);
139 		break;
140 	case FileStandardInformation:
141 		status = smb2_qif_standard(sr, qi);
142 		break;
143 	case FileInternalInformation:
144 		status = smb2_qif_internal(sr, qi);
145 		break;
146 	case FileEaInformation:
147 		status = smb2_qif_ea_size(sr, qi);
148 		break;
149 	case FileAccessInformation:
150 		status = smb2_qif_access(sr, qi);
151 		break;
152 	case FileNameInformation:
153 		status = smb2_qif_name(sr, qi);
154 		break;
155 	case FileNormalizedNameInformation:
156 		status = smb2_qif_normalized_name(sr, qi);
157 		break;
158 	case FilePositionInformation:
159 		status = smb2_qif_position(sr, qi);
160 		break;
161 	case FileFullEaInformation:
162 		status = smb2_qif_full_ea(sr, qi);
163 		break;
164 	case FileModeInformation:
165 		status = smb2_qif_mode(sr, qi);
166 		break;
167 	case FileAlignmentInformation:
168 		status = smb2_qif_alignment(sr, qi);
169 		break;
170 	case FileAllInformation:
171 		status = smb2_qif_all(sr, qi);
172 		break;
173 	case FileAlternateNameInformation:
174 		status = smb2_qif_altname(sr, qi);
175 		break;
176 	case FileStreamInformation:
177 		status = smb2_qif_stream(sr, qi);
178 		break;
179 	case FilePipeInformation:
180 		status = smb2_qif_pipe(sr, qi);
181 		break;
182 	case FilePipeLocalInformation:
183 		status = smb2_qif_pipe_lcl(sr, qi);
184 		break;
185 	case FilePipeRemoteInformation:
186 		status = smb2_qif_pipe_rem(sr, qi);
187 		break;
188 	case FileCompressionInformation:
189 		status = smb2_qif_compr(sr, qi);
190 		break;
191 	case FileNetworkOpenInformation:
192 		status = smb2_qif_opens(sr, qi);
193 		break;
194 	case FileAttributeTagInformation:
195 		status = smb2_qif_tags(sr, qi);
196 		break;
197 	case FileIdInformation:
198 		status = smb2_qif_id_info(sr, qi);
199 		break;
200 	default:
201 		status = NT_STATUS_INVALID_INFO_CLASS;
202 		break;
203 	}
204 
205 	return (status);
206 }
207 
208 /*
209  * FileAllInformation
210  *
211  * This returns a concatenation of:
212  *	FileBasicInformation
213  *	FileStandardInformation
214  *	FileInternalInformation
215  *	FileEaInformation
216  *	FilePositionInformation
217  *	FileModeInformation
218  *	FileAlignmentInformation
219  *	FileNameInformation
220  *
221  * Note: FileNameInformation is all zero on Win2016 and later.
222  */
223 static uint32_t
224 smb2_qif_all(smb_request_t *sr, smb_queryinfo_t *qi)
225 {
226 	uint32_t status;
227 
228 	status = smb2_qif_basic(sr, qi);
229 	if (status)
230 		return (status);
231 	status = smb2_qif_standard(sr, qi);
232 	if (status)
233 		return (status);
234 	status = smb2_qif_internal(sr, qi);
235 	if (status)
236 		return (status);
237 	status = smb2_qif_ea_size(sr, qi);
238 	if (status)
239 		return (status);
240 	status = smb2_qif_position(sr, qi);
241 	if (status)
242 		return (status);
243 	status = smb2_qif_mode(sr, qi);
244 	if (status)
245 		return (status);
246 	status = smb2_qif_alignment(sr, qi);
247 	if (status)
248 		return (status);
249 
250 	/* See smb2_qif_all_get_name */
251 	if (qi->qi_namelen != 0) {
252 		/* Win2012r2 and earlier fill it in. */
253 		status = smb2_qif_name(sr, qi);
254 	} else {
255 		/* Win2016 and later just put zeros. */
256 		int rc = smb_mbc_encodef(&sr->raw_data, "10.");
257 		status = (rc == 0) ? 0 : NT_STATUS_BUFFER_OVERFLOW;
258 	}
259 
260 	return (status);
261 }
262 
263 /*
264  * FileBasicInformation
265  * See also:
266  *	case SMB_QUERY_FILE_BASIC_INFO:
267  *	case SMB_FILE_BASIC_INFORMATION:
268  */
269 static uint32_t
270 smb2_qif_basic(smb_request_t *sr, smb_queryinfo_t *qi)
271 {
272 	smb_attr_t *sa = &qi->qi_attr;
273 	int rc;
274 
275 	ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC);
276 
277 	rc = smb_mbc_encodef(
278 	    &sr->raw_data, "TTTTll",
279 	    &sa->sa_crtime,		/* T */
280 	    &sa->sa_vattr.va_atime,	/* T */
281 	    &sa->sa_vattr.va_mtime,	/* T */
282 	    &sa->sa_vattr.va_ctime,	/* T */
283 	    sa->sa_dosattr,		/* l */
284 	    0); /* reserved */		/* l */
285 	if (rc != 0)
286 		return (NT_STATUS_BUFFER_OVERFLOW);
287 
288 	return (0);
289 }
290 
291 /*
292  * FileStandardInformation
293  * See also:
294  *	SMB_QUERY_FILE_STANDARD_INFO
295  *	SMB_FILE_STANDARD_INFORMATION
296  */
297 static uint32_t
298 smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi)
299 {
300 	smb_attr_t *sa = &qi->qi_attr;
301 	int rc;
302 
303 	ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
304 
305 	rc = smb_mbc_encodef(
306 	    &sr->raw_data, "qqlbbw",
307 	    sa->sa_allocsz,		/* q */
308 	    sa->sa_vattr.va_size,	/* q */
309 	    sa->sa_vattr.va_nlink,	/* l */
310 	    qi->qi_delete_on_close,	/* b */
311 	    qi->qi_isdir,		/* b */
312 	    0); /* reserved */		/* w */
313 	if (rc != 0)
314 		return (NT_STATUS_BUFFER_OVERFLOW);
315 
316 	return (0);
317 }
318 
319 /*
320  * FileInternalInformation
321  * See also:
322  *	SMB_FILE_INTERNAL_INFORMATION
323  */
324 static uint32_t
325 smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi)
326 {
327 	smb_attr_t *sa = &qi->qi_attr;
328 	u_longlong_t nodeid;
329 	int rc;
330 
331 	ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID);
332 	nodeid = sa->sa_vattr.va_nodeid;
333 
334 	if (smb2_aapl_use_file_ids == 0 &&
335 	    (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0)
336 		nodeid = 0;
337 
338 	rc = smb_mbc_encodef(
339 	    &sr->raw_data, "q",
340 	    nodeid);	/* q */
341 	if (rc != 0)
342 		return (NT_STATUS_BUFFER_OVERFLOW);
343 
344 	return (0);
345 }
346 
347 /*
348  * FileEaInformation
349  * See also:
350  *	SMB_QUERY_FILE_EA_INFO
351  *	SMB_FILE_EA_INFORMATION
352  */
353 static uint32_t
354 smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi)
355 {
356 	_NOTE(ARGUNUSED(qi))
357 	int rc;
358 
359 	rc = smb_mbc_encodef(
360 	    &sr->raw_data, "l", 0);
361 	if (rc != 0)
362 		return (NT_STATUS_BUFFER_OVERFLOW);
363 
364 	return (0);
365 }
366 
367 /*
368  * FileFullEaInformation
369  * We could put EAs in a named stream...
370  */
371 /* ARGSUSED */
372 static uint32_t
373 smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi)
374 {
375 	return (NT_STATUS_NO_EAS_ON_FILE);
376 }
377 
378 /*
379  * FileAccessInformation
380  */
381 static uint32_t
382 smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi)
383 {
384 	_NOTE(ARGUNUSED(qi))
385 	smb_ofile_t *of = sr->fid_ofile;
386 	int rc;
387 
388 	rc = smb_mbc_encodef(
389 	    &sr->raw_data, "l",
390 	    of->f_granted_access);
391 	if (rc != 0)
392 		return (NT_STATUS_BUFFER_OVERFLOW);
393 
394 	return (0);
395 }
396 
397 /*
398  * FileNameInformation
399  * See also:
400  *	SMB_QUERY_FILE_NAME_INFO
401  *	SMB_FILE_NAME_INFORMATION
402  */
403 static uint32_t
404 smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi)
405 {
406 	char *name;
407 	uint32_t nlen;
408 	int rc;
409 
410 	/* SMB2 leaves off the leading / */
411 	nlen = qi->qi_namelen;
412 	name = qi->qi_name;
413 	if (qi->qi_name[0] == '\\') {
414 		name++;
415 		nlen -= 2;
416 	}
417 
418 	rc = smb_mbc_encodef(
419 	    &sr->raw_data, "llU",
420 	    0, /* FileIndex	 (l) */
421 	    nlen,	/* l */
422 	    name);	/* U */
423 	if (rc != 0)
424 		return (NT_STATUS_BUFFER_OVERFLOW);
425 
426 	return (0);
427 }
428 
429 /*
430  * FileNormalizedNameInformation
431  */
432 static uint32_t
433 smb2_qif_normalized_name(smb_request_t *sr, smb_queryinfo_t *qi)
434 {
435 	char *name;
436 	uint32_t nlen;
437 	int rc;
438 
439 	/* SMB2 leaves off the leading / */
440 	nlen = qi->qi_namelen;
441 	name = qi->qi_name;
442 	if (qi->qi_name[0] == '\\') {
443 		name++;
444 		nlen -= 2;
445 	}
446 
447 	rc = smb_mbc_encodef(
448 	    &sr->raw_data, "lU",
449 	    nlen,	/* l */
450 	    name);	/* U */
451 	if (rc != 0)
452 		return (NT_STATUS_BUFFER_OVERFLOW);
453 
454 	return (0);
455 }
456 
457 /*
458  * FilePositionInformation
459  */
460 static uint32_t
461 smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi)
462 {
463 	_NOTE(ARGUNUSED(qi))
464 	smb_ofile_t *of = sr->fid_ofile;
465 	uint64_t pos;
466 	int rc;
467 
468 	mutex_enter(&of->f_mutex);
469 	pos = of->f_seek_pos;
470 	mutex_exit(&of->f_mutex);
471 
472 	rc = smb_mbc_encodef(
473 	    &sr->raw_data, "q", pos);
474 	if (rc != 0)
475 		return (NT_STATUS_BUFFER_OVERFLOW);
476 
477 	return (0);
478 }
479 
480 /*
481  * FileModeInformation [MS-FSA 2.4.24]
482  */
483 static uint32_t
484 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi)
485 {
486 	_NOTE(ARGUNUSED(qi))
487 	smb_ofile_t *of = sr->fid_ofile;
488 	uint32_t mode;
489 	int rc;
490 
491 	/*
492 	 * See MS-FSA description of Open.Mode
493 	 * For now, we have these in...
494 	 */
495 	mode = of->f_create_options &
496 	    (FILE_WRITE_THROUGH | FILE_SEQUENTIAL_ONLY |
497 	    FILE_NO_INTERMEDIATE_BUFFERING | FILE_DELETE_ON_CLOSE);
498 
499 	/*
500 	 * The ofile level DoC flag is currently in of->f_flags
501 	 * (SMB_OFLAGS_SET_DELETE_ON_CLOSE) though probably it
502 	 * should be in f_create_options (and perhaps rename
503 	 * that field to f_mode or something closer to the
504 	 * Open.Mode terminology used in MS-FSA).
505 	 */
506 	if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE)
507 		mode |= FILE_DELETE_ON_CLOSE;
508 
509 	rc = smb_mbc_encodef(
510 	    &sr->raw_data, "l", mode);
511 	if (rc != 0)
512 		return (NT_STATUS_BUFFER_OVERFLOW);
513 
514 	return (0);
515 }
516 
517 /*
518  * FileAlignmentInformation
519  */
520 static uint32_t
521 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi)
522 {
523 	_NOTE(ARGUNUSED(qi))
524 	int rc;
525 
526 	rc = smb_mbc_encodef(
527 	    &sr->raw_data, "l", 0);
528 	if (rc != 0)
529 		return (NT_STATUS_BUFFER_OVERFLOW);
530 
531 	return (0);
532 }
533 
534 /*
535  * FileAlternateNameInformation
536  * See also:
537  *	SMB_QUERY_FILE_ALT_NAME_INFO
538  *	SMB_FILE_ALT_NAME_INFORMATION
539  */
540 static uint32_t
541 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi)
542 {
543 	smb_ofile_t *of = sr->fid_ofile;
544 	int rc;
545 
546 	ASSERT(qi->qi_namelen > 0);
547 	ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID);
548 
549 	if (of->f_ftype != SMB_FTYPE_DISK)
550 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
551 	if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
552 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
553 
554 	/* fill in qi->qi_shortname */
555 	smb_query_shortname(of->f_node, qi);
556 
557 	rc = smb_mbc_encodef(
558 	    &sr->raw_data, "%lU", sr,
559 	    smb_wcequiv_strlen(qi->qi_shortname),
560 	    qi->qi_shortname);
561 	if (rc != 0)
562 		return (NT_STATUS_BUFFER_OVERFLOW);
563 
564 	return (0);
565 }
566 
567 /*
568  * FileStreamInformation
569  */
570 static uint32_t
571 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi)
572 {
573 	smb_ofile_t *of = sr->fid_ofile;
574 	smb_attr_t *attr = &qi->qi_attr;
575 	uint32_t status;
576 
577 	ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
578 	if (of->f_ftype != SMB_FTYPE_DISK) {
579 		(void) smb_mbc_encodef(
580 		    &sr->raw_data, "l", 0);
581 		return (0);
582 	}
583 
584 	status = smb_query_stream_info(sr, &sr->raw_data, qi);
585 	return (status);
586 }
587 
588 /*
589  * FilePipeInformation
590  */
591 static uint32_t
592 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi)
593 {
594 	_NOTE(ARGUNUSED(qi))
595 	smb_ofile_t *of = sr->fid_ofile;
596 	uint32_t	pipe_mode;
597 	uint32_t	nonblock;
598 	int		rc;
599 
600 	switch (of->f_ftype) {
601 	case SMB_FTYPE_BYTE_PIPE:
602 		pipe_mode = 0;	/* FILE_PIPE_BYTE_STREAM_MODE */
603 		break;
604 	case SMB_FTYPE_MESG_PIPE:
605 		pipe_mode = 1;	/* FILE_PIPE_MESSAGE_MODE */
606 		break;
607 	case SMB_FTYPE_DISK:
608 	case SMB_FTYPE_PRINTER:
609 	default:
610 		return (NT_STATUS_INVALID_PARAMETER);
611 	}
612 	nonblock = 0;	/* XXX todo: Get this from the pipe handle. */
613 
614 	rc = smb_mbc_encodef(
615 	    &sr->raw_data, "ll",
616 	    pipe_mode, nonblock);
617 	if (rc != 0)
618 		return (NT_STATUS_BUFFER_OVERFLOW);
619 
620 	return (0);
621 }
622 
623 /*
624  * FilePipeLocalInformation
625  */
626 /* ARGSUSED */
627 static uint32_t
628 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi)
629 {
630 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
631 }
632 
633 /*
634  * FilePipeRemoteInformation
635  */
636 /* ARGSUSED */
637 static uint32_t
638 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi)
639 {
640 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
641 }
642 
643 /*
644  * FileCompressionInformation
645  * XXX: For now, just say "not compressed".
646  */
647 static uint32_t
648 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi)
649 {
650 	smb_attr_t *sa = &qi->qi_attr;
651 	uint16_t CompressionFormat = 0;	/* COMPRESSION_FORMAT_NONE */
652 	int rc;
653 
654 	ASSERT(sa->sa_mask & SMB_AT_SIZE);
655 
656 	rc = smb_mbc_encodef(
657 	    &sr->raw_data, "qw6.",
658 	    sa->sa_vattr.va_size,	/* q */
659 	    CompressionFormat);		/* w */
660 	if (rc != 0)
661 		return (NT_STATUS_BUFFER_OVERFLOW);
662 
663 	return (0);
664 }
665 
666 /*
667  * FileNetworkOpenInformation
668  */
669 static uint32_t
670 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi)
671 {
672 	smb_attr_t *sa = &qi->qi_attr;
673 	int rc;
674 
675 	rc = smb_mbc_encodef(
676 	    &sr->raw_data, "TTTTqqll",
677 	    &sa->sa_crtime,		/* T */
678 	    &sa->sa_vattr.va_atime,	/* T */
679 	    &sa->sa_vattr.va_mtime,	/* T */
680 	    &sa->sa_vattr.va_ctime,	/* T */
681 	    sa->sa_allocsz,		/* q */
682 	    sa->sa_vattr.va_size,	/* q */
683 	    sa->sa_dosattr,		/* l */
684 	    0); /* reserved */		/* l */
685 	if (rc != 0)
686 		return (NT_STATUS_BUFFER_OVERFLOW);
687 
688 	return (0);
689 }
690 
691 /*
692  * FileAttributeTagInformation
693  *
694  * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
695  * second dword should be the reparse tag.  Otherwise
696  * the tag value should be set to zero.
697  * We don't support reparse points, so we set the tag
698  * to zero.
699  */
700 static uint32_t
701 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi)
702 {
703 	_NOTE(ARGUNUSED(qi))
704 	int rc;
705 
706 	rc = smb_mbc_encodef(
707 	    &sr->raw_data, "ll", 0, 0);
708 	if (rc != 0)
709 		return (NT_STATUS_BUFFER_OVERFLOW);
710 
711 	return (0);
712 }
713 
714 /*
715  * FileIdInformation
716  *
717  * Returns a A FILE_ID_INFORMATION
718  *	VolumeSerialNumber (8 bytes)
719  *	FileId (16 bytes)
720  *
721  * Take the volume serial from the share root,
722  * and compose the FileId from the nodeid and fsid
723  * of the file (in case we crossed mounts)
724  */
725 static uint32_t
726 smb2_qif_id_info(smb_request_t *sr, smb_queryinfo_t *qi)
727 {
728 	smb_attr_t *sa = &qi->qi_attr;
729 	smb_ofile_t *of = sr->fid_ofile;
730 	smb_tree_t *tree = sr->tid_tree;
731 	vfs_t	*f_vfs;	// file
732 	vfs_t	*s_vfs;	// share
733 	uint64_t nodeid;
734 	int rc;
735 
736 	ASSERT((sa->sa_mask & SMB_AT_NODEID) != 0);
737 	if (of->f_ftype != SMB_FTYPE_DISK)
738 		return (NT_STATUS_INVALID_INFO_CLASS);
739 
740 	s_vfs = SMB_NODE_VFS(tree->t_snode);
741 	f_vfs = SMB_NODE_VFS(of->f_node);
742 	nodeid = (uint64_t)sa->sa_vattr.va_nodeid;
743 
744 	rc = smb_mbc_encodef(
745 	    &sr->raw_data, "llqll",
746 	    s_vfs->vfs_fsid.val[0],	/* l */
747 	    s_vfs->vfs_fsid.val[1],	/* l */
748 	    nodeid,			/* q */
749 	    f_vfs->vfs_fsid.val[0],	/* l */
750 	    f_vfs->vfs_fsid.val[1]);	/* l */
751 	if (rc != 0)
752 		return (NT_STATUS_INFO_LENGTH_MISMATCH);
753 
754 	return (0);
755 }
756