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