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