xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_read.c (revision 8934:8ff6afa44187)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
22*8934SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #include <smbsrv/smb_incl.h>
275331Samw #include <smbsrv/smb_fsops.h>
285331Samw 
295331Samw 
30*8934SJose.Borrego@Sun.COM /*
31*8934SJose.Borrego@Sun.COM  * The maximum number of bytes to return from SMB Core
32*8934SJose.Borrego@Sun.COM  * SmbRead or SmbLockAndRead.
33*8934SJose.Borrego@Sun.COM  */
34*8934SJose.Borrego@Sun.COM #define	SMB_CORE_READ_MAX	4432
35*8934SJose.Borrego@Sun.COM 
36*8934SJose.Borrego@Sun.COM /*
37*8934SJose.Borrego@Sun.COM  * The limit in bytes for SmbReadX.
38*8934SJose.Borrego@Sun.COM  */
39*8934SJose.Borrego@Sun.COM #define	SMB_READX_MAX		0x10000
40*8934SJose.Borrego@Sun.COM 
416139Sjb150015 int smb_common_read(smb_request_t *, smb_rw_param_t *);
425331Samw 
435331Samw /*
445331Samw  * Read bytes from a file or named pipe (SMB Core).
455331Samw  *
465331Samw  * The requested count specifies the number of bytes desired.  Offset
475331Samw  * is limited to 32 bits, so this client request is inappropriate for
485331Samw  * files with 64 bit offsets.
495331Samw  *
505331Samw  * On return, count is the number of bytes actually being returned, which
515331Samw  * may be less than the count requested only if a read specifies bytes
525331Samw  * beyond the current file size.  In this case only the bytes that exist
535331Samw  * are returned.  A read completely beyond the end of file results in a
545331Samw  * response of length zero.  This is the only circumstance when a zero
555331Samw  * length response is generated.  A count returned which is less than the
565331Samw  * count requested is the end of file indicator.
575331Samw  */
586030Sjb150015 smb_sdrc_t
596139Sjb150015 smb_pre_read(smb_request_t *sr)
605331Samw {
616139Sjb150015 	smb_rw_param_t *param;
625331Samw 	uint32_t off_low;
63*8934SJose.Borrego@Sun.COM 	uint16_t count;
645331Samw 	uint16_t remcnt;
655331Samw 	int rc;
665331Samw 
676139Sjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
686139Sjb150015 	sr->arg.rw = param;
696139Sjb150015 
705331Samw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
71*8934SJose.Borrego@Sun.COM 	    &count, &off_low, &remcnt);
726139Sjb150015 
736139Sjb150015 	param->rw_offset = (uint64_t)off_low;
74*8934SJose.Borrego@Sun.COM 	param->rw_count = (uint32_t)count;
756139Sjb150015 	param->rw_mincnt = 0;
766139Sjb150015 
776139Sjb150015 	DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
786139Sjb150015 	    smb_rw_param_t *, param);
796139Sjb150015 
806139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
816139Sjb150015 }
825331Samw 
836139Sjb150015 void
846139Sjb150015 smb_post_read(smb_request_t *sr)
856139Sjb150015 {
866139Sjb150015 	DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
876139Sjb150015 	    smb_rw_param_t *, sr->arg.rw);
886139Sjb150015 
896139Sjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
906139Sjb150015 }
916139Sjb150015 
926139Sjb150015 smb_sdrc_t
936139Sjb150015 smb_com_read(smb_request_t *sr)
946139Sjb150015 {
956139Sjb150015 	smb_rw_param_t *param = sr->arg.rw;
96*8934SJose.Borrego@Sun.COM 	uint16_t count;
976139Sjb150015 	int rc;
985331Samw 
99*8934SJose.Borrego@Sun.COM 	smbsr_lookup_file(sr);
1005331Samw 	if (sr->fid_ofile == NULL) {
1015772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1026139Sjb150015 		return (SDRC_ERROR);
1035331Samw 	}
1045331Samw 
1057961SNatalie.Li@Sun.COM 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
1067961SNatalie.Li@Sun.COM 
107*8934SJose.Borrego@Sun.COM 	if (param->rw_count > SMB_CORE_READ_MAX)
108*8934SJose.Borrego@Sun.COM 		param->rw_count = SMB_CORE_READ_MAX;
109*8934SJose.Borrego@Sun.COM 
1106139Sjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
1115772Sas200622 		smbsr_errno(sr, rc);
1126139Sjb150015 		return (SDRC_ERROR);
1135331Samw 	}
1145331Samw 
115*8934SJose.Borrego@Sun.COM 	count = (uint16_t)param->rw_count;
1166030Sjb150015 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
117*8934SJose.Borrego@Sun.COM 	    5, count, VAR_BCC, 0x01, count, &sr->raw_data);
1185331Samw 
1196139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1205331Samw }
1215331Samw 
1225331Samw /*
1235331Samw  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
1245331Samw  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
1255331Samw  * attempt to use it on non-disk shares.
1265331Samw  *
1275331Samw  * The requested count specifies the number of bytes desired.  Offset
1285331Samw  * specifies the offset in the file of the first byte to be locked then
1295331Samw  * read. Note that offset is limited to 32 bits, so this client request
1305331Samw  * is inappropriate for files with 64 bit offsets.
1315331Samw  *
1325331Samw  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
1335331Samw  * immediately an error should be returned to the client.  If an error
1345331Samw  * occurs on the lock, the bytes should not be read.
1355331Samw  *
1365331Samw  * On return, count is the number of bytes actually being returned, which
1375331Samw  * may be less than the count requested only if a read specifies bytes
1385331Samw  * beyond the current file size.  In this case only the bytes that exist
1395331Samw  * are returned.  A read completely beyond the end of file results in a
1405331Samw  * response of length zero.  This is the only circumstance when a zero
1415331Samw  * length response is generated.  A count returned which is less than the
1425331Samw  * count requested is the end of file indicator.
1435331Samw  */
1446030Sjb150015 smb_sdrc_t
1456139Sjb150015 smb_pre_lock_and_read(smb_request_t *sr)
1465331Samw {
1476139Sjb150015 	smb_rw_param_t *param;
148*8934SJose.Borrego@Sun.COM 	uint32_t off_low;
149*8934SJose.Borrego@Sun.COM 	uint16_t count;
1505331Samw 	uint16_t remcnt;
1516139Sjb150015 	int rc;
1526139Sjb150015 
1536139Sjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
1546139Sjb150015 	sr->arg.rw = param;
1556139Sjb150015 
1566139Sjb150015 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
157*8934SJose.Borrego@Sun.COM 	    &count, &off_low, &remcnt);
1586139Sjb150015 
1596139Sjb150015 	param->rw_offset = (uint64_t)off_low;
160*8934SJose.Borrego@Sun.COM 	param->rw_count = (uint32_t)count;
1616139Sjb150015 	param->rw_mincnt = 0;
1626139Sjb150015 
1636139Sjb150015 	DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
1646139Sjb150015 	    smb_rw_param_t *, param);
1656139Sjb150015 
1666139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1676139Sjb150015 }
1686139Sjb150015 
1696139Sjb150015 void
1706139Sjb150015 smb_post_lock_and_read(smb_request_t *sr)
1716139Sjb150015 {
1726139Sjb150015 	DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
1736139Sjb150015 	    smb_rw_param_t *, sr->arg.rw);
1746139Sjb150015 
1756139Sjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
1766139Sjb150015 }
1776139Sjb150015 
1786139Sjb150015 smb_sdrc_t
1796139Sjb150015 smb_com_lock_and_read(smb_request_t *sr)
1806139Sjb150015 {
1816139Sjb150015 	smb_rw_param_t *param = sr->arg.rw;
1826139Sjb150015 	DWORD status;
183*8934SJose.Borrego@Sun.COM 	uint16_t count;
1845331Samw 	int rc;
1855331Samw 
1865331Samw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
1875772Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
1886139Sjb150015 		return (SDRC_ERROR);
1895331Samw 	}
1905331Samw 
191*8934SJose.Borrego@Sun.COM 	smbsr_lookup_file(sr);
1925331Samw 	if (sr->fid_ofile == NULL) {
1935772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1946139Sjb150015 		return (SDRC_ERROR);
1955331Samw 	}
1965331Samw 
1977961SNatalie.Li@Sun.COM 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
1987961SNatalie.Li@Sun.COM 
1996432Sas200622 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
200*8934SJose.Borrego@Sun.COM 	    0, SMB_LOCK_TYPE_READWRITE);
201*8934SJose.Borrego@Sun.COM 
2026139Sjb150015 	if (status != NT_STATUS_SUCCESS) {
2036139Sjb150015 		smb_lock_range_error(sr, status);
2046139Sjb150015 		return (SDRC_ERROR);
2055331Samw 	}
2065331Samw 
207*8934SJose.Borrego@Sun.COM 	if (param->rw_count > SMB_CORE_READ_MAX)
208*8934SJose.Borrego@Sun.COM 		param->rw_count = SMB_CORE_READ_MAX;
209*8934SJose.Borrego@Sun.COM 
2106139Sjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
2115772Sas200622 		smbsr_errno(sr, rc);
2126139Sjb150015 		return (SDRC_ERROR);
2135331Samw 	}
2145331Samw 
215*8934SJose.Borrego@Sun.COM 	count = (uint16_t)param->rw_count;
2166030Sjb150015 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
217*8934SJose.Borrego@Sun.COM 	    5, count, VAR_BCC, 0x1, count, &sr->raw_data);
2185331Samw 
2196139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2205331Samw }
2215331Samw 
2225331Samw /*
2235331Samw  * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
2245331Samw  * SMB Core Plus to maximize performance when reading a large block
2255331Samw  * of data from a server.  This request was extended in LM 0.12 to
2265331Samw  * support 64-bit offsets; the server can indicate support by setting
2275331Samw  * CAP_LARGE_FILES in the negotiated capabilities.
2285331Samw  *
2295331Samw  * The client must guarantee that there is (and will be) no other request
2305331Samw  * to the server for the duration of the SMB_COM_READ_RAW, since the
2315331Samw  * server response has no header or trailer. To help ensure that there
2325331Samw  * are no interruptions, we block all I/O for the session during read raw.
2335331Samw  *
2345331Samw  * If this is the first SMB request received since we sent an oplock break
2355331Samw  * to this client, we don't know if it's safe to send the raw data because
2365331Samw  * the requests may have crossed on the wire and the client may have
2375331Samw  * interpreted the oplock break as part of the raw data. To avoid problems,
2385331Samw  * we send a zero length session packet, which will force the client to
2395331Samw  * retry the read.
2405331Samw  *
241*8934SJose.Borrego@Sun.COM  * Do not return errors from SmbReadRaw.
2425331Samw  * Read errors are handled by sending a zero length response.
2435331Samw  */
2446030Sjb150015 smb_sdrc_t
2456139Sjb150015 smb_pre_read_raw(smb_request_t *sr)
2465331Samw {
2476139Sjb150015 	smb_rw_param_t *param;
2486139Sjb150015 	uint32_t off_low;
2496139Sjb150015 	uint32_t off_high;
2506139Sjb150015 	uint32_t timeout;
251*8934SJose.Borrego@Sun.COM 	uint16_t count;
2526139Sjb150015 	int rc;
2536139Sjb150015 
2546139Sjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
2556139Sjb150015 	sr->arg.rw = param;
2566139Sjb150015 
2576139Sjb150015 	if (sr->smb_wct == 8) {
2586139Sjb150015 		rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
259*8934SJose.Borrego@Sun.COM 		    &off_low, &count, &param->rw_mincnt, &timeout);
260*8934SJose.Borrego@Sun.COM 		if (rc == 0) {
261*8934SJose.Borrego@Sun.COM 			param->rw_offset = (uint64_t)off_low;
262*8934SJose.Borrego@Sun.COM 			param->rw_count = (uint32_t)count;
263*8934SJose.Borrego@Sun.COM 		}
2646139Sjb150015 	} else {
2656139Sjb150015 		rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
266*8934SJose.Borrego@Sun.COM 		    &off_low, &count, &param->rw_mincnt, &timeout, &off_high);
267*8934SJose.Borrego@Sun.COM 		if (rc == 0) {
268*8934SJose.Borrego@Sun.COM 			param->rw_offset = ((uint64_t)off_high << 32) | off_low;
269*8934SJose.Borrego@Sun.COM 			param->rw_count = (uint32_t)count;
270*8934SJose.Borrego@Sun.COM 		}
2716139Sjb150015 	}
2726139Sjb150015 
2736139Sjb150015 	DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr,
2746139Sjb150015 	    smb_rw_param_t *, param);
2756139Sjb150015 
276*8934SJose.Borrego@Sun.COM 	return (SDRC_SUCCESS);
2776139Sjb150015 }
2786139Sjb150015 
2796139Sjb150015 void
2806139Sjb150015 smb_post_read_raw(smb_request_t *sr)
2816139Sjb150015 {
282*8934SJose.Borrego@Sun.COM 	mbuf_chain_t	*mbc;
283*8934SJose.Borrego@Sun.COM 
284*8934SJose.Borrego@Sun.COM 	if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) {
285*8934SJose.Borrego@Sun.COM 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
286*8934SJose.Borrego@Sun.COM 
287*8934SJose.Borrego@Sun.COM 		while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) !=
288*8934SJose.Borrego@Sun.COM 		    NULL) {
289*8934SJose.Borrego@Sun.COM 			SMB_MBC_VALID(mbc);
290*8934SJose.Borrego@Sun.COM 			list_remove(&sr->session->s_oplock_brkreqs, mbc);
291*8934SJose.Borrego@Sun.COM 			(void) smb_session_send(sr->session, 0, mbc);
292*8934SJose.Borrego@Sun.COM 			smb_mbc_free(mbc);
293*8934SJose.Borrego@Sun.COM 		}
294*8934SJose.Borrego@Sun.COM 	}
295*8934SJose.Borrego@Sun.COM 
2966139Sjb150015 	DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr,
2976139Sjb150015 	    smb_rw_param_t *, sr->arg.rw);
2986139Sjb150015 
2996139Sjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
3006139Sjb150015 }
3016139Sjb150015 
3026139Sjb150015 smb_sdrc_t
3036139Sjb150015 smb_com_read_raw(smb_request_t *sr)
3046139Sjb150015 {
3056139Sjb150015 	smb_rw_param_t *param = sr->arg.rw;
3065331Samw 
3075331Samw 	switch (sr->session->s_state) {
3085331Samw 	case SMB_SESSION_STATE_NEGOTIATED:
309*8934SJose.Borrego@Sun.COM 		sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE;
3106139Sjb150015 		break;
3115331Samw 
3125331Samw 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
3135331Samw 		(void) smb_session_send(sr->session, 0, NULL);
3145331Samw 		return (SDRC_NO_REPLY);
3155331Samw 
3165331Samw 	case SMB_SESSION_STATE_TERMINATED:
3175331Samw 	case SMB_SESSION_STATE_DISCONNECTED:
3185331Samw 		return (SDRC_NO_REPLY);
3195331Samw 
320*8934SJose.Borrego@Sun.COM 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
321*8934SJose.Borrego@Sun.COM 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
322*8934SJose.Borrego@Sun.COM 		return (SDRC_DROP_VC);
323*8934SJose.Borrego@Sun.COM 
3246139Sjb150015 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
3255331Samw 	case SMB_SESSION_STATE_CONNECTED:
3265331Samw 	case SMB_SESSION_STATE_ESTABLISHED:
3275331Samw 	default:
3285331Samw 		return (SDRC_DROP_VC);
3295331Samw 	}
3306139Sjb150015 
331*8934SJose.Borrego@Sun.COM 	smbsr_lookup_file(sr);
3326139Sjb150015 	if (sr->fid_ofile == NULL) {
333*8934SJose.Borrego@Sun.COM 		(void) smb_session_send(sr->session, 0, NULL);
334*8934SJose.Borrego@Sun.COM 		return (SDRC_NO_REPLY);
3356139Sjb150015 	}
3366139Sjb150015 
3377961SNatalie.Li@Sun.COM 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
3387961SNatalie.Li@Sun.COM 
339*8934SJose.Borrego@Sun.COM 	if (param->rw_mincnt > param->rw_count)
340*8934SJose.Borrego@Sun.COM 		param->rw_mincnt = 0;
3416139Sjb150015 
342*8934SJose.Borrego@Sun.COM 	if (smb_common_read(sr, param) != 0) {
3436139Sjb150015 		(void) smb_session_send(sr->session, 0, NULL);
3446139Sjb150015 		m_freem(sr->raw_data.chain);
345*8934SJose.Borrego@Sun.COM 		sr->raw_data.chain = NULL;
3466139Sjb150015 	} else {
3476139Sjb150015 		(void) smb_session_send(sr->session, 0, &sr->raw_data);
3486139Sjb150015 	}
3496139Sjb150015 
3506139Sjb150015 	return (SDRC_NO_REPLY);
3515331Samw }
3525331Samw 
3535331Samw /*
3545331Samw  * Read bytes from a file (SMB Core).  This request was extended in
3555331Samw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
3565331Samw  * 12 and including additional offset information.
357*8934SJose.Borrego@Sun.COM  *
358*8934SJose.Borrego@Sun.COM  * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
359*8934SJose.Borrego@Sun.COM  * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
360*8934SJose.Borrego@Sun.COM  * than the negotiated buffer size.  If maxcnt_high is 0xFF, it must
361*8934SJose.Borrego@Sun.COM  * be ignored.  Otherwise, maxcnt_high represents the upper 16 bits
362*8934SJose.Borrego@Sun.COM  * of rw_count.
3635331Samw  */
3646030Sjb150015 smb_sdrc_t
3656139Sjb150015 smb_pre_read_andx(smb_request_t *sr)
3665331Samw {
3676139Sjb150015 	smb_rw_param_t *param;
3685331Samw 	uint32_t off_low;
3695331Samw 	uint32_t off_high;
370*8934SJose.Borrego@Sun.COM 	uint32_t maxcnt_high;
371*8934SJose.Borrego@Sun.COM 	uint16_t maxcnt_low;
372*8934SJose.Borrego@Sun.COM 	uint16_t mincnt;
3735331Samw 	uint16_t remcnt;
3745331Samw 	int rc;
3755331Samw 
3766139Sjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
3776139Sjb150015 	sr->arg.rw = param;
3786139Sjb150015 
3795331Samw 	if (sr->smb_wct == 12) {
380*8934SJose.Borrego@Sun.COM 		rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
381*8934SJose.Borrego@Sun.COM 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
382*8934SJose.Borrego@Sun.COM 		    &remcnt, &off_high);
383*8934SJose.Borrego@Sun.COM 
384*8934SJose.Borrego@Sun.COM 		param->rw_offset = ((uint64_t)off_high << 32) |
385*8934SJose.Borrego@Sun.COM 		    (uint64_t)off_low;
3865331Samw 
387*8934SJose.Borrego@Sun.COM 		param->rw_count = (uint32_t)maxcnt_low;
388*8934SJose.Borrego@Sun.COM 		if (maxcnt_high < 0xFF)
389*8934SJose.Borrego@Sun.COM 			param->rw_count |= maxcnt_high << 16;
3905331Samw 	} else {
391*8934SJose.Borrego@Sun.COM 		rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
392*8934SJose.Borrego@Sun.COM 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
393*8934SJose.Borrego@Sun.COM 		    &remcnt);
3945331Samw 
3956139Sjb150015 		param->rw_offset = (uint64_t)off_low;
396*8934SJose.Borrego@Sun.COM 		param->rw_count = (uint32_t)maxcnt_low;
3975331Samw 	}
3985331Samw 
3996139Sjb150015 	param->rw_mincnt = 0;
4006139Sjb150015 
4016139Sjb150015 	DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
4026139Sjb150015 	    smb_rw_param_t *, param);
4036139Sjb150015 
4046139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
4056139Sjb150015 }
4065331Samw 
4076139Sjb150015 void
4086139Sjb150015 smb_post_read_andx(smb_request_t *sr)
4096139Sjb150015 {
4106139Sjb150015 	DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
4116139Sjb150015 	    smb_rw_param_t *, sr->arg.rw);
4126139Sjb150015 
4136139Sjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
4146139Sjb150015 }
4156139Sjb150015 
4166139Sjb150015 smb_sdrc_t
4176139Sjb150015 smb_com_read_andx(smb_request_t *sr)
4186139Sjb150015 {
4196139Sjb150015 	smb_rw_param_t *param = sr->arg.rw;
420*8934SJose.Borrego@Sun.COM 	uint16_t datalen_high;
421*8934SJose.Borrego@Sun.COM 	uint16_t datalen_low;
422*8934SJose.Borrego@Sun.COM 	uint16_t data_offset;
4236139Sjb150015 	uint16_t offset2;
4246139Sjb150015 	int rc;
4255331Samw 
426*8934SJose.Borrego@Sun.COM 	smbsr_lookup_file(sr);
4275331Samw 	if (sr->fid_ofile == NULL) {
4285772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
4296139Sjb150015 		return (SDRC_ERROR);
4305331Samw 	}
4315331Samw 
4327961SNatalie.Li@Sun.COM 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
4337961SNatalie.Li@Sun.COM 
434*8934SJose.Borrego@Sun.COM 	if (param->rw_count >= SMB_READX_MAX)
435*8934SJose.Borrego@Sun.COM 		param->rw_count = 0;
436*8934SJose.Borrego@Sun.COM 
4376139Sjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
4385772Sas200622 		smbsr_errno(sr, rc);
4396139Sjb150015 		return (SDRC_ERROR);
4405331Samw 	}
4415331Samw 
442*8934SJose.Borrego@Sun.COM 	datalen_low = param->rw_count & 0xFFFF;
443*8934SJose.Borrego@Sun.COM 	datalen_high = (param->rw_count >> 16) & 0xFF;
4445331Samw 
4455331Samw 	/*
446*8934SJose.Borrego@Sun.COM 	 * If this is a secondary command, the data offset
447*8934SJose.Borrego@Sun.COM 	 * includes the previous wct + sizeof(wct).
4485331Samw 	 */
449*8934SJose.Borrego@Sun.COM 	data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
450*8934SJose.Borrego@Sun.COM 
4515331Samw 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
452*8934SJose.Borrego@Sun.COM 		data_offset += 60;
453*8934SJose.Borrego@Sun.COM 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
454*8934SJose.Borrego@Sun.COM 
455*8934SJose.Borrego@Sun.COM 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
4565331Samw 		    12,			/* wct */
457*8934SJose.Borrego@Sun.COM 		    param->rw_andx,	/* secondary andx command */
458*8934SJose.Borrego@Sun.COM 		    offset2,		/* offset to next command */
459*8934SJose.Borrego@Sun.COM 		    0,			/* set to 0 for named pipes */
460*8934SJose.Borrego@Sun.COM 		    datalen_low,	/* data byte count */
461*8934SJose.Borrego@Sun.COM 		    data_offset,	/* offset from start to data */
462*8934SJose.Borrego@Sun.COM 		    datalen_high,	/* data byte count */
4635331Samw 		    VAR_BCC,		/* BCC marker */
464*8934SJose.Borrego@Sun.COM 		    0x00,		/* padding */
4655331Samw 		    &sr->raw_data);
4665331Samw 	} else {
467*8934SJose.Borrego@Sun.COM 		data_offset += 59;
468*8934SJose.Borrego@Sun.COM 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
469*8934SJose.Borrego@Sun.COM 
470*8934SJose.Borrego@Sun.COM 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
4715331Samw 		    12,			/* wct */
472*8934SJose.Borrego@Sun.COM 		    param->rw_andx,	/* secondary andx command */
473*8934SJose.Borrego@Sun.COM 		    offset2,		/* offset to next command */
474*8934SJose.Borrego@Sun.COM 		    -1,			/* must be -1 for regular files */
475*8934SJose.Borrego@Sun.COM 		    datalen_low,	/* data byte count */
476*8934SJose.Borrego@Sun.COM 		    data_offset,	/* offset from start to data */
477*8934SJose.Borrego@Sun.COM 		    datalen_high,	/* data byte count */
4785331Samw 		    VAR_BCC,		/* BCC marker */
4795331Samw 		    &sr->raw_data);
4805331Samw 	}
4815331Samw 
4826139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
4835331Samw }
4845331Samw 
4855331Samw /*
4865331Samw  * Common function for reading files or IPC/MSRPC named pipes.  All
4875331Samw  * protocol read functions should lookup the fid before calling this
4885331Samw  * function.  We can't move the fid lookup here because lock-and-read
4895331Samw  * requires the fid to do locking before attempting the read.
4905331Samw  *
4915331Samw  * Returns errno values.
4925331Samw  */
4935331Samw int
4946139Sjb150015 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
4955331Samw {
4965331Samw 	smb_ofile_t *ofile = sr->fid_ofile;
4975331Samw 	smb_node_t *node;
4986139Sjb150015 	smb_vdb_t *vdb = &param->rw_vdb;
4995331Samw 	struct mbuf *top;
5005331Samw 	int rc;
5015331Samw 
502*8934SJose.Borrego@Sun.COM 	vdb->vdb_tag = 0;
503*8934SJose.Borrego@Sun.COM 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
504*8934SJose.Borrego@Sun.COM 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
505*8934SJose.Borrego@Sun.COM 	vdb->vdb_uio.uio_resid = param->rw_count;
506*8934SJose.Borrego@Sun.COM 	vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
507*8934SJose.Borrego@Sun.COM 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
5085331Samw 
5095331Samw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
5105331Samw 	case STYPE_DISKTREE:
5115331Samw 		node = ofile->f_node;
5125331Samw 
5135331Samw 		if (node->attr.sa_vattr.va_type != VDIR) {
5146139Sjb150015 			rc = smb_lock_range_access(sr, node, param->rw_offset,
5156139Sjb150015 			    param->rw_count, B_FALSE);
5165331Samw 			if (rc != NT_STATUS_SUCCESS) {
5175331Samw 				rc = ERANGE;
5185331Samw 				break;
5195331Samw 			}
5205331Samw 		}
5215331Samw 
522*8934SJose.Borrego@Sun.COM 		if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
523*8934SJose.Borrego@Sun.COM 		    !(sr->smb_flg2 & SMB_FLAGS2_PAGING_IO)) {
524*8934SJose.Borrego@Sun.COM 			/*
525*8934SJose.Borrego@Sun.COM 			 * SMB_FLAGS2_PAGING_IO: permit execute-only reads.
526*8934SJose.Borrego@Sun.COM 			 *
527*8934SJose.Borrego@Sun.COM 			 * Reject request if the file has been opened
528*8934SJose.Borrego@Sun.COM 			 * execute-only and SMB_FLAGS2_PAGING_IO is not set.
529*8934SJose.Borrego@Sun.COM 			 */
530*8934SJose.Borrego@Sun.COM 			rc = EACCES;
531*8934SJose.Borrego@Sun.COM 			break;
532*8934SJose.Borrego@Sun.COM 		}
533*8934SJose.Borrego@Sun.COM 
5345331Samw 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
5355331Samw 
536*8934SJose.Borrego@Sun.COM 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
537*8934SJose.Borrego@Sun.COM 		top = smb_mbuf_allocate(&vdb->vdb_uio);
5385331Samw 
539*8934SJose.Borrego@Sun.COM 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio,
5405331Samw 		    &node->attr);
5415331Samw 
542*8934SJose.Borrego@Sun.COM 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
5435331Samw 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
5445331Samw 		MBC_ATTACH_MBUF(&sr->raw_data, top);
5455331Samw 		break;
5465331Samw 
5475331Samw 	case STYPE_IPC:
548*8934SJose.Borrego@Sun.COM 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
5495331Samw 		break;
5505331Samw 
5515331Samw 	default:
5525331Samw 		rc = EACCES;
5535331Samw 		break;
5545331Samw 	}
5555331Samw 
556*8934SJose.Borrego@Sun.COM 	param->rw_count -= vdb->vdb_uio.uio_resid;
5575331Samw 
5585331Samw 	if (rc != 0)
5595331Samw 		return (rc);
5605331Samw 
5616139Sjb150015 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
5625331Samw 		/*
5635331Samw 		 * mincnt is only used by read-raw and is typically
5645331Samw 		 * zero.  If mincnt is greater than zero and the
5655331Samw 		 * number of bytes read is less than mincnt, tell
5665331Samw 		 * the client that we read nothing.
5675331Samw 		 */
5686139Sjb150015 		param->rw_count = 0;
5695331Samw 	}
5705331Samw 
5716139Sjb150015 	param->rw_offset += param->rw_count;
5725331Samw 	mutex_enter(&sr->fid_ofile->f_mutex);
5736139Sjb150015 	ofile->f_seek_pos = param->rw_offset;
5745331Samw 	mutex_exit(&sr->fid_ofile->f_mutex);
5755331Samw 	return (rc);
5765331Samw }
577