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