xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c (revision 7014882c6a3672fd0e5d60200af8643ae53c5928)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <smbsrv/smb_kproto.h>
27 #include <smbsrv/smb_vops.h>
28 #include <smbsrv/smb_fsops.h>
29 
30 /*
31  * Trans2 Query File/Path Information Levels:
32  *
33  * SMB_INFO_STANDARD
34  * SMB_INFO_QUERY_EA_SIZE
35  * SMB_INFO_QUERY_EAS_FROM_LIST
36  * SMB_INFO_QUERY_ALL_EAS - not valid for pipes
37  * SMB_INFO_IS_NAME_VALID - only valid when query is by path
38  *
39  * SMB_QUERY_FILE_BASIC_INFO
40  * SMB_QUERY_FILE_STANDARD_INFO
41  * SMB_QUERY_FILE_EA_INFO
42  * SMB_QUERY_FILE_NAME_INFO
43  * SMB_QUERY_FILE_ALL_INFO
44  * SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes
45  * SMB_QUERY_FILE_STREAM_INFO - not valid for pipes
46  * SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes
47  *
48  * Supported Passthrough levels:
49  * SMB_FILE_BASIC_INFORMATION
50  * SMB_FILE_STANDARD_INFORMATION
51  * SMB_FILE_INTERNAL_INFORMATION
52  * SMB_FILE_EA_INFORMATION
53  * SMB_FILE_ACCESS_INFORMATION - not yet supported when query by path
54  * SMB_FILE_NAME_INFORMATION
55  * SMB_FILE_ALL_INFORMATION
56  * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
57  * SMB_FILE_STREAM_INFORMATION - not valid for pipes
58  * SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes
59  * SMB_FILE_NETWORK_OPEN_INFORMATION - not valid for pipes
60  * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes
61  *
62  * Internal levels representing non trans2 requests
63  * SMB_QUERY_INFORMATION
64  * SMB_QUERY_INFORMATION2
65  */
66 
67 /*
68  * SMB_STREAM_ENCODE_FIXED_SIZE:
69  * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
70  */
71 #define	SMB_STREAM_ENCODE_FIXED_SZ	24
72 
73 typedef struct smb_queryinfo {
74 	smb_node_t	*qi_node;	/* NULL for pipes */
75 	smb_attr_t	qi_attr;
76 	boolean_t	qi_delete_on_close;
77 	uint32_t	qi_namelen;
78 	char		qi_shortname[SMB_SHORTNAMELEN];
79 	char		qi_name[MAXPATHLEN];
80 } smb_queryinfo_t;
81 #define	qi_mtime	qi_attr.sa_vattr.va_mtime
82 #define	qi_ctime	qi_attr.sa_vattr.va_ctime
83 #define	qi_atime	qi_attr.sa_vattr.va_atime
84 #define	qi_crtime	qi_attr.sa_crtime
85 
86 static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
87 static int smb_query_by_path(smb_request_t *, smb_xa_t *, uint16_t);
88 
89 static int smb_query_fileinfo(smb_request_t *, smb_node_t *,
90     uint16_t, smb_queryinfo_t *);
91 static int smb_query_pipeinfo(smb_request_t *, smb_opipe_t *,
92     uint16_t, smb_queryinfo_t *);
93 static boolean_t smb_query_pipe_valid_infolev(smb_request_t *, uint16_t);
94 
95 static int smb_query_encode_response(smb_request_t *, smb_xa_t *,
96     uint16_t, smb_queryinfo_t *);
97 static void smb_encode_stream_info(smb_request_t *, smb_xa_t *,
98     smb_queryinfo_t *);
99 static boolean_t smb_stream_fits(smb_request_t *, smb_xa_t *, char *, uint32_t);
100 static int smb_query_pathname(smb_request_t *, smb_node_t *, boolean_t,
101     smb_queryinfo_t *);
102 static void smb_query_shortname(smb_node_t *, smb_queryinfo_t *);
103 
104 int smb_query_passthru;
105 
106 /*
107  * smb_com_trans2_query_file_information
108  */
109 smb_sdrc_t
110 smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
111 {
112 	uint16_t infolev;
113 
114 	if (smb_mbc_decodef(&xa->req_param_mb, "ww",
115 	    &sr->smb_fid, &infolev) != 0)
116 		return (SDRC_ERROR);
117 
118 	if (smb_query_by_fid(sr, xa, infolev) != 0)
119 		return (SDRC_ERROR);
120 
121 	return (SDRC_SUCCESS);
122 }
123 
124 /*
125  * smb_com_trans2_query_path_information
126  */
127 smb_sdrc_t
128 smb_com_trans2_query_path_information(smb_request_t *sr, smb_xa_t *xa)
129 {
130 	uint16_t	infolev;
131 	smb_fqi_t	*fqi = &sr->arg.dirop.fqi;
132 
133 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
134 		smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
135 		    ERRDOS, ERROR_INVALID_FUNCTION);
136 		return (SDRC_ERROR);
137 	}
138 
139 	if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
140 	    sr, &infolev, &fqi->fq_path.pn_path) != 0)
141 		return (SDRC_ERROR);
142 
143 	if (smb_query_by_path(sr, xa, infolev) != 0)
144 		return (SDRC_ERROR);
145 
146 	return (SDRC_SUCCESS);
147 }
148 
149 /*
150  * smb_com_query_information (aka getattr)
151  */
152 smb_sdrc_t
153 smb_pre_query_information(smb_request_t *sr)
154 {
155 	int rc;
156 	smb_fqi_t *fqi = &sr->arg.dirop.fqi;
157 
158 	rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
159 
160 	DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr,
161 	    smb_fqi_t *, fqi);
162 
163 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
164 }
165 
166 void
167 smb_post_query_information(smb_request_t *sr)
168 {
169 	DTRACE_SMB_1(op__QueryInformation__done, smb_request_t *, sr);
170 }
171 
172 smb_sdrc_t
173 smb_com_query_information(smb_request_t *sr)
174 {
175 	uint16_t infolev = SMB_QUERY_INFORMATION;
176 
177 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
178 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
179 		    ERRDOS, ERROR_ACCESS_DENIED);
180 		return (SDRC_ERROR);
181 	}
182 
183 	if (smb_query_by_path(sr, NULL, infolev) != 0)
184 		return (SDRC_ERROR);
185 
186 	return (SDRC_SUCCESS);
187 }
188 
189 /*
190  * smb_com_query_information2 (aka getattre)
191  */
192 smb_sdrc_t
193 smb_pre_query_information2(smb_request_t *sr)
194 {
195 	int rc;
196 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
197 
198 	DTRACE_SMB_1(op__QueryInformation2__start, smb_request_t *, sr);
199 
200 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
201 }
202 
203 void
204 smb_post_query_information2(smb_request_t *sr)
205 {
206 	DTRACE_SMB_1(op__QueryInformation2__done, smb_request_t *, sr);
207 }
208 
209 smb_sdrc_t
210 smb_com_query_information2(smb_request_t *sr)
211 {
212 	uint16_t infolev = SMB_QUERY_INFORMATION2;
213 
214 	if (smb_query_by_fid(sr, NULL, infolev) != 0)
215 		return (SDRC_ERROR);
216 
217 	return (SDRC_SUCCESS);
218 }
219 
220 /*
221  * smb_query_by_fid
222  *
223  * Common code for querying file information by open file (or pipe) id.
224  * Use the id to identify the node / pipe object and request the
225  * smb_queryinfo_t data for that object.
226  */
227 static int
228 smb_query_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
229 {
230 	int		rc;
231 	smb_queryinfo_t	*qinfo;
232 	smb_node_t	*node;
233 	smb_opipe_t	*opipe;
234 
235 	smbsr_lookup_file(sr);
236 
237 	if (sr->fid_ofile == NULL) {
238 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
239 		return (-1);
240 	}
241 
242 	if (infolev == SMB_INFO_IS_NAME_VALID) {
243 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
244 		smbsr_release_file(sr);
245 		return (-1);
246 	}
247 
248 	if ((sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) &&
249 	    (!smb_query_pipe_valid_infolev(sr, infolev))) {
250 		smbsr_release_file(sr);
251 		return (-1);
252 	}
253 
254 	qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
255 
256 	switch (sr->fid_ofile->f_ftype) {
257 	case SMB_FTYPE_DISK:
258 		node = sr->fid_ofile->f_node;
259 		rc = smb_query_fileinfo(sr, node, infolev, qinfo);
260 		break;
261 	case SMB_FTYPE_MESG_PIPE:
262 		opipe = sr->fid_ofile->f_pipe;
263 		rc = smb_query_pipeinfo(sr, opipe, infolev, qinfo);
264 		break;
265 	default:
266 		smbsr_error(sr, 0, ERRDOS, ERRbadfile);
267 		rc = -1;
268 		break;
269 	}
270 
271 	if (rc == 0)
272 		rc = smb_query_encode_response(sr, xa, infolev, qinfo);
273 
274 	kmem_free(qinfo, sizeof (smb_queryinfo_t));
275 	smbsr_release_file(sr);
276 	return (rc);
277 }
278 
279 /*
280  * smb_query_by_path
281  *
282  * Common code for querying file information by file name.
283  * Use the file name to identify the node object and request the
284  * smb_queryinfo_t data for that node.
285  *
286  * Path should be set in sr->arg.dirop.fqi.fq_path prior to
287  * calling smb_query_by_path.
288  *
289  * Querying attributes on a named pipe by name is an error and
290  * is handled in the calling functions so that they can return
291  * the appropriate error status code (which differs by caller).
292  */
293 static int
294 smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
295 {
296 	smb_queryinfo_t	*qinfo;
297 	smb_node_t	*node, *dnode;
298 	smb_pathname_t	*pn;
299 	int		rc;
300 
301 	/* VALID, but not yet supported */
302 	if (infolev == SMB_FILE_ACCESS_INFORMATION) {
303 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
304 		return (-1);
305 	}
306 
307 	pn = &sr->arg.dirop.fqi.fq_path;
308 	smb_pathname_init(sr, pn, pn->pn_path);
309 	if (!smb_pathname_validate(sr, pn))
310 		return (-1);
311 
312 	qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
313 
314 	rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
315 	    sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode,
316 	    qinfo->qi_name);
317 
318 	if (rc == 0) {
319 		rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
320 		    sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node);
321 		smb_node_release(dnode);
322 	}
323 
324 	if (rc != 0) {
325 		if (rc == ENOENT)
326 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
327 			    ERRDOS, ERROR_FILE_NOT_FOUND);
328 		else
329 			smbsr_errno(sr, rc);
330 
331 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
332 		return (-1);
333 	}
334 
335 	if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
336 		smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
337 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
338 		smb_node_release(node);
339 		return (-1);
340 	}
341 
342 	rc = smb_query_fileinfo(sr, node, infolev, qinfo);
343 	if (rc != 0) {
344 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
345 		smb_node_release(node);
346 		return (rc);
347 	}
348 
349 	/* If delete_on_close - NT_STATUS_DELETE_PENDING */
350 	if (qinfo->qi_delete_on_close) {
351 		smbsr_error(sr, NT_STATUS_DELETE_PENDING,
352 		    ERRDOS, ERROR_ACCESS_DENIED);
353 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
354 		smb_node_release(node);
355 		return (-1);
356 	}
357 
358 	rc = smb_query_encode_response(sr, xa, infolev, qinfo);
359 	kmem_free(qinfo, sizeof (smb_queryinfo_t));
360 	smb_node_release(node);
361 	return (rc);
362 }
363 
364 /*
365  * smb_size32
366  * Some responses only support 32 bit file sizes. If the file size
367  * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response.
368  */
369 static uint32_t
370 smb_size32(u_offset_t size)
371 {
372 	return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size);
373 }
374 
375 /*
376  * smb_query_encode_response
377  *
378  * Encode the data from smb_queryinfo_t into client response
379  */
380 int
381 smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa,
382     uint16_t infolev, smb_queryinfo_t *qinfo)
383 {
384 	uint16_t dattr;
385 	u_offset_t datasz, allocsz;
386 	uint32_t isdir;
387 
388 	dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
389 	datasz = qinfo->qi_attr.sa_vattr.va_size;
390 	allocsz = qinfo->qi_attr.sa_allocsz;
391 	isdir = ((dattr & FILE_ATTRIBUTE_DIRECTORY) != 0);
392 
393 	switch (infolev) {
394 	case SMB_QUERY_INFORMATION:
395 		(void) smbsr_encode_result(sr, 10, 0, "bwll10.w",
396 		    10,
397 		    dattr,
398 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
399 		    smb_size32(datasz),
400 		    0);
401 		break;
402 
403 	case SMB_QUERY_INFORMATION2:
404 		(void) smbsr_encode_result(sr, 11, 0, "byyyllww",
405 		    11,
406 		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
407 		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
408 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
409 		    smb_size32(datasz), smb_size32(allocsz), dattr, 0);
410 	break;
411 
412 	case SMB_FILE_ACCESS_INFORMATION:
413 		ASSERT(sr->fid_ofile);
414 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
415 		    sr->fid_ofile->f_granted_access);
416 		break;
417 
418 	case SMB_INFO_STANDARD:
419 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
420 		(void) smb_mbc_encodef(&xa->rep_data_mb,
421 		    ((sr->session->native_os == NATIVE_OS_WIN95) ?
422 		    "YYYllw" : "yyyllw"),
423 		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
424 		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
425 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
426 		    smb_size32(datasz), smb_size32(allocsz), dattr);
427 		break;
428 
429 	case SMB_INFO_QUERY_EA_SIZE:
430 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
431 		(void) smb_mbc_encodef(&xa->rep_data_mb,
432 		    ((sr->session->native_os == NATIVE_OS_WIN95) ?
433 		    "YYYllwl" : "yyyllwl"),
434 		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
435 		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
436 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
437 		    smb_size32(datasz), smb_size32(allocsz), dattr, 0);
438 		break;
439 
440 	case SMB_INFO_QUERY_ALL_EAS:
441 	case SMB_INFO_QUERY_EAS_FROM_LIST:
442 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
443 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
444 		break;
445 
446 	case SMB_INFO_IS_NAME_VALID:
447 		break;
448 
449 	case SMB_QUERY_FILE_BASIC_INFO:
450 	case SMB_FILE_BASIC_INFORMATION:
451 		/*
452 		 * NT includes 6 bytes (spec says 4) at the end of this
453 		 * response, which are required by NetBench 5.01.
454 		 */
455 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
456 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
457 		    &qinfo->qi_crtime,
458 		    &qinfo->qi_atime,
459 		    &qinfo->qi_mtime,
460 		    &qinfo->qi_ctime,
461 		    dattr);
462 		break;
463 
464 	case SMB_QUERY_FILE_STANDARD_INFO:
465 	case SMB_FILE_STANDARD_INFORMATION:
466 		/* 2-byte pad at end */
467 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
468 		(void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
469 		    (uint64_t)allocsz,
470 		    (uint64_t)datasz,
471 		    qinfo->qi_attr.sa_vattr.va_nlink,
472 		    qinfo->qi_delete_on_close,
473 		    (uint8_t)isdir);
474 		break;
475 
476 	case SMB_QUERY_FILE_EA_INFO:
477 	case SMB_FILE_EA_INFORMATION:
478 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
479 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
480 		break;
481 
482 	case SMB_QUERY_FILE_NAME_INFO:
483 	case SMB_FILE_NAME_INFORMATION:
484 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
485 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
486 		    qinfo->qi_namelen, qinfo->qi_name);
487 		break;
488 
489 	case SMB_QUERY_FILE_ALL_INFO:
490 	case SMB_FILE_ALL_INFORMATION:
491 		/*
492 		 * There is a 6-byte pad between Attributes and AllocationSize,
493 		 * and a 2-byte pad after the Directory field.
494 		 */
495 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
496 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
497 		    &qinfo->qi_crtime,
498 		    &qinfo->qi_atime,
499 		    &qinfo->qi_mtime,
500 		    &qinfo->qi_ctime,
501 		    dattr,
502 		    (uint64_t)allocsz,
503 		    (uint64_t)datasz,
504 		    qinfo->qi_attr.sa_vattr.va_nlink,
505 		    qinfo->qi_delete_on_close,
506 		    isdir,
507 		    0);
508 
509 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
510 		    sr, qinfo->qi_namelen, qinfo->qi_name);
511 		break;
512 
513 	case SMB_QUERY_FILE_ALT_NAME_INFO:
514 	case SMB_FILE_ALT_NAME_INFORMATION:
515 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
516 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
517 		    smb_wcequiv_strlen(qinfo->qi_shortname),
518 		    qinfo->qi_shortname);
519 		break;
520 
521 	case SMB_QUERY_FILE_STREAM_INFO:
522 	case SMB_FILE_STREAM_INFORMATION:
523 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
524 		smb_encode_stream_info(sr, xa, qinfo);
525 		break;
526 
527 	case SMB_QUERY_FILE_COMPRESSION_INFO:
528 	case SMB_FILE_COMPRESSION_INFORMATION:
529 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
530 		(void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
531 		    datasz, 0, 0, 0, 0);
532 		break;
533 
534 	case SMB_FILE_INTERNAL_INFORMATION:
535 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
536 		(void) smb_mbc_encodef(&xa->rep_data_mb, "q",
537 		    qinfo->qi_attr.sa_vattr.va_nodeid);
538 		break;
539 
540 	case SMB_FILE_NETWORK_OPEN_INFORMATION:
541 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
542 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTqql4.",
543 		    &qinfo->qi_crtime,
544 		    &qinfo->qi_atime,
545 		    &qinfo->qi_mtime,
546 		    &qinfo->qi_ctime,
547 		    (uint64_t)allocsz,
548 		    (uint64_t)datasz,
549 		    (uint32_t)dattr);
550 		break;
551 
552 	case SMB_FILE_ATTR_TAG_INFORMATION:
553 		/*
554 		 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
555 		 * second dword should be the reparse tag.  Otherwise
556 		 * the tag value should be set to zero.
557 		 * We don't support reparse points, so we set the tag
558 		 * to zero.
559 		 */
560 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
561 		(void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
562 		    (uint32_t)dattr, 0);
563 		break;
564 
565 	default:
566 		if ((infolev > 1000) && smb_query_passthru)
567 			smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
568 			    ERRDOS, ERROR_NOT_SUPPORTED);
569 		else
570 			smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
571 		return (-1);
572 	}
573 
574 	return (0);
575 }
576 
577 /*
578  * smb_encode_stream_info
579  *
580  * This function encodes the streams information.
581  * The following rules about how have been derived from observed NT
582  * behaviour.
583  *
584  * If the target is a file:
585  * 1. If there are no named streams, the response should still contain
586  *    an entry for the unnamed stream.
587  * 2. If there are named streams, the response should contain an entry
588  *    for the unnamed stream followed by the entries for the named
589  *    streams.
590  *
591  * If the target is a directory:
592  * 1. If there are no streams, the response is complete. Directories
593  *    do not report the unnamed stream.
594  * 2. If there are streams, the response should contain entries for
595  *    those streams but there should not be an entry for the unnamed
596  *    stream.
597  *
598  * Note that the stream name lengths exclude the null terminator but
599  * the field lengths (i.e. next offset calculations) need to include
600  * the null terminator and be padded to a multiple of 8 bytes. The
601  * last entry does not seem to need any padding.
602  *
603  * If an error is encountered when trying to read the stream entries
604  * (smb_odir_read_streaminfo) it is treated as if there are no [more]
605  * entries. The entries that have been read so far are returned and
606  * no error is reported.
607  *
608  * If the response buffer is not large enough to return all of the
609  * named stream entries, the entries that do fit are returned and
610  * a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset
611  * value in the last returned entry must be 0.
612  */
613 static void
614 smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo)
615 {
616 	char *stream_name;
617 	uint32_t next_offset;
618 	uint32_t stream_nlen;
619 	uint32_t pad;
620 	u_offset_t datasz, allocsz;
621 	boolean_t is_dir;
622 	smb_streaminfo_t *sinfo, *sinfo_next;
623 	int rc = 0;
624 	boolean_t done = B_FALSE;
625 	boolean_t eos = B_FALSE;
626 	uint16_t odid;
627 	smb_odir_t *od = NULL;
628 
629 	smb_node_t *fnode = qinfo->qi_node;
630 	smb_attr_t *attr = &qinfo->qi_attr;
631 
632 	ASSERT(fnode);
633 	if (SMB_IS_STREAM(fnode)) {
634 		fnode = fnode->n_unode;
635 		ASSERT(fnode);
636 	}
637 	ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
638 	ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
639 
640 	sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
641 	sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
642 	is_dir = ((attr->sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) != 0);
643 	datasz = attr->sa_vattr.va_size;
644 	allocsz = attr->sa_allocsz;
645 
646 	odid = smb_odir_openat(sr, fnode);
647 	if (odid != 0)
648 		od = smb_tree_lookup_odir(sr->tid_tree, odid);
649 	if (od != NULL)
650 		rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
651 
652 	if ((od == NULL) || (rc != 0) || (eos))
653 		done = B_TRUE;
654 
655 	/* If not a directory, encode an entry for the unnamed stream. */
656 	if (!is_dir) {
657 		stream_name = "::$DATA";
658 		stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
659 		next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen +
660 		    smb_ascii_or_unicode_null_len(sr);
661 
662 		/* Can unnamed stream fit in response buffer? */
663 		if (MBC_ROOM_FOR(&xa->rep_data_mb, next_offset) == 0) {
664 			done = B_TRUE;
665 			smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
666 			    ERRDOS, ERROR_MORE_DATA);
667 		} else {
668 			/* Can first named stream fit in rsp buffer? */
669 			if (!done && !smb_stream_fits(sr, xa, sinfo->si_name,
670 			    next_offset)) {
671 				done = B_TRUE;
672 				smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
673 				    ERRDOS, ERROR_MORE_DATA);
674 			}
675 
676 			if (done)
677 				next_offset = 0;
678 
679 			(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr,
680 			    next_offset, stream_nlen, datasz, allocsz,
681 			    stream_name);
682 		}
683 	}
684 
685 	/*
686 	 * If there is no next entry, or there is not enough space in
687 	 * the response buffer for the next entry, the next_offset and
688 	 * padding are 0.
689 	 */
690 	while (!done) {
691 		stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
692 		sinfo_next->si_name[0] = 0;
693 
694 		rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
695 		if ((rc != 0) || (eos)) {
696 			done = B_TRUE;
697 		} else {
698 			next_offset = SMB_STREAM_ENCODE_FIXED_SZ +
699 			    stream_nlen +
700 			    smb_ascii_or_unicode_null_len(sr);
701 			pad = smb_pad_align(next_offset, 8);
702 			next_offset += pad;
703 
704 			/* Can next named stream fit in response buffer? */
705 			if (!smb_stream_fits(sr, xa, sinfo_next->si_name,
706 			    next_offset)) {
707 				done = B_TRUE;
708 				smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
709 				    ERRDOS, ERROR_MORE_DATA);
710 			}
711 		}
712 
713 		if (done) {
714 			next_offset = 0;
715 			pad = 0;
716 		}
717 
718 		rc = smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
719 		    sr, next_offset, stream_nlen,
720 		    sinfo->si_size, sinfo->si_alloc_size,
721 		    sinfo->si_name, pad);
722 
723 		(void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
724 	}
725 
726 	kmem_free(sinfo, sizeof (smb_streaminfo_t));
727 	kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
728 	if (od) {
729 		smb_odir_close(od);
730 		smb_odir_release(od);
731 	}
732 }
733 
734 /*
735  * smb_stream_fits
736  *
737  * Check if the named stream entry can fit in the response buffer.
738  *
739  * Required space =
740  *	offset (size of current entry)
741  *	+ SMB_STREAM_ENCODE_FIXED_SIZE
742  *      + length of encoded stream name
743  *	+ length of null terminator
744  *	+ alignment padding
745  */
746 static boolean_t
747 smb_stream_fits(smb_request_t *sr, smb_xa_t *xa, char *name, uint32_t offset)
748 {
749 	uint32_t len, pad;
750 
751 	len = SMB_STREAM_ENCODE_FIXED_SZ +
752 	    smb_ascii_or_unicode_strlen(sr, name) +
753 	    smb_ascii_or_unicode_null_len(sr);
754 	pad = smb_pad_align(len, 8);
755 	len += pad;
756 
757 	return (MBC_ROOM_FOR(&xa->rep_data_mb, offset + len) != 0);
758 }
759 
760 /*
761  * smb_query_fileinfo
762  *
763  * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
764  * (This should become an smb_ofile / smb_node function.)
765  */
766 int
767 smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev,
768     smb_queryinfo_t *qinfo)
769 {
770 	int rc = 0;
771 
772 	/* If shortname required but not supported -> OBJECT_NAME_NOT_FOUND */
773 	if ((infolev == SMB_QUERY_FILE_ALT_NAME_INFO) ||
774 	    (infolev == SMB_FILE_ALT_NAME_INFORMATION)) {
775 		if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_SHORTNAMES)) {
776 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
777 			    ERRDOS, ERROR_FILE_NOT_FOUND);
778 			return (-1);
779 		}
780 	}
781 
782 	(void) bzero(qinfo, sizeof (smb_queryinfo_t));
783 
784 	if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) {
785 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
786 		    ERRDOS, ERROR_INTERNAL_ERROR);
787 		return (-1);
788 	}
789 
790 	qinfo->qi_node = node;
791 	qinfo->qi_delete_on_close =
792 	    (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
793 
794 	/*
795 	 * The number of links reported should be the number of
796 	 * non-deleted links. Thus if delete_on_close is set,
797 	 * decrement the link count.
798 	 */
799 	if (qinfo->qi_delete_on_close &&
800 	    qinfo->qi_attr.sa_vattr.va_nlink > 0) {
801 		--(qinfo->qi_attr.sa_vattr.va_nlink);
802 	}
803 
804 	/*
805 	 * populate name, namelen and shortname ONLY for the information
806 	 * levels that require these fields
807 	 */
808 	switch (infolev) {
809 	case SMB_QUERY_FILE_ALL_INFO:
810 	case SMB_FILE_ALL_INFORMATION:
811 		rc = smb_query_pathname(sr, node, B_TRUE, qinfo);
812 		break;
813 	case SMB_QUERY_FILE_NAME_INFO:
814 	case SMB_FILE_NAME_INFORMATION:
815 		rc = smb_query_pathname(sr, node, B_FALSE, qinfo);
816 		break;
817 	case SMB_QUERY_FILE_ALT_NAME_INFO:
818 	case SMB_FILE_ALT_NAME_INFORMATION:
819 		smb_query_shortname(node, qinfo);
820 		break;
821 	default:
822 		break;
823 	}
824 
825 	if (rc != 0) {
826 		smbsr_errno(sr, rc);
827 		return (-1);
828 	}
829 	return (0);
830 }
831 
832 /*
833  * smb_query_pathname
834  *
835  * Determine the absolute pathname of 'node' within the share.
836  * For some levels (e.g. ALL_INFO) the pathname should include the
837  * sharename for others (e.g. NAME_INFO) the pathname should be
838  * relative to the share.
839  * For example if the node represents file "test1.txt" in directory
840  * "dir1" on share "share1"
841  * - if include_share is TRUE the pathname would be: \share1\dir1\test1.txt
842  * - if include_share is FALSE the pathname would be: \dir1\test1.txt
843  *
844  * For some reason NT will not show the security tab in the root
845  * directory of a mapped drive unless the filename length is greater
846  * than one. So if the length is 1 we set it to 2 to persuade NT to
847  * show the tab. It should be safe because of the null terminator.
848  */
849 static int
850 smb_query_pathname(smb_request_t *sr, smb_node_t *node, boolean_t include_share,
851     smb_queryinfo_t *qinfo)
852 {
853 	smb_tree_t *tree = sr->tid_tree;
854 	char *buf = qinfo->qi_name;
855 	size_t buflen = MAXPATHLEN;
856 	size_t len;
857 	int rc;
858 
859 	if (include_share) {
860 		len = snprintf(buf, buflen, "\\%s", tree->t_sharename);
861 		if (len == (buflen - 1))
862 			return (ENAMETOOLONG);
863 
864 		buf += len;
865 		buflen -= len;
866 	}
867 
868 	if (node == tree->t_snode) {
869 		if (!include_share)
870 			(void) strlcpy(buf, "\\", buflen);
871 		return (0);
872 	}
873 
874 	rc =  smb_node_getshrpath(node, tree, buf, buflen);
875 	if (rc == 0) {
876 		qinfo->qi_namelen =
877 		    smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
878 		if (qinfo->qi_namelen == 1)
879 			qinfo->qi_namelen = 2;
880 	}
881 	return (rc);
882 }
883 
884 /*
885  * smb_query_shortname
886  *
887  * If the node is a named stream, use its associated
888  * unnamed stream name to determine the shortname.
889  * If a shortname is required (smb_needs_mangle()), generate it
890  * using smb_mangle(), otherwise, convert the original name to
891  * upper-case and return it as the alternative name.
892  */
893 static void
894 smb_query_shortname(smb_node_t *node, smb_queryinfo_t *qinfo)
895 {
896 	char *namep;
897 
898 	if (SMB_IS_STREAM(node))
899 		namep = node->n_unode->od_name;
900 	else
901 		namep = node->od_name;
902 
903 	if (smb_needs_mangled(namep)) {
904 		smb_mangle(namep, qinfo->qi_attr.sa_vattr.va_nodeid,
905 		    qinfo->qi_shortname, SMB_SHORTNAMELEN);
906 	} else {
907 		(void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
908 		(void) smb_strupr(qinfo->qi_shortname);
909 	}
910 }
911 
912 /*
913  * smb_query_pipeinfo
914  *
915  * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE
916  * (This should become an smb_opipe function.)
917  */
918 static int
919 smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev,
920     smb_queryinfo_t *qinfo)
921 {
922 	char *namep = opipe->p_name;
923 
924 	(void) bzero(qinfo, sizeof (smb_queryinfo_t));
925 	qinfo->qi_node = NULL;
926 	qinfo->qi_attr.sa_vattr.va_nlink = 1;
927 	qinfo->qi_delete_on_close = 1;
928 
929 	if ((infolev == SMB_INFO_STANDARD) ||
930 	    (infolev == SMB_INFO_QUERY_EA_SIZE) ||
931 	    (infolev == SMB_QUERY_INFORMATION2)) {
932 		qinfo->qi_attr.sa_dosattr = 0;
933 	} else {
934 		qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL;
935 	}
936 
937 	/* If the leading \ is missing from the pipe name, add it. */
938 	if (*namep != '\\')
939 		(void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
940 	else
941 		(void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
942 
943 	qinfo->qi_namelen=
944 	    smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
945 
946 	return (0);
947 }
948 
949 /*
950  * smb_query_pipe_valid_infolev
951  *
952  * If the infolev is not valid for a message pipe, the error
953  * information is set in sr and B_FALSE is returned.
954  * Otherwise, returns B_TRUE.
955  */
956 static boolean_t
957 smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev)
958 {
959 	switch (infolev) {
960 	case SMB_INFO_QUERY_ALL_EAS:
961 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
962 		    ERRDOS, ERROR_ACCESS_DENIED);
963 		return (B_FALSE);
964 
965 	case SMB_QUERY_FILE_ALT_NAME_INFO:
966 	case SMB_FILE_ALT_NAME_INFORMATION:
967 	case SMB_QUERY_FILE_STREAM_INFO:
968 	case SMB_FILE_STREAM_INFORMATION:
969 	case SMB_QUERY_FILE_COMPRESSION_INFO:
970 	case SMB_FILE_COMPRESSION_INFORMATION:
971 	case SMB_FILE_NETWORK_OPEN_INFORMATION:
972 	case SMB_FILE_ATTR_TAG_INFORMATION:
973 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
974 		    ERRDOS, ERROR_INVALID_PARAMETER);
975 		return (B_FALSE);
976 	}
977 
978 	return (B_TRUE);
979 }
980