1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22cb174861Sjoyce mcintosh  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*dfa42fabSMatt Barden  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
27da6c28aaSamw #include <smbsrv/smb_fsops.h>
28da6c28aaSamw 
292c2961f8Sjose borrego /*
302c2961f8Sjose borrego  * The maximum number of bytes to return from SMB Core
312c2961f8Sjose borrego  * SmbRead or SmbLockAndRead.
322c2961f8Sjose borrego  */
332c2961f8Sjose borrego #define	SMB_CORE_READ_MAX	4432
342c2961f8Sjose borrego 
352c2961f8Sjose borrego /*
362c2961f8Sjose borrego  * The limit in bytes for SmbReadX.
372c2961f8Sjose borrego  */
382c2961f8Sjose borrego #define	SMB_READX_MAX		0x10000
39da6c28aaSamw 
402c2961f8Sjose borrego int smb_common_read(smb_request_t *, smb_rw_param_t *);
41da6c28aaSamw 
42da6c28aaSamw /*
43da6c28aaSamw  * Read bytes from a file or named pipe (SMB Core).
44da6c28aaSamw  *
45da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
46da6c28aaSamw  * is limited to 32 bits, so this client request is inappropriate for
47da6c28aaSamw  * files with 64 bit offsets.
48da6c28aaSamw  *
49da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
50da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
51da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
52da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
53da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
54da6c28aaSamw  * length response is generated.  A count returned which is less than the
55da6c28aaSamw  * count requested is the end of file indicator.
56da6c28aaSamw  */
577b59d02dSjb smb_sdrc_t
smb_pre_read(smb_request_t * sr)58faa1795aSjb smb_pre_read(smb_request_t *sr)
59da6c28aaSamw {
60faa1795aSjb 	smb_rw_param_t *param;
61da6c28aaSamw 	uint32_t off_low;
622c2961f8Sjose borrego 	uint16_t count;
63da6c28aaSamw 	uint16_t remcnt;
64da6c28aaSamw 	int rc;
65da6c28aaSamw 
66faa1795aSjb 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
67faa1795aSjb 	sr->arg.rw = param;
68faa1795aSjb 
69da6c28aaSamw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
702c2961f8Sjose borrego 	    &count, &off_low, &remcnt);
71faa1795aSjb 
72faa1795aSjb 	param->rw_offset = (uint64_t)off_low;
732c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
74faa1795aSjb 	param->rw_mincnt = 0;
75faa1795aSjb 
7693bc28dbSGordon Ross 	DTRACE_SMB_START(op__Read, smb_request_t *, sr); /* arg.rw */
77faa1795aSjb 
78faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
79faa1795aSjb }
80faa1795aSjb 
81faa1795aSjb void
smb_post_read(smb_request_t * sr)82faa1795aSjb smb_post_read(smb_request_t *sr)
83faa1795aSjb {
8493bc28dbSGordon Ross 	DTRACE_SMB_DONE(op__Read, smb_request_t *, sr); /* arg.rw */
85da6c28aaSamw 
86faa1795aSjb 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
87faa1795aSjb }
88faa1795aSjb 
89faa1795aSjb smb_sdrc_t
smb_com_read(smb_request_t * sr)90faa1795aSjb smb_com_read(smb_request_t *sr)
91faa1795aSjb {
92faa1795aSjb 	smb_rw_param_t *param = sr->arg.rw;
932c2961f8Sjose borrego 	uint16_t count;
94faa1795aSjb 	int rc;
95da6c28aaSamw 
962c2961f8Sjose borrego 	smbsr_lookup_file(sr);
97da6c28aaSamw 	if (sr->fid_ofile == NULL) {
98dc20a302Sas 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
99faa1795aSjb 		return (SDRC_ERROR);
100da6c28aaSamw 	}
101da6c28aaSamw 
102b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
103b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1042c2961f8Sjose borrego 	if (param->rw_count > SMB_CORE_READ_MAX)
1052c2961f8Sjose borrego 		param->rw_count = SMB_CORE_READ_MAX;
1062c2961f8Sjose borrego 
107faa1795aSjb 	if ((rc = smb_common_read(sr, param)) != 0) {
108dc20a302Sas 		smbsr_errno(sr, rc);
109faa1795aSjb 		return (SDRC_ERROR);
110da6c28aaSamw 	}
111da6c28aaSamw 
1122c2961f8Sjose borrego 	count = (uint16_t)param->rw_count;
1137b59d02dSjb 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
1142c2961f8Sjose borrego 	    5, count, VAR_BCC, 0x01, count, &sr->raw_data);
115da6c28aaSamw 
116faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
117da6c28aaSamw }
118da6c28aaSamw 
119da6c28aaSamw /*
120da6c28aaSamw  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
121da6c28aaSamw  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
122da6c28aaSamw  * attempt to use it on non-disk shares.
123da6c28aaSamw  *
124da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
125da6c28aaSamw  * specifies the offset in the file of the first byte to be locked then
126da6c28aaSamw  * read. Note that offset is limited to 32 bits, so this client request
127da6c28aaSamw  * is inappropriate for files with 64 bit offsets.
128da6c28aaSamw  *
129da6c28aaSamw  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
130da6c28aaSamw  * immediately an error should be returned to the client.  If an error
131da6c28aaSamw  * occurs on the lock, the bytes should not be read.
132da6c28aaSamw  *
133da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
134da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
135da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
136da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
137da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
138da6c28aaSamw  * length response is generated.  A count returned which is less than the
139da6c28aaSamw  * count requested is the end of file indicator.
140da6c28aaSamw  */
1417b59d02dSjb smb_sdrc_t
smb_pre_lock_and_read(smb_request_t * sr)142faa1795aSjb smb_pre_lock_and_read(smb_request_t *sr)
143da6c28aaSamw {
144faa1795aSjb 	smb_rw_param_t *param;
145da6c28aaSamw 	uint32_t off_low;
1462c2961f8Sjose borrego 	uint16_t count;
1472c2961f8Sjose borrego 	uint16_t remcnt;
148da6c28aaSamw 	int rc;
149da6c28aaSamw 
150faa1795aSjb 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
151faa1795aSjb 	sr->arg.rw = param;
152da6c28aaSamw 
153da6c28aaSamw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
1542c2961f8Sjose borrego 	    &count, &off_low, &remcnt);
155faa1795aSjb 
156faa1795aSjb 	param->rw_offset = (uint64_t)off_low;
1572c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
158faa1795aSjb 	param->rw_mincnt = 0;
159faa1795aSjb 
16093bc28dbSGordon Ross 	DTRACE_SMB_START(op__LockAndRead, smb_request_t *, sr); /* arg.rw */
161faa1795aSjb 
162faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
163faa1795aSjb }
164faa1795aSjb 
165faa1795aSjb void
smb_post_lock_and_read(smb_request_t * sr)166faa1795aSjb smb_post_lock_and_read(smb_request_t *sr)
167faa1795aSjb {
16893bc28dbSGordon Ross 	DTRACE_SMB_DONE(op__LockAndRead, smb_request_t *, sr); /* arg.rw */
169faa1795aSjb 
170faa1795aSjb 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
171faa1795aSjb }
172da6c28aaSamw 
173faa1795aSjb smb_sdrc_t
smb_com_lock_and_read(smb_request_t * sr)174faa1795aSjb smb_com_lock_and_read(smb_request_t *sr)
175faa1795aSjb {
176faa1795aSjb 	smb_rw_param_t *param = sr->arg.rw;
177faa1795aSjb 	DWORD status;
1780897f7fbSGordon Ross 	uint32_t lk_pid;
1792c2961f8Sjose borrego 	uint16_t count;
180faa1795aSjb 	int rc;
181faa1795aSjb 
182faa1795aSjb 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
183faa1795aSjb 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
184faa1795aSjb 		return (SDRC_ERROR);
185faa1795aSjb 	}
186da6c28aaSamw 
1872c2961f8Sjose borrego 	smbsr_lookup_file(sr);
188da6c28aaSamw 	if (sr->fid_ofile == NULL) {
189dc20a302Sas 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
190faa1795aSjb 		return (SDRC_ERROR);
191da6c28aaSamw 	}
192da6c28aaSamw 
193b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
194b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1950897f7fbSGordon Ross 	/* Note: SMB1 locking uses 16-bit PIDs. */
1960897f7fbSGordon Ross 	lk_pid = sr->smb_pid & 0xFFFF;
1970897f7fbSGordon Ross 
1986537f381Sas 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
1990897f7fbSGordon Ross 	    lk_pid, SMB_LOCK_TYPE_READWRITE, 0);
2002c2961f8Sjose borrego 
201faa1795aSjb 	if (status != NT_STATUS_SUCCESS) {
202faa1795aSjb 		smb_lock_range_error(sr, status);
203faa1795aSjb 		return (SDRC_ERROR);
204da6c28aaSamw 	}
205da6c28aaSamw 
2062c2961f8Sjose borrego 	if (param->rw_count > SMB_CORE_READ_MAX)
2072c2961f8Sjose borrego 		param->rw_count = SMB_CORE_READ_MAX;
2082c2961f8Sjose borrego 
209faa1795aSjb 	if ((rc = smb_common_read(sr, param)) != 0) {
210dc20a302Sas 		smbsr_errno(sr, rc);
211faa1795aSjb 		return (SDRC_ERROR);
212da6c28aaSamw 	}
213da6c28aaSamw 
2142c2961f8Sjose borrego 	count = (uint16_t)param->rw_count;
2157b59d02dSjb 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
2162c2961f8Sjose borrego 	    5, count, VAR_BCC, 0x1, count, &sr->raw_data);
217da6c28aaSamw 
218faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
219da6c28aaSamw }
220da6c28aaSamw 
22193bc28dbSGordon Ross /*
22293bc28dbSGordon Ross  * The SMB_COM_READ_RAW protocol was a negotiated option introduced in
22393bc28dbSGordon Ross  * SMB Core Plus to maximize performance when reading a large block
22493bc28dbSGordon Ross  * of data from a server.  It's obsolete and no longer supported.
22593bc28dbSGordon Ross  *
22693bc28dbSGordon Ross  * We keep a handler for it so the dtrace provider can see if
22793bc28dbSGordon Ross  * the client tried to use this command.
22893bc28dbSGordon Ross  */
22993bc28dbSGordon Ross smb_sdrc_t
smb_pre_read_raw(smb_request_t * sr)23093bc28dbSGordon Ross smb_pre_read_raw(smb_request_t *sr)
23193bc28dbSGordon Ross {
23293bc28dbSGordon Ross 	DTRACE_SMB_START(op__ReadRaw, smb_request_t *, sr);
23393bc28dbSGordon Ross 	return (SDRC_SUCCESS);
23493bc28dbSGordon Ross }
23593bc28dbSGordon Ross 
23693bc28dbSGordon Ross void
smb_post_read_raw(smb_request_t * sr)23793bc28dbSGordon Ross smb_post_read_raw(smb_request_t *sr)
23893bc28dbSGordon Ross {
23993bc28dbSGordon Ross 	DTRACE_SMB_DONE(op__ReadRaw, smb_request_t *, sr);
24093bc28dbSGordon Ross }
24193bc28dbSGordon Ross 
24293bc28dbSGordon Ross smb_sdrc_t
smb_com_read_raw(smb_request_t * sr)24393bc28dbSGordon Ross smb_com_read_raw(smb_request_t *sr)
24493bc28dbSGordon Ross {
24593bc28dbSGordon Ross 	smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
24693bc28dbSGordon Ross 	    ERROR_NOT_SUPPORTED);
24793bc28dbSGordon Ross 	return (SDRC_ERROR);
24893bc28dbSGordon Ross }
24993bc28dbSGordon Ross 
250da6c28aaSamw /*
251da6c28aaSamw  * Read bytes from a file (SMB Core).  This request was extended in
252da6c28aaSamw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
253da6c28aaSamw  * 12 and including additional offset information.
2542c2961f8Sjose borrego  *
2552c2961f8Sjose borrego  * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
2562c2961f8Sjose borrego  * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
2572c2961f8Sjose borrego  * than the negotiated buffer size.  If maxcnt_high is 0xFF, it must
2582c2961f8Sjose borrego  * be ignored.  Otherwise, maxcnt_high represents the upper 16 bits
2592c2961f8Sjose borrego  * of rw_count.
260da6c28aaSamw  */
2617b59d02dSjb smb_sdrc_t
smb_pre_read_andx(smb_request_t * sr)262faa1795aSjb smb_pre_read_andx(smb_request_t *sr)
263da6c28aaSamw {
264faa1795aSjb 	smb_rw_param_t *param;
265da6c28aaSamw 	uint32_t off_low;
266da6c28aaSamw 	uint32_t off_high;
2672c2961f8Sjose borrego 	uint32_t maxcnt_high;
2682c2961f8Sjose borrego 	uint16_t maxcnt_low;
2692c2961f8Sjose borrego 	uint16_t mincnt;
270da6c28aaSamw 	uint16_t remcnt;
271da6c28aaSamw 	int rc;
272da6c28aaSamw 
273faa1795aSjb 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
274faa1795aSjb 	sr->arg.rw = param;
275faa1795aSjb 
276da6c28aaSamw 	if (sr->smb_wct == 12) {
2772c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
2782c2961f8Sjose borrego 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
2792c2961f8Sjose borrego 		    &remcnt, &off_high);
2802c2961f8Sjose borrego 
2812c2961f8Sjose borrego 		param->rw_offset = ((uint64_t)off_high << 32) |
2822c2961f8Sjose borrego 		    (uint64_t)off_low;
283da6c28aaSamw 
2842c2961f8Sjose borrego 		param->rw_count = (uint32_t)maxcnt_low;
2853a6c5f83SAlan Wright 
2863a6c5f83SAlan Wright 		if ((sr->session->capabilities & CAP_LARGE_READX) &&
2873a6c5f83SAlan Wright 		    (maxcnt_high < 0xFF))
2882c2961f8Sjose borrego 			param->rw_count |= maxcnt_high << 16;
289da6c28aaSamw 	} else {
2902c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
2912c2961f8Sjose borrego 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
2922c2961f8Sjose borrego 		    &remcnt);
293da6c28aaSamw 
294faa1795aSjb 		param->rw_offset = (uint64_t)off_low;
2952c2961f8Sjose borrego 		param->rw_count = (uint32_t)maxcnt_low;
296da6c28aaSamw 	}
297da6c28aaSamw 
298faa1795aSjb 	param->rw_mincnt = 0;
299faa1795aSjb 
30093bc28dbSGordon Ross 	DTRACE_SMB_START(op__ReadX, smb_request_t *, sr); /* arg.rw */
301faa1795aSjb 
302faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
303faa1795aSjb }
304da6c28aaSamw 
305faa1795aSjb void
smb_post_read_andx(smb_request_t * sr)306faa1795aSjb smb_post_read_andx(smb_request_t *sr)
307faa1795aSjb {
30893bc28dbSGordon Ross 	DTRACE_SMB_DONE(op__ReadX, smb_request_t *, sr); /* arg.rw */
309faa1795aSjb 
310faa1795aSjb 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
311faa1795aSjb }
312faa1795aSjb 
313faa1795aSjb smb_sdrc_t
smb_com_read_andx(smb_request_t * sr)314faa1795aSjb smb_com_read_andx(smb_request_t *sr)
315faa1795aSjb {
316faa1795aSjb 	smb_rw_param_t *param = sr->arg.rw;
3172c2961f8Sjose borrego 	uint16_t datalen_high;
3182c2961f8Sjose borrego 	uint16_t datalen_low;
3192c2961f8Sjose borrego 	uint16_t data_offset;
320faa1795aSjb 	uint16_t offset2;
321faa1795aSjb 	int rc;
322da6c28aaSamw 
3232c2961f8Sjose borrego 	smbsr_lookup_file(sr);
324da6c28aaSamw 	if (sr->fid_ofile == NULL) {
325dc20a302Sas 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
326faa1795aSjb 		return (SDRC_ERROR);
327da6c28aaSamw 	}
328da6c28aaSamw 
329b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
330b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3312c2961f8Sjose borrego 	if (param->rw_count >= SMB_READX_MAX)
3322c2961f8Sjose borrego 		param->rw_count = 0;
3332c2961f8Sjose borrego 
334faa1795aSjb 	if ((rc = smb_common_read(sr, param)) != 0) {
335dc20a302Sas 		smbsr_errno(sr, rc);
336faa1795aSjb 		return (SDRC_ERROR);
337da6c28aaSamw 	}
338da6c28aaSamw 
3392c2961f8Sjose borrego 	datalen_low = param->rw_count & 0xFFFF;
3402c2961f8Sjose borrego 	datalen_high = (param->rw_count >> 16) & 0xFF;
341da6c28aaSamw 
342da6c28aaSamw 	/*
3432c2961f8Sjose borrego 	 * If this is a secondary command, the data offset
3442c2961f8Sjose borrego 	 * includes the previous wct + sizeof(wct).
345da6c28aaSamw 	 */
3462c2961f8Sjose borrego 	data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
3472c2961f8Sjose borrego 
348da6c28aaSamw 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
3492c2961f8Sjose borrego 		data_offset += 60;
3502c2961f8Sjose borrego 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
3512c2961f8Sjose borrego 
3522c2961f8Sjose borrego 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
353da6c28aaSamw 		    12,			/* wct */
3542c2961f8Sjose borrego 		    param->rw_andx,	/* secondary andx command */
3552c2961f8Sjose borrego 		    offset2,		/* offset to next command */
3562c2961f8Sjose borrego 		    0,			/* set to 0 for named pipes */
3572c2961f8Sjose borrego 		    datalen_low,	/* data byte count */
3582c2961f8Sjose borrego 		    data_offset,	/* offset from start to data */
3592c2961f8Sjose borrego 		    datalen_high,	/* data byte count */
360da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
3612c2961f8Sjose borrego 		    0x00,		/* padding */
362da6c28aaSamw 		    &sr->raw_data);
363da6c28aaSamw 	} else {
3642c2961f8Sjose borrego 		data_offset += 59;
3652c2961f8Sjose borrego 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
3662c2961f8Sjose borrego 
3672c2961f8Sjose borrego 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
368da6c28aaSamw 		    12,			/* wct */
3692c2961f8Sjose borrego 		    param->rw_andx,	/* secondary andx command */
3702c2961f8Sjose borrego 		    offset2,		/* offset to next command */
3712c2961f8Sjose borrego 		    -1,			/* must be -1 for regular files */
3722c2961f8Sjose borrego 		    datalen_low,	/* data byte count */
3732c2961f8Sjose borrego 		    data_offset,	/* offset from start to data */
3742c2961f8Sjose borrego 		    datalen_high,	/* data byte count */
375da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
376da6c28aaSamw 		    &sr->raw_data);
377da6c28aaSamw 	}
378da6c28aaSamw 
379faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
380da6c28aaSamw }
381da6c28aaSamw 
382da6c28aaSamw /*
383da6c28aaSamw  * Common function for reading files or IPC/MSRPC named pipes.  All
384da6c28aaSamw  * protocol read functions should lookup the fid before calling this
385da6c28aaSamw  * function.  We can't move the fid lookup here because lock-and-read
386da6c28aaSamw  * requires the fid to do locking before attempting the read.
387da6c28aaSamw  *
38894047d49SGordon Ross  * Reading from a file does not break oplocks because any need for
38994047d49SGordon Ross  * breaking before read is handled in open.
390cb174861Sjoyce mcintosh  *
391da6c28aaSamw  * Returns errno values.
392da6c28aaSamw  */
393da6c28aaSamw int
smb_common_read(smb_request_t * sr,smb_rw_param_t * param)394faa1795aSjb smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
395da6c28aaSamw {
396da6c28aaSamw 	smb_ofile_t *ofile = sr->fid_ofile;
397da6c28aaSamw 	smb_node_t *node;
398faa1795aSjb 	smb_vdb_t *vdb = &param->rw_vdb;
399da6c28aaSamw 	struct mbuf *top;
400da6c28aaSamw 	int rc;
401da6c28aaSamw 
4022c2961f8Sjose borrego 	vdb->vdb_tag = 0;
4032c2961f8Sjose borrego 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
4042c2961f8Sjose borrego 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
4052c2961f8Sjose borrego 	vdb->vdb_uio.uio_resid = param->rw_count;
4062c2961f8Sjose borrego 	vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
4072c2961f8Sjose borrego 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
408f96bd5c8SAlan Wright 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
409da6c28aaSamw 
410da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
411da6c28aaSamw 	case STYPE_DISKTREE:
412da6c28aaSamw 		node = ofile->f_node;
413da6c28aaSamw 
414037cac00Sjoyce mcintosh 		if (!smb_node_is_dir(node)) {
415faa1795aSjb 			rc = smb_lock_range_access(sr, node, param->rw_offset,
416faa1795aSjb 			    param->rw_count, B_FALSE);
417da6c28aaSamw 			if (rc != NT_STATUS_SUCCESS) {
418da6c28aaSamw 				rc = ERANGE;
419da6c28aaSamw 				break;
420da6c28aaSamw 			}
421da6c28aaSamw 		}
422da6c28aaSamw 
4232c2961f8Sjose borrego 		if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
4249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		    !(sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)) {
4252c2961f8Sjose borrego 			/*
4269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * SMB_FLAGS2_READ_IF_EXECUTE: permit execute-only
4279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * reads.
4282c2961f8Sjose borrego 			 *
4292c2961f8Sjose borrego 			 * Reject request if the file has been opened
4309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * execute-only and SMB_FLAGS2_READ_IF_EXECUTE is not
4319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * set.
4322c2961f8Sjose borrego 			 */
4332c2961f8Sjose borrego 			rc = EACCES;
4342c2961f8Sjose borrego 			break;
4352c2961f8Sjose borrego 		}
4362c2961f8Sjose borrego 
4372c2961f8Sjose borrego 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
4382c2961f8Sjose borrego 		top = smb_mbuf_allocate(&vdb->vdb_uio);
439da6c28aaSamw 
44055f0a249SGordon Ross 		rc = smb_fsop_read(sr, sr->user_cr, node, ofile,
441*dfa42fabSMatt Barden 		    &vdb->vdb_uio, 0);
442da6c28aaSamw 
4432c2961f8Sjose borrego 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
444da6c28aaSamw 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
445da6c28aaSamw 		MBC_ATTACH_MBUF(&sr->raw_data, top);
446da6c28aaSamw 		break;
447da6c28aaSamw 
448da6c28aaSamw 	case STYPE_IPC:
44968b2bbf2SGordon Ross 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
45068b2bbf2SGordon Ross 		top = smb_mbuf_allocate(&vdb->vdb_uio);
45168b2bbf2SGordon Ross 
4522c2961f8Sjose borrego 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
45368b2bbf2SGordon Ross 
45468b2bbf2SGordon Ross 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
45568b2bbf2SGordon Ross 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
45668b2bbf2SGordon Ross 		MBC_ATTACH_MBUF(&sr->raw_data, top);
457da6c28aaSamw 		break;
458da6c28aaSamw 
459da6c28aaSamw 	default:
460da6c28aaSamw 		rc = EACCES;
461da6c28aaSamw 		break;
462da6c28aaSamw 	}
463da6c28aaSamw 
4642c2961f8Sjose borrego 	param->rw_count -= vdb->vdb_uio.uio_resid;
465da6c28aaSamw 
466da6c28aaSamw 	if (rc != 0)
467da6c28aaSamw 		return (rc);
468da6c28aaSamw 
469faa1795aSjb 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
470da6c28aaSamw 		/*
471da6c28aaSamw 		 * mincnt is only used by read-raw and is typically
472da6c28aaSamw 		 * zero.  If mincnt is greater than zero and the
473da6c28aaSamw 		 * number of bytes read is less than mincnt, tell
474da6c28aaSamw 		 * the client that we read nothing.
475da6c28aaSamw 		 */
476faa1795aSjb 		param->rw_count = 0;
477da6c28aaSamw 	}
478da6c28aaSamw 
479faa1795aSjb 	param->rw_offset += param->rw_count;
480da6c28aaSamw 	mutex_enter(&sr->fid_ofile->f_mutex);
481faa1795aSjb 	ofile->f_seek_pos = param->rw_offset;
482da6c28aaSamw 	mutex_exit(&sr->fid_ofile->f_mutex);
483da6c28aaSamw 	return (rc);
484da6c28aaSamw }
485