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
80static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
81static int smb_query_by_path(smb_request_t *, smb_xa_t *, uint16_t);
82
83static int smb_query_fileinfo(smb_request_t *, smb_node_t *,
84    uint16_t, smb_queryinfo_t *);
85static int smb_query_pipeinfo(smb_request_t *, smb_opipe_t *,
86    uint16_t, smb_queryinfo_t *);
87static boolean_t smb_query_pipe_valid_infolev(smb_request_t *, uint16_t);
88
89static int smb_query_encode_response(smb_request_t *, smb_xa_t *,
90    uint16_t, smb_queryinfo_t *);
91static boolean_t smb_stream_fits(smb_request_t *, mbuf_chain_t *,
92    char *, uint32_t);
93static int smb_query_pathname(smb_request_t *, smb_node_t *, boolean_t,
94    smb_queryinfo_t *);
95
96int smb_query_passthru;
97
98/*
99 * smb_com_trans2_query_file_information
100 */
101smb_sdrc_t
102smb_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 */
119smb_sdrc_t
120smb_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 */
144smb_sdrc_t
145smb_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
157void
158smb_post_query_information(smb_request_t *sr)
159{
160	DTRACE_SMB_DONE(op__QueryInformation, smb_request_t *, sr);
161}
162
163smb_sdrc_t
164smb_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 */
183smb_sdrc_t
184smb_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
194void
195smb_post_query_information2(smb_request_t *sr)
196{
197	DTRACE_SMB_DONE(op__QueryInformation2, smb_request_t *, sr);
198}
199
200smb_sdrc_t
201smb_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 */
218static int
219smb_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 */
285static int
286smb_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 */
372static uint32_t
373smb_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 */
383int
384smb_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 */
617uint32_t
618smb_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 */
760static boolean_t
761smb_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 */
781int
782smb_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 */
869static int
870smb_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 */
913void
914smb_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 */
938static int
939smb_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 */
977static boolean_t
978smb_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