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 /* 228934SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 26*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 275331Samw #include <smbsrv/smb_fsops.h> 285331Samw 295331Samw 308934SJose.Borrego@Sun.COM /* 318934SJose.Borrego@Sun.COM * The maximum number of bytes to return from SMB Core 328934SJose.Borrego@Sun.COM * SmbRead or SmbLockAndRead. 338934SJose.Borrego@Sun.COM */ 348934SJose.Borrego@Sun.COM #define SMB_CORE_READ_MAX 4432 358934SJose.Borrego@Sun.COM 368934SJose.Borrego@Sun.COM /* 378934SJose.Borrego@Sun.COM * The limit in bytes for SmbReadX. 388934SJose.Borrego@Sun.COM */ 398934SJose.Borrego@Sun.COM #define SMB_READX_MAX 0x10000 408934SJose.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; 638934SJose.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, 718934SJose.Borrego@Sun.COM &count, &off_low, &remcnt); 726139Sjb150015 736139Sjb150015 param->rw_offset = (uint64_t)off_low; 748934SJose.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; 968934SJose.Borrego@Sun.COM uint16_t count; 976139Sjb150015 int rc; 985331Samw 998934SJose.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 1078934SJose.Borrego@Sun.COM if (param->rw_count > SMB_CORE_READ_MAX) 1088934SJose.Borrego@Sun.COM param->rw_count = SMB_CORE_READ_MAX; 1098934SJose.Borrego@Sun.COM 1106139Sjb150015 if ((rc = smb_common_read(sr, param)) != 0) { 1115772Sas200622 smbsr_errno(sr, rc); 1126139Sjb150015 return (SDRC_ERROR); 1135331Samw } 1145331Samw 1158934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count; 1166030Sjb150015 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 1178934SJose.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; 1488934SJose.Borrego@Sun.COM uint32_t off_low; 1498934SJose.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, 1578934SJose.Borrego@Sun.COM &count, &off_low, &remcnt); 1586139Sjb150015 1596139Sjb150015 param->rw_offset = (uint64_t)off_low; 1608934SJose.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; 1838934SJose.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 1918934SJose.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, 2008934SJose.Borrego@Sun.COM 0, SMB_LOCK_TYPE_READWRITE); 2018934SJose.Borrego@Sun.COM 2026139Sjb150015 if (status != NT_STATUS_SUCCESS) { 2036139Sjb150015 smb_lock_range_error(sr, status); 2046139Sjb150015 return (SDRC_ERROR); 2055331Samw } 2065331Samw 2078934SJose.Borrego@Sun.COM if (param->rw_count > SMB_CORE_READ_MAX) 2088934SJose.Borrego@Sun.COM param->rw_count = SMB_CORE_READ_MAX; 2098934SJose.Borrego@Sun.COM 2106139Sjb150015 if ((rc = smb_common_read(sr, param)) != 0) { 2115772Sas200622 smbsr_errno(sr, rc); 2126139Sjb150015 return (SDRC_ERROR); 2135331Samw } 2145331Samw 2158934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count; 2166030Sjb150015 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 2178934SJose.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 * 2418934SJose.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; 2518934SJose.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, 2598934SJose.Borrego@Sun.COM &off_low, &count, ¶m->rw_mincnt, &timeout); 2608934SJose.Borrego@Sun.COM if (rc == 0) { 2618934SJose.Borrego@Sun.COM param->rw_offset = (uint64_t)off_low; 2628934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 2638934SJose.Borrego@Sun.COM } 2646139Sjb150015 } else { 2656139Sjb150015 rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid, 2668934SJose.Borrego@Sun.COM &off_low, &count, ¶m->rw_mincnt, &timeout, &off_high); 2678934SJose.Borrego@Sun.COM if (rc == 0) { 2688934SJose.Borrego@Sun.COM param->rw_offset = ((uint64_t)off_high << 32) | off_low; 2698934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 2708934SJose.Borrego@Sun.COM } 2716139Sjb150015 } 2726139Sjb150015 2736139Sjb150015 DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr, 2746139Sjb150015 smb_rw_param_t *, param); 2756139Sjb150015 2769343SAfshin.Ardakani@Sun.COM smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER); 2778934SJose.Borrego@Sun.COM return (SDRC_SUCCESS); 2786139Sjb150015 } 2796139Sjb150015 2806139Sjb150015 void 2816139Sjb150015 smb_post_read_raw(smb_request_t *sr) 2826139Sjb150015 { 2838934SJose.Borrego@Sun.COM mbuf_chain_t *mbc; 2848934SJose.Borrego@Sun.COM 2858934SJose.Borrego@Sun.COM if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) { 2868934SJose.Borrego@Sun.COM sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; 2878934SJose.Borrego@Sun.COM 2888934SJose.Borrego@Sun.COM while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) != 2898934SJose.Borrego@Sun.COM NULL) { 2908934SJose.Borrego@Sun.COM SMB_MBC_VALID(mbc); 2918934SJose.Borrego@Sun.COM list_remove(&sr->session->s_oplock_brkreqs, mbc); 2928934SJose.Borrego@Sun.COM (void) smb_session_send(sr->session, 0, mbc); 2938934SJose.Borrego@Sun.COM smb_mbc_free(mbc); 2948934SJose.Borrego@Sun.COM } 2958934SJose.Borrego@Sun.COM } 2968934SJose.Borrego@Sun.COM 2976139Sjb150015 DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr, 2986139Sjb150015 smb_rw_param_t *, sr->arg.rw); 2996139Sjb150015 3009343SAfshin.Ardakani@Sun.COM smb_rwx_rwexit(&sr->session->s_lock); 3016139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 3026139Sjb150015 } 3036139Sjb150015 3046139Sjb150015 smb_sdrc_t 3056139Sjb150015 smb_com_read_raw(smb_request_t *sr) 3066139Sjb150015 { 3076139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 3085331Samw 3095331Samw switch (sr->session->s_state) { 3105331Samw case SMB_SESSION_STATE_NEGOTIATED: 3118934SJose.Borrego@Sun.COM sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE; 3126139Sjb150015 break; 3135331Samw 3145331Samw case SMB_SESSION_STATE_OPLOCK_BREAKING: 3155331Samw (void) smb_session_send(sr->session, 0, NULL); 3165331Samw return (SDRC_NO_REPLY); 3175331Samw 3185331Samw case SMB_SESSION_STATE_TERMINATED: 3195331Samw case SMB_SESSION_STATE_DISCONNECTED: 3205331Samw return (SDRC_NO_REPLY); 3215331Samw 3228934SJose.Borrego@Sun.COM case SMB_SESSION_STATE_READ_RAW_ACTIVE: 3238934SJose.Borrego@Sun.COM sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; 3248934SJose.Borrego@Sun.COM return (SDRC_DROP_VC); 3258934SJose.Borrego@Sun.COM 3266139Sjb150015 case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: 3275331Samw case SMB_SESSION_STATE_CONNECTED: 3285331Samw case SMB_SESSION_STATE_ESTABLISHED: 3295331Samw default: 3305331Samw return (SDRC_DROP_VC); 3315331Samw } 3326139Sjb150015 3338934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 3346139Sjb150015 if (sr->fid_ofile == NULL) { 3358934SJose.Borrego@Sun.COM (void) smb_session_send(sr->session, 0, NULL); 3368934SJose.Borrego@Sun.COM return (SDRC_NO_REPLY); 3376139Sjb150015 } 3386139Sjb150015 3397961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 3407961SNatalie.Li@Sun.COM 3418934SJose.Borrego@Sun.COM if (param->rw_mincnt > param->rw_count) 3428934SJose.Borrego@Sun.COM param->rw_mincnt = 0; 3436139Sjb150015 3448934SJose.Borrego@Sun.COM if (smb_common_read(sr, param) != 0) { 3456139Sjb150015 (void) smb_session_send(sr->session, 0, NULL); 3466139Sjb150015 m_freem(sr->raw_data.chain); 3478934SJose.Borrego@Sun.COM sr->raw_data.chain = NULL; 3486139Sjb150015 } else { 3496139Sjb150015 (void) smb_session_send(sr->session, 0, &sr->raw_data); 3506139Sjb150015 } 3516139Sjb150015 3526139Sjb150015 return (SDRC_NO_REPLY); 3535331Samw } 3545331Samw 3555331Samw /* 3565331Samw * Read bytes from a file (SMB Core). This request was extended in 3575331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 3585331Samw * 12 and including additional offset information. 3598934SJose.Borrego@Sun.COM * 3608934SJose.Borrego@Sun.COM * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4: 3618934SJose.Borrego@Sun.COM * If wct is 12 and CAP_LARGE_READX is set, the count may be larger 3628934SJose.Borrego@Sun.COM * than the negotiated buffer size. If maxcnt_high is 0xFF, it must 3638934SJose.Borrego@Sun.COM * be ignored. Otherwise, maxcnt_high represents the upper 16 bits 3648934SJose.Borrego@Sun.COM * of rw_count. 3655331Samw */ 3666030Sjb150015 smb_sdrc_t 3676139Sjb150015 smb_pre_read_andx(smb_request_t *sr) 3685331Samw { 3696139Sjb150015 smb_rw_param_t *param; 3705331Samw uint32_t off_low; 3715331Samw uint32_t off_high; 3728934SJose.Borrego@Sun.COM uint32_t maxcnt_high; 3738934SJose.Borrego@Sun.COM uint16_t maxcnt_low; 3748934SJose.Borrego@Sun.COM uint16_t mincnt; 3755331Samw uint16_t remcnt; 3765331Samw int rc; 3775331Samw 3786139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 3796139Sjb150015 sr->arg.rw = param; 3806139Sjb150015 3815331Samw if (sr->smb_wct == 12) { 3828934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", ¶m->rw_andx, 3838934SJose.Borrego@Sun.COM &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high, 3848934SJose.Borrego@Sun.COM &remcnt, &off_high); 3858934SJose.Borrego@Sun.COM 3868934SJose.Borrego@Sun.COM param->rw_offset = ((uint64_t)off_high << 32) | 3878934SJose.Borrego@Sun.COM (uint64_t)off_low; 3885331Samw 3898934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)maxcnt_low; 3908938Samw@Sun.COM 3918938Samw@Sun.COM if ((sr->session->capabilities & CAP_LARGE_READX) && 3928938Samw@Sun.COM (maxcnt_high < 0xFF)) 3938934SJose.Borrego@Sun.COM param->rw_count |= maxcnt_high << 16; 3945331Samw } else { 3958934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "b3.wlwwlw", ¶m->rw_andx, 3968934SJose.Borrego@Sun.COM &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high, 3978934SJose.Borrego@Sun.COM &remcnt); 3985331Samw 3996139Sjb150015 param->rw_offset = (uint64_t)off_low; 4008934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)maxcnt_low; 4015331Samw } 4025331Samw 4036139Sjb150015 param->rw_mincnt = 0; 4046139Sjb150015 4056139Sjb150015 DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr, 4066139Sjb150015 smb_rw_param_t *, param); 4076139Sjb150015 4086139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4096139Sjb150015 } 4105331Samw 4116139Sjb150015 void 4126139Sjb150015 smb_post_read_andx(smb_request_t *sr) 4136139Sjb150015 { 4146139Sjb150015 DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr, 4156139Sjb150015 smb_rw_param_t *, sr->arg.rw); 4166139Sjb150015 4176139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 4186139Sjb150015 } 4196139Sjb150015 4206139Sjb150015 smb_sdrc_t 4216139Sjb150015 smb_com_read_andx(smb_request_t *sr) 4226139Sjb150015 { 4236139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 4248934SJose.Borrego@Sun.COM uint16_t datalen_high; 4258934SJose.Borrego@Sun.COM uint16_t datalen_low; 4268934SJose.Borrego@Sun.COM uint16_t data_offset; 4276139Sjb150015 uint16_t offset2; 4286139Sjb150015 int rc; 4295331Samw 4308934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 4315331Samw if (sr->fid_ofile == NULL) { 4325772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 4336139Sjb150015 return (SDRC_ERROR); 4345331Samw } 4355331Samw 4367961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 4377961SNatalie.Li@Sun.COM 4388934SJose.Borrego@Sun.COM if (param->rw_count >= SMB_READX_MAX) 4398934SJose.Borrego@Sun.COM param->rw_count = 0; 4408934SJose.Borrego@Sun.COM 4416139Sjb150015 if ((rc = smb_common_read(sr, param)) != 0) { 4425772Sas200622 smbsr_errno(sr, rc); 4436139Sjb150015 return (SDRC_ERROR); 4445331Samw } 4455331Samw 4468934SJose.Borrego@Sun.COM datalen_low = param->rw_count & 0xFFFF; 4478934SJose.Borrego@Sun.COM datalen_high = (param->rw_count >> 16) & 0xFF; 4485331Samw 4495331Samw /* 4508934SJose.Borrego@Sun.COM * If this is a secondary command, the data offset 4518934SJose.Borrego@Sun.COM * includes the previous wct + sizeof(wct). 4525331Samw */ 4538934SJose.Borrego@Sun.COM data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1; 4548934SJose.Borrego@Sun.COM 4555331Samw if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 4568934SJose.Borrego@Sun.COM data_offset += 60; 4578934SJose.Borrego@Sun.COM offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60; 4588934SJose.Borrego@Sun.COM 4598934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC", 4605331Samw 12, /* wct */ 4618934SJose.Borrego@Sun.COM param->rw_andx, /* secondary andx command */ 4628934SJose.Borrego@Sun.COM offset2, /* offset to next command */ 4638934SJose.Borrego@Sun.COM 0, /* set to 0 for named pipes */ 4648934SJose.Borrego@Sun.COM datalen_low, /* data byte count */ 4658934SJose.Borrego@Sun.COM data_offset, /* offset from start to data */ 4668934SJose.Borrego@Sun.COM datalen_high, /* data byte count */ 4675331Samw VAR_BCC, /* BCC marker */ 4688934SJose.Borrego@Sun.COM 0x00, /* padding */ 4695331Samw &sr->raw_data); 4705331Samw } else { 4718934SJose.Borrego@Sun.COM data_offset += 59; 4728934SJose.Borrego@Sun.COM offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59; 4738934SJose.Borrego@Sun.COM 4748934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC", 4755331Samw 12, /* wct */ 4768934SJose.Borrego@Sun.COM param->rw_andx, /* secondary andx command */ 4778934SJose.Borrego@Sun.COM offset2, /* offset to next command */ 4788934SJose.Borrego@Sun.COM -1, /* must be -1 for regular files */ 4798934SJose.Borrego@Sun.COM datalen_low, /* data byte count */ 4808934SJose.Borrego@Sun.COM data_offset, /* offset from start to data */ 4818934SJose.Borrego@Sun.COM datalen_high, /* data byte count */ 4825331Samw VAR_BCC, /* BCC marker */ 4835331Samw &sr->raw_data); 4845331Samw } 4855331Samw 4866139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4875331Samw } 4885331Samw 4895331Samw /* 4905331Samw * Common function for reading files or IPC/MSRPC named pipes. All 4915331Samw * protocol read functions should lookup the fid before calling this 4925331Samw * function. We can't move the fid lookup here because lock-and-read 4935331Samw * requires the fid to do locking before attempting the read. 4945331Samw * 4955331Samw * Returns errno values. 4965331Samw */ 4975331Samw int 4986139Sjb150015 smb_common_read(smb_request_t *sr, smb_rw_param_t *param) 4995331Samw { 5005331Samw smb_ofile_t *ofile = sr->fid_ofile; 5015331Samw smb_node_t *node; 5026139Sjb150015 smb_vdb_t *vdb = ¶m->rw_vdb; 5035331Samw struct mbuf *top; 5045331Samw int rc; 5055331Samw 5068934SJose.Borrego@Sun.COM vdb->vdb_tag = 0; 5078934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0]; 5088934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_iovcnt = MAX_IOVEC; 5098934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_resid = param->rw_count; 5108934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset; 5118934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_segflg = UIO_SYSSPACE; 5125331Samw 5135331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 5145331Samw case STYPE_DISKTREE: 5155331Samw node = ofile->f_node; 5165331Samw 51710001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) { 5186139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 5196139Sjb150015 param->rw_count, B_FALSE); 5205331Samw if (rc != NT_STATUS_SUCCESS) { 5215331Samw rc = ERANGE; 5225331Samw break; 5235331Samw } 5245331Samw } 5255331Samw 5268934SJose.Borrego@Sun.COM if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) && 5278934SJose.Borrego@Sun.COM !(sr->smb_flg2 & SMB_FLAGS2_PAGING_IO)) { 5288934SJose.Borrego@Sun.COM /* 5298934SJose.Borrego@Sun.COM * SMB_FLAGS2_PAGING_IO: permit execute-only reads. 5308934SJose.Borrego@Sun.COM * 5318934SJose.Borrego@Sun.COM * Reject request if the file has been opened 5328934SJose.Borrego@Sun.COM * execute-only and SMB_FLAGS2_PAGING_IO is not set. 5338934SJose.Borrego@Sun.COM */ 5348934SJose.Borrego@Sun.COM rc = EACCES; 5358934SJose.Borrego@Sun.COM break; 5368934SJose.Borrego@Sun.COM } 5378934SJose.Borrego@Sun.COM 5388934SJose.Borrego@Sun.COM sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid; 5398934SJose.Borrego@Sun.COM top = smb_mbuf_allocate(&vdb->vdb_uio); 5405331Samw 54110001SJoyce.McIntosh@Sun.COM rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio); 5425331Samw 5438934SJose.Borrego@Sun.COM sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid; 5445331Samw smb_mbuf_trim(top, sr->raw_data.max_bytes); 5455331Samw MBC_ATTACH_MBUF(&sr->raw_data, top); 5465331Samw break; 5475331Samw 5485331Samw case STYPE_IPC: 5498934SJose.Borrego@Sun.COM rc = smb_opipe_read(sr, &vdb->vdb_uio); 5505331Samw break; 5515331Samw 5525331Samw default: 5535331Samw rc = EACCES; 5545331Samw break; 5555331Samw } 5565331Samw 5578934SJose.Borrego@Sun.COM param->rw_count -= vdb->vdb_uio.uio_resid; 5585331Samw 5595331Samw if (rc != 0) 5605331Samw return (rc); 5615331Samw 5626139Sjb150015 if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) { 5635331Samw /* 5645331Samw * mincnt is only used by read-raw and is typically 5655331Samw * zero. If mincnt is greater than zero and the 5665331Samw * number of bytes read is less than mincnt, tell 5675331Samw * the client that we read nothing. 5685331Samw */ 5696139Sjb150015 param->rw_count = 0; 5705331Samw } 5715331Samw 5726139Sjb150015 param->rw_offset += param->rw_count; 5735331Samw mutex_enter(&sr->fid_ofile->f_mutex); 5746139Sjb150015 ofile->f_seek_pos = param->rw_offset; 5755331Samw mutex_exit(&sr->fid_ofile->f_mutex); 5765331Samw return (rc); 5775331Samw } 578