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