xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c (revision 49b7860084dbba18bc00b29413d6182197f9fe93)
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 2013 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 #include <smbsrv/smb_kproto.h>
28 #include <smbsrv/smb_vops.h>
29 #include <smbsrv/smb_fsops.h>
30 
31 /*
32  * Trans2 Query File/Path Information Levels:
33  *
34  * SMB_INFO_STANDARD
35  * SMB_INFO_QUERY_EA_SIZE
36  * SMB_INFO_QUERY_EAS_FROM_LIST
37  * SMB_INFO_QUERY_ALL_EAS - not valid for pipes
38  * SMB_INFO_IS_NAME_VALID - only valid when query is by path
39  *
40  * SMB_QUERY_FILE_BASIC_INFO
41  * SMB_QUERY_FILE_STANDARD_INFO
42  * SMB_QUERY_FILE_EA_INFO
43  * SMB_QUERY_FILE_NAME_INFO
44  * SMB_QUERY_FILE_ALL_INFO
45  * SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes
46  * SMB_QUERY_FILE_STREAM_INFO - not valid for pipes
47  * SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes
48  *
49  * Supported Passthrough levels:
50  * SMB_FILE_BASIC_INFORMATION
51  * SMB_FILE_STANDARD_INFORMATION
52  * SMB_FILE_INTERNAL_INFORMATION
53  * SMB_FILE_EA_INFORMATION
54  * SMB_FILE_ACCESS_INFORMATION - not yet supported when query by path
55  * SMB_FILE_NAME_INFORMATION
56  * SMB_FILE_ALL_INFORMATION
57  * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
58  * SMB_FILE_STREAM_INFORMATION - not valid for pipes
59  * SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes
60  * SMB_FILE_NETWORK_OPEN_INFORMATION - not valid for pipes
61  * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes
62  *
63  * Internal levels representing non trans2 requests
64  * SMB_QUERY_INFORMATION
65  * SMB_QUERY_INFORMATION2
66  */
67 
68 /*
69  * SMB_STREAM_ENCODE_FIXED_SIZE:
70  * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
71  */
72 #define	SMB_STREAM_ENCODE_FIXED_SZ	24
73 
74 /* See smb_queryinfo_t in smb_ktypes.h */
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 boolean_t smb_stream_fits(smb_request_t *, mbuf_chain_t *,
92     char *, uint32_t);
93 static int smb_query_pathname(smb_request_t *, smb_node_t *, boolean_t,
94     smb_queryinfo_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, ERROR_INVALID_LEVEL);
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 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
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 	/*
295 	 * The function smb_query_fileinfo is used here and in
296 	 * smb_query_by_fid.  That common function needs this
297 	 * one to call it with a NULL fid_ofile, so check here.
298 	 * Note: smb_query_by_fid enforces the opposite.
299 	 *
300 	 * In theory we could ASSERT this, but whether we have
301 	 * fid_ofile set here depends on what sequence of SMB
302 	 * commands the client has sent in this message, so
303 	 * let's be cautious and handle it as an error.
304 	 */
305 	if (sr->fid_ofile != NULL)
306 		return (-1);
307 
308 
309 	/* VALID, but not yet supported */
310 	if (infolev == SMB_FILE_ACCESS_INFORMATION) {
311 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
312 		return (-1);
313 	}
314 
315 	pn = &sr->arg.dirop.fqi.fq_path;
316 	smb_pathname_init(sr, pn, pn->pn_path);
317 	if (!smb_pathname_validate(sr, pn))
318 		return (-1);
319 
320 	qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
321 
322 	rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
323 	    sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode,
324 	    qinfo->qi_name);
325 
326 	if (rc == 0) {
327 		rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
328 		    sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node);
329 		smb_node_release(dnode);
330 	}
331 
332 	if (rc != 0) {
333 		if (rc == ENOENT)
334 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
335 			    ERRDOS, ERROR_FILE_NOT_FOUND);
336 		else
337 			smbsr_errno(sr, rc);
338 
339 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
340 		return (-1);
341 	}
342 
343 	if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
344 		smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
345 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
346 		smb_node_release(node);
347 		return (-1);
348 	}
349 
350 	rc = smb_query_fileinfo(sr, node, infolev, qinfo);
351 	if (rc != 0) {
352 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
353 		smb_node_release(node);
354 		return (rc);
355 	}
356 
357 	/* If delete_on_close - NT_STATUS_DELETE_PENDING */
358 	if (qinfo->qi_delete_on_close) {
359 		smbsr_error(sr, NT_STATUS_DELETE_PENDING,
360 		    ERRDOS, ERROR_ACCESS_DENIED);
361 		kmem_free(qinfo, sizeof (smb_queryinfo_t));
362 		smb_node_release(node);
363 		return (-1);
364 	}
365 
366 	rc = smb_query_encode_response(sr, xa, infolev, qinfo);
367 	kmem_free(qinfo, sizeof (smb_queryinfo_t));
368 	smb_node_release(node);
369 	return (rc);
370 }
371 
372 /*
373  * smb_size32
374  * Some responses only support 32 bit file sizes. If the file size
375  * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response.
376  */
377 static uint32_t
378 smb_size32(u_offset_t size)
379 {
380 	return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size);
381 }
382 
383 /*
384  * smb_query_encode_response
385  *
386  * Encode the data from smb_queryinfo_t into client response
387  */
388 int
389 smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa,
390     uint16_t infolev, smb_queryinfo_t *qinfo)
391 {
392 	uint16_t dattr;
393 	u_offset_t datasz, allocsz;
394 	uint32_t status;
395 
396 	dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
397 	datasz = qinfo->qi_attr.sa_vattr.va_size;
398 	allocsz = qinfo->qi_attr.sa_allocsz;
399 
400 	switch (infolev) {
401 	case SMB_QUERY_INFORMATION:
402 		(void) smbsr_encode_result(sr, 10, 0, "bwll10.w",
403 		    10,
404 		    dattr,
405 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
406 		    smb_size32(datasz),
407 		    0);
408 		break;
409 
410 	case SMB_QUERY_INFORMATION2:
411 		(void) smbsr_encode_result(sr, 11, 0, "byyyllww",
412 		    11,
413 		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
414 		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
415 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
416 		    smb_size32(datasz), smb_size32(allocsz), dattr, 0);
417 	break;
418 
419 	case SMB_FILE_ACCESS_INFORMATION:
420 		ASSERT(sr->fid_ofile);
421 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
422 		    sr->fid_ofile->f_granted_access);
423 		break;
424 
425 	case SMB_INFO_STANDARD:
426 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
427 		(void) smb_mbc_encodef(&xa->rep_data_mb,
428 		    ((sr->session->native_os == NATIVE_OS_WIN95) ?
429 		    "YYYllw" : "yyyllw"),
430 		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
431 		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
432 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
433 		    smb_size32(datasz), smb_size32(allocsz), dattr);
434 		break;
435 
436 	case SMB_INFO_QUERY_EA_SIZE:
437 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
438 		(void) smb_mbc_encodef(&xa->rep_data_mb,
439 		    ((sr->session->native_os == NATIVE_OS_WIN95) ?
440 		    "YYYllwl" : "yyyllwl"),
441 		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
442 		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
443 		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
444 		    smb_size32(datasz), smb_size32(allocsz), dattr, 0);
445 		break;
446 
447 	case SMB_INFO_QUERY_ALL_EAS:
448 	case SMB_INFO_QUERY_EAS_FROM_LIST:
449 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
450 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
451 		break;
452 
453 	case SMB_INFO_IS_NAME_VALID:
454 		break;
455 
456 	case SMB_QUERY_FILE_BASIC_INFO:
457 	case SMB_FILE_BASIC_INFORMATION:
458 		/*
459 		 * NT includes 6 bytes (spec says 4) at the end of this
460 		 * response, which are required by NetBench 5.01.
461 		 */
462 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
463 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
464 		    &qinfo->qi_crtime,
465 		    &qinfo->qi_atime,
466 		    &qinfo->qi_mtime,
467 		    &qinfo->qi_ctime,
468 		    dattr);
469 		break;
470 
471 	case SMB_QUERY_FILE_STANDARD_INFO:
472 	case SMB_FILE_STANDARD_INFORMATION:
473 		/* 2-byte pad at end */
474 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
475 		(void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
476 		    (uint64_t)allocsz,
477 		    (uint64_t)datasz,
478 		    qinfo->qi_attr.sa_vattr.va_nlink,
479 		    qinfo->qi_delete_on_close,
480 		    qinfo->qi_isdir);
481 		break;
482 
483 	case SMB_QUERY_FILE_EA_INFO:
484 	case SMB_FILE_EA_INFORMATION:
485 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
486 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
487 		break;
488 
489 	case SMB_QUERY_FILE_NAME_INFO:
490 	case SMB_FILE_NAME_INFORMATION:
491 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
492 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
493 		    qinfo->qi_namelen, qinfo->qi_name);
494 		break;
495 
496 	case SMB_QUERY_FILE_ALL_INFO:
497 	case SMB_FILE_ALL_INFORMATION:
498 		/*
499 		 * There is a 6-byte pad between Attributes and AllocationSize,
500 		 * and a 2-byte pad after the Directory field.
501 		 */
502 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
503 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
504 		    &qinfo->qi_crtime,
505 		    &qinfo->qi_atime,
506 		    &qinfo->qi_mtime,
507 		    &qinfo->qi_ctime,
508 		    dattr,
509 		    (uint64_t)allocsz,
510 		    (uint64_t)datasz,
511 		    qinfo->qi_attr.sa_vattr.va_nlink,
512 		    qinfo->qi_delete_on_close,
513 		    qinfo->qi_isdir,
514 		    0);
515 
516 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
517 		    sr, qinfo->qi_namelen, qinfo->qi_name);
518 		break;
519 
520 	case SMB_QUERY_FILE_ALT_NAME_INFO:
521 	case SMB_FILE_ALT_NAME_INFORMATION:
522 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
523 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
524 		    smb_wcequiv_strlen(qinfo->qi_shortname),
525 		    qinfo->qi_shortname);
526 		break;
527 
528 	case SMB_QUERY_FILE_STREAM_INFO:
529 	case SMB_FILE_STREAM_INFORMATION:
530 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
531 		status = smb_query_stream_info(sr, &xa->rep_data_mb, qinfo);
532 		if (status)
533 			smbsr_status(sr, status, 0, 0);
534 		break;
535 
536 	case SMB_QUERY_FILE_COMPRESSION_INFO:
537 	case SMB_FILE_COMPRESSION_INFORMATION:
538 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
539 		(void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
540 		    datasz, 0, 0, 0, 0);
541 		break;
542 
543 	case SMB_FILE_INTERNAL_INFORMATION:
544 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
545 		(void) smb_mbc_encodef(&xa->rep_data_mb, "q",
546 		    qinfo->qi_attr.sa_vattr.va_nodeid);
547 		break;
548 
549 	case SMB_FILE_NETWORK_OPEN_INFORMATION:
550 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
551 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTqql4.",
552 		    &qinfo->qi_crtime,
553 		    &qinfo->qi_atime,
554 		    &qinfo->qi_mtime,
555 		    &qinfo->qi_ctime,
556 		    (uint64_t)allocsz,
557 		    (uint64_t)datasz,
558 		    (uint32_t)dattr);
559 		break;
560 
561 	case SMB_FILE_ATTR_TAG_INFORMATION:
562 		/*
563 		 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
564 		 * second dword should be the reparse tag.  Otherwise
565 		 * the tag value should be set to zero.
566 		 * We don't support reparse points, so we set the tag
567 		 * to zero.
568 		 */
569 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
570 		(void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
571 		    (uint32_t)dattr, 0);
572 		break;
573 
574 	default:
575 		if ((infolev > 1000) && smb_query_passthru)
576 			smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
577 			    ERRDOS, ERROR_NOT_SUPPORTED);
578 		else
579 			smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
580 		return (-1);
581 	}
582 
583 	return (0);
584 }
585 
586 /*
587  * smb_encode_stream_info
588  *
589  * This function encodes the streams information.
590  * The following rules about how have been derived from observed NT
591  * behaviour.
592  *
593  * If the target is a file:
594  * 1. If there are no named streams, the response should still contain
595  *    an entry for the unnamed stream.
596  * 2. If there are named streams, the response should contain an entry
597  *    for the unnamed stream followed by the entries for the named
598  *    streams.
599  *
600  * If the target is a directory:
601  * 1. If there are no streams, the response is complete. Directories
602  *    do not report the unnamed stream.
603  * 2. If there are streams, the response should contain entries for
604  *    those streams but there should not be an entry for the unnamed
605  *    stream.
606  *
607  * Note that the stream name lengths exclude the null terminator but
608  * the field lengths (i.e. next offset calculations) need to include
609  * the null terminator and be padded to a multiple of 8 bytes. The
610  * last entry does not seem to need any padding.
611  *
612  * If an error is encountered when trying to read the stream entries
613  * (smb_odir_read_streaminfo) it is treated as if there are no [more]
614  * entries. The entries that have been read so far are returned and
615  * no error is reported.
616  *
617  * If the response buffer is not large enough to return all of the
618  * named stream entries, the entries that do fit are returned and
619  * a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset
620  * value in the last returned entry must be 0.
621  */
622 uint32_t
623 smb_query_stream_info(smb_request_t *sr, mbuf_chain_t *mbc,
624 	smb_queryinfo_t *qinfo)
625 {
626 	char *stream_name;
627 	uint32_t next_offset;
628 	uint32_t stream_nlen;
629 	uint32_t pad;
630 	u_offset_t datasz, allocsz;
631 	smb_streaminfo_t *sinfo, *sinfo_next;
632 	int rc = 0;
633 	boolean_t done = B_FALSE;
634 	boolean_t eos = B_FALSE;
635 	smb_odir_t *od = NULL;
636 	uint32_t status = 0;
637 
638 	smb_node_t *fnode = qinfo->qi_node;
639 	smb_attr_t *attr = &qinfo->qi_attr;
640 
641 	ASSERT(fnode);
642 	if (SMB_IS_STREAM(fnode)) {
643 		fnode = fnode->n_unode;
644 		ASSERT(fnode);
645 	}
646 	ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
647 	ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
648 
649 	sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
650 	sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
651 	datasz = attr->sa_vattr.va_size;
652 	allocsz = attr->sa_allocsz;
653 
654 	status = smb_odir_openat(sr, fnode, &od);
655 	switch (status) {
656 	case 0:
657 		break;
658 	case NT_STATUS_NO_SUCH_FILE:
659 	case NT_STATUS_NOT_SUPPORTED:
660 		/* No streams. */
661 		done = B_TRUE;
662 		break;
663 	default:
664 		return (status);
665 	}
666 
667 	if (!done) {
668 		rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
669 		if ((rc != 0) || (eos))
670 			done = B_TRUE;
671 	}
672 
673 	/* If not a directory, encode an entry for the unnamed stream. */
674 	if (qinfo->qi_isdir == 0) {
675 		stream_name = "::$DATA";
676 		stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
677 		next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen +
678 		    smb_ascii_or_unicode_null_len(sr);
679 
680 		/* Can unnamed stream fit in response buffer? */
681 		if (MBC_ROOM_FOR(mbc, next_offset) == 0) {
682 			done = B_TRUE;
683 			status = NT_STATUS_BUFFER_OVERFLOW;
684 		} else {
685 			/* Can first named stream fit in rsp buffer? */
686 			if (!done && !smb_stream_fits(sr, mbc, sinfo->si_name,
687 			    next_offset)) {
688 				done = B_TRUE;
689 				status = NT_STATUS_BUFFER_OVERFLOW;
690 			}
691 
692 			if (done)
693 				next_offset = 0;
694 
695 			(void) smb_mbc_encodef(mbc, "%llqqu", sr,
696 			    next_offset, stream_nlen, datasz, allocsz,
697 			    stream_name);
698 		}
699 	}
700 
701 	/*
702 	 * If there is no next entry, or there is not enough space in
703 	 * the response buffer for the next entry, the next_offset and
704 	 * padding are 0.
705 	 */
706 	while (!done) {
707 		stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
708 		sinfo_next->si_name[0] = 0;
709 
710 		rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
711 		if ((rc != 0) || (eos)) {
712 			done = B_TRUE;
713 		} else {
714 			next_offset = SMB_STREAM_ENCODE_FIXED_SZ +
715 			    stream_nlen +
716 			    smb_ascii_or_unicode_null_len(sr);
717 			pad = smb_pad_align(next_offset, 8);
718 			next_offset += pad;
719 
720 			/* Can next named stream fit in response buffer? */
721 			if (!smb_stream_fits(sr, mbc, sinfo_next->si_name,
722 			    next_offset)) {
723 				done = B_TRUE;
724 				status = NT_STATUS_BUFFER_OVERFLOW;
725 			}
726 		}
727 
728 		if (done) {
729 			next_offset = 0;
730 			pad = 0;
731 		}
732 
733 		(void) smb_mbc_encodef(mbc, "%llqqu#.",
734 		    sr, next_offset, stream_nlen,
735 		    sinfo->si_size, sinfo->si_alloc_size,
736 		    sinfo->si_name, pad);
737 
738 		(void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
739 	}
740 
741 	kmem_free(sinfo, sizeof (smb_streaminfo_t));
742 	kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
743 	if (od) {
744 		smb_odir_close(od);
745 		smb_odir_release(od);
746 	}
747 
748 	return (status);
749 }
750 
751 /*
752  * smb_stream_fits
753  *
754  * Check if the named stream entry can fit in the response buffer.
755  *
756  * Required space =
757  *	offset (size of current entry)
758  *	+ SMB_STREAM_ENCODE_FIXED_SIZE
759  *      + length of encoded stream name
760  *	+ length of null terminator
761  *	+ alignment padding
762  */
763 static boolean_t
764 smb_stream_fits(smb_request_t *sr, mbuf_chain_t *mbc,
765 	char *name, uint32_t offset)
766 {
767 	uint32_t len, pad;
768 
769 	len = SMB_STREAM_ENCODE_FIXED_SZ +
770 	    smb_ascii_or_unicode_strlen(sr, name) +
771 	    smb_ascii_or_unicode_null_len(sr);
772 	pad = smb_pad_align(len, 8);
773 	len += pad;
774 
775 	return (MBC_ROOM_FOR(mbc, offset + len) != 0);
776 }
777 
778 /*
779  * smb_query_fileinfo
780  *
781  * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
782  * (This should become an smb_ofile / smb_node function.)
783  */
784 int
785 smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev,
786     smb_queryinfo_t *qinfo)
787 {
788 	int rc = 0;
789 
790 	/* If shortname required but not supported -> OBJECT_NAME_NOT_FOUND */
791 	if ((infolev == SMB_QUERY_FILE_ALT_NAME_INFO) ||
792 	    (infolev == SMB_FILE_ALT_NAME_INFORMATION)) {
793 		if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_SHORTNAMES)) {
794 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
795 			    ERRDOS, ERROR_FILE_NOT_FOUND);
796 			return (-1);
797 		}
798 	}
799 
800 	(void) bzero(qinfo, sizeof (smb_queryinfo_t));
801 
802 	/* See: smb_query_encode_response */
803 	qinfo->qi_attr.sa_mask = SMB_AT_ALL;
804 	rc = smb_node_getattr(sr, node, sr->user_cr, sr->fid_ofile,
805 	    &qinfo->qi_attr);
806 	if (rc != 0) {
807 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
808 		    ERRDOS, ERROR_INTERNAL_ERROR);
809 		return (-1);
810 	}
811 
812 	qinfo->qi_node = node;
813 	qinfo->qi_delete_on_close =
814 	    (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
815 	qinfo->qi_isdir = smb_node_is_dir(node);
816 
817 	/*
818 	 * The number of links reported should be the number of
819 	 * non-deleted links. Thus if delete_on_close is set,
820 	 * decrement the link count.
821 	 */
822 	if (qinfo->qi_delete_on_close &&
823 	    qinfo->qi_attr.sa_vattr.va_nlink > 0) {
824 		--(qinfo->qi_attr.sa_vattr.va_nlink);
825 	}
826 
827 	/*
828 	 * populate name, namelen and shortname ONLY for the information
829 	 * levels that require these fields
830 	 */
831 	switch (infolev) {
832 	case SMB_QUERY_FILE_ALL_INFO:
833 	case SMB_FILE_ALL_INFORMATION:
834 		rc = smb_query_pathname(sr, node, B_TRUE, qinfo);
835 		break;
836 	case SMB_QUERY_FILE_NAME_INFO:
837 	case SMB_FILE_NAME_INFORMATION:
838 		rc = smb_query_pathname(sr, node, B_FALSE, qinfo);
839 		break;
840 	case SMB_QUERY_FILE_ALT_NAME_INFO:
841 	case SMB_FILE_ALT_NAME_INFORMATION:
842 		smb_query_shortname(node, qinfo);
843 		break;
844 	default:
845 		break;
846 	}
847 
848 	if (rc != 0) {
849 		smbsr_errno(sr, rc);
850 		return (-1);
851 	}
852 	return (0);
853 }
854 
855 /*
856  * smb_query_pathname
857  *
858  * Determine the absolute pathname of 'node' within the share.
859  * For some levels (e.g. ALL_INFO) the pathname should include the
860  * sharename for others (e.g. NAME_INFO) the pathname should be
861  * relative to the share.
862  * For example if the node represents file "test1.txt" in directory
863  * "dir1" on share "share1"
864  * - if include_share is TRUE the pathname would be: \share1\dir1\test1.txt
865  * - if include_share is FALSE the pathname would be: \dir1\test1.txt
866  *
867  * For some reason NT will not show the security tab in the root
868  * directory of a mapped drive unless the filename length is greater
869  * than one. So if the length is 1 we set it to 2 to persuade NT to
870  * show the tab. It should be safe because of the null terminator.
871  */
872 static int
873 smb_query_pathname(smb_request_t *sr, smb_node_t *node, boolean_t include_share,
874     smb_queryinfo_t *qinfo)
875 {
876 	smb_tree_t *tree = sr->tid_tree;
877 	char *buf = qinfo->qi_name;
878 	size_t buflen = MAXPATHLEN;
879 	size_t len;
880 	int rc;
881 
882 	if (include_share) {
883 		len = snprintf(buf, buflen, "\\%s", tree->t_sharename);
884 		if (len == (buflen - 1))
885 			return (ENAMETOOLONG);
886 
887 		buf += len;
888 		buflen -= len;
889 	}
890 
891 	if (node == tree->t_snode) {
892 		if (!include_share)
893 			(void) strlcpy(buf, "\\", buflen);
894 		return (0);
895 	}
896 
897 	rc =  smb_node_getshrpath(node, tree, buf, buflen);
898 	if (rc == 0) {
899 		qinfo->qi_namelen =
900 		    smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
901 		if (qinfo->qi_namelen == 1)
902 			qinfo->qi_namelen = 2;
903 	}
904 	return (rc);
905 }
906 
907 /*
908  * smb_query_shortname
909  *
910  * If the node is a named stream, use its associated
911  * unnamed stream name to determine the shortname.
912  * If a shortname is required (smb_needs_mangle()), generate it
913  * using smb_mangle(), otherwise, convert the original name to
914  * upper-case and return it as the alternative name.
915  */
916 void
917 smb_query_shortname(smb_node_t *node, smb_queryinfo_t *qinfo)
918 {
919 	char *namep;
920 
921 	if (SMB_IS_STREAM(node))
922 		namep = node->n_unode->od_name;
923 	else
924 		namep = node->od_name;
925 
926 	if (smb_needs_mangled(namep)) {
927 		smb_mangle(namep, qinfo->qi_attr.sa_vattr.va_nodeid,
928 		    qinfo->qi_shortname, SMB_SHORTNAMELEN);
929 	} else {
930 		(void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
931 		(void) smb_strupr(qinfo->qi_shortname);
932 	}
933 }
934 
935 /*
936  * smb_query_pipeinfo
937  *
938  * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE
939  * (This should become an smb_opipe function.)
940  */
941 static int
942 smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev,
943     smb_queryinfo_t *qinfo)
944 {
945 	char *namep = opipe->p_name;
946 
947 	(void) bzero(qinfo, sizeof (smb_queryinfo_t));
948 	qinfo->qi_node = NULL;
949 	qinfo->qi_attr.sa_vattr.va_nlink = 1;
950 	qinfo->qi_delete_on_close = 1;
951 	qinfo->qi_isdir = 0;
952 
953 	if ((infolev == SMB_INFO_STANDARD) ||
954 	    (infolev == SMB_INFO_QUERY_EA_SIZE) ||
955 	    (infolev == SMB_QUERY_INFORMATION2)) {
956 		qinfo->qi_attr.sa_dosattr = 0;
957 	} else {
958 		qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL;
959 	}
960 
961 	/* If the leading \ is missing from the pipe name, add it. */
962 	if (*namep != '\\')
963 		(void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
964 	else
965 		(void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
966 
967 	qinfo->qi_namelen=
968 	    smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
969 
970 	return (0);
971 }
972 
973 /*
974  * smb_query_pipe_valid_infolev
975  *
976  * If the infolev is not valid for a message pipe, the error
977  * information is set in sr and B_FALSE is returned.
978  * Otherwise, returns B_TRUE.
979  */
980 static boolean_t
981 smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev)
982 {
983 	switch (infolev) {
984 	case SMB_INFO_QUERY_ALL_EAS:
985 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
986 		    ERRDOS, ERROR_ACCESS_DENIED);
987 		return (B_FALSE);
988 
989 	case SMB_QUERY_FILE_ALT_NAME_INFO:
990 	case SMB_FILE_ALT_NAME_INFORMATION:
991 	case SMB_QUERY_FILE_STREAM_INFO:
992 	case SMB_FILE_STREAM_INFORMATION:
993 	case SMB_QUERY_FILE_COMPRESSION_INFO:
994 	case SMB_FILE_COMPRESSION_INFORMATION:
995 	case SMB_FILE_NETWORK_OPEN_INFORMATION:
996 	case SMB_FILE_ATTR_TAG_INFORMATION:
997 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
998 		    ERRDOS, ERROR_INVALID_PARAMETER);
999 		return (B_FALSE);
1000 	}
1001 
1002 	return (B_TRUE);
1003 }
1004