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