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
27static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *);
28static uint32_t smb2_qif_basic(smb_request_t *, smb_queryinfo_t *);
29static uint32_t smb2_qif_standard(smb_request_t *, smb_queryinfo_t *);
30static uint32_t smb2_qif_internal(smb_request_t *, smb_queryinfo_t *);
31static uint32_t smb2_qif_ea_size(smb_request_t *, smb_queryinfo_t *);
32static uint32_t smb2_qif_access(smb_request_t *, smb_queryinfo_t *);
33static uint32_t smb2_qif_name(smb_request_t *, smb_queryinfo_t *);
34static uint32_t smb2_qif_position(smb_request_t *, smb_queryinfo_t *);
35static uint32_t smb2_qif_full_ea(smb_request_t *, smb_queryinfo_t *);
36static uint32_t smb2_qif_mode(smb_request_t *, smb_queryinfo_t *);
37static uint32_t smb2_qif_alignment(smb_request_t *, smb_queryinfo_t *);
38static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *);
39static uint32_t smb2_qif_altname(smb_request_t *, smb_queryinfo_t *);
40static uint32_t smb2_qif_stream(smb_request_t *, smb_queryinfo_t *);
41static uint32_t smb2_qif_pipe(smb_request_t *, smb_queryinfo_t *);
42static uint32_t smb2_qif_pipe_lcl(smb_request_t *, smb_queryinfo_t *);
43static uint32_t smb2_qif_pipe_rem(smb_request_t *, smb_queryinfo_t *);
44static uint32_t smb2_qif_compr(smb_request_t *, smb_queryinfo_t *);
45static uint32_t smb2_qif_opens(smb_request_t *, smb_queryinfo_t *);
46static uint32_t smb2_qif_tags(smb_request_t *, smb_queryinfo_t *);
47
48
49uint32_t
50smb2_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 */
200static uint32_t
201smb2_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 */
239static uint32_t
240smb2_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 */
264static uint32_t
265smb2_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 */
288static uint32_t
289smb2_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 */
314static uint32_t
315smb2_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 */
330static uint32_t
331smb2_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 */
339static uint32_t
340smb2_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 */
358static uint32_t
359smb2_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 */
376static uint32_t
377smb2_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 */
398static uint32_t
399smb2_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 */
412static uint32_t
413smb2_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 */
429static uint32_t
430smb2_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 */
456static uint32_t
457smb2_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 */
477static uint32_t
478smb2_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 */
510static uint32_t
511smb2_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 */
520static uint32_t
521smb2_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 */
530static uint32_t
531smb2_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 */
549static uint32_t
550smb2_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 */
577static uint32_t
578smb2_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}
586