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