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