2023-10-31 17:48:09 +03:00
/*
2003-08-13 05:53:07 +04:00
Unix SMB / CIFS implementation .
client file read / write routines
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) James Myers 2003
2023-10-31 17:48:09 +03:00
2003-08-13 05:53:07 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
2023-10-31 17:48:09 +03:00
2003-08-13 05:53:07 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2023-10-31 17:48:09 +03:00
2003-08-13 05:53:07 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2004-11-01 04:03:22 +03:00
# include "libcli/raw/libcliraw.h"
2008-04-02 06:53:27 +04:00
# include "libcli/raw/raw_proto.h"
2003-08-13 05:53:07 +04:00
# define SETUP_REQUEST(cmd, wct, buflen) do { \
2004-08-04 17:23:35 +04:00
req = smbcli_request_setup ( tree , cmd , wct , buflen ) ; \
2003-08-13 05:53:07 +04:00
if ( ! req ) return NULL ; \
} while ( 0 )
/****************************************************************************
low level read operation ( async send )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-02 06:53:27 +04:00
_PUBLIC_ struct smbcli_request * smb_raw_read_send ( struct smbcli_tree * tree , union smb_read * parms )
2003-08-13 05:53:07 +04:00
{
2007-10-07 02:28:14 +04:00
bool bigoffset = false ;
2023-10-31 17:48:09 +03:00
struct smbcli_request * req = NULL ;
2003-08-13 05:53:07 +04:00
switch ( parms - > generic . level ) {
case RAW_READ_READBRAW :
2004-03-08 10:11:13 +03:00
if ( tree - > session - > transport - > negotiate . capabilities & CAP_LARGE_FILES ) {
2007-10-07 02:28:14 +04:00
bigoffset = true ;
2003-08-13 05:53:07 +04:00
}
SETUP_REQUEST ( SMBreadbraw , bigoffset ? 10 : 8 , 0 ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > readbraw . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( req - > out . vwv , VWV ( 1 ) , parms - > readbraw . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 3 ) , parms - > readbraw . in . maxcnt ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > readbraw . in . mincnt ) ;
SIVAL ( req - > out . vwv , VWV ( 5 ) , parms - > readbraw . in . timeout ) ;
SSVAL ( req - > out . vwv , VWV ( 7 ) , 0 ) ; /* reserved */
if ( bigoffset ) {
SIVAL ( req - > out . vwv , VWV ( 8 ) , parms - > readbraw . in . offset > > 32 ) ;
}
break ;
case RAW_READ_LOCKREAD :
SETUP_REQUEST ( SMBlockread , 5 , 0 ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > lockread . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > lockread . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > lockread . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > lockread . in . remaining ) ;
break ;
case RAW_READ_READ :
SETUP_REQUEST ( SMBread , 5 , 0 ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > read . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > read . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > read . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > read . in . remaining ) ;
break ;
case RAW_READ_READX :
2004-03-08 10:11:13 +03:00
if ( tree - > session - > transport - > negotiate . capabilities & CAP_LARGE_FILES ) {
2007-10-07 02:28:14 +04:00
bigoffset = true ;
2003-08-13 05:53:07 +04:00
}
SETUP_REQUEST ( SMBreadX , bigoffset ? 12 : 10 , 0 ) ;
2004-12-26 11:13:01 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , SMB_CHAIN_NONE ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 1 ) , 0 ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 2 ) , parms - > readx . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( req - > out . vwv , VWV ( 3 ) , parms - > readx . in . offset ) ;
2004-10-26 09:34:35 +04:00
SSVAL ( req - > out . vwv , VWV ( 5 ) , parms - > readx . in . maxcnt & 0xFFFF ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 6 ) , parms - > readx . in . mincnt ) ;
2004-10-26 09:34:35 +04:00
SIVAL ( req - > out . vwv , VWV ( 7 ) , parms - > readx . in . maxcnt > > 16 ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 9 ) , parms - > readx . in . remaining ) ;
2006-05-20 14:40:10 +04:00
/*
* TODO : give an error when the offset is 64 bit
* and the server doesn ' t support it
*/
2003-08-13 05:53:07 +04:00
if ( bigoffset ) {
SIVAL ( req - > out . vwv , VWV ( 10 ) , parms - > readx . in . offset > > 32 ) ;
}
2006-03-11 15:58:36 +03:00
if ( parms - > readx . in . read_for_execute ) {
2006-04-18 17:05:24 +04:00
uint16_t flags2 = SVAL ( req - > out . hdr , HDR_FLG2 ) ;
flags2 | = FLAGS2_READ_PERMIT_EXECUTE ;
SSVAL ( req - > out . hdr , HDR_FLG2 , flags2 ) ;
2006-03-11 15:58:36 +03:00
}
2003-08-13 05:53:07 +04:00
break ;
2006-05-20 14:46:38 +04:00
case RAW_READ_SMB2 :
return NULL ;
2003-08-13 05:53:07 +04:00
}
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_send ( req ) ) {
smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
return NULL ;
}
return req ;
}
/****************************************************************************
low level read operation ( async recv )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS smb_raw_read_recv ( struct smbcli_request * req , union smb_read * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_receive ( req ) | |
smbcli_request_is_error ( req ) ) {
2003-08-13 05:53:07 +04:00
goto failed ;
}
switch ( parms - > generic . level ) {
case RAW_READ_READBRAW :
parms - > readbraw . out . nread = req - > in . size - NBT_HDR_SIZE ;
2023-10-31 17:48:09 +03:00
if ( parms - > readbraw . out . nread >
2003-08-13 05:53:07 +04:00
MAX ( parms - > readx . in . mincnt , parms - > readx . in . maxcnt ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
goto failed ;
}
memcpy ( parms - > readbraw . out . data , req - > in . buffer + NBT_HDR_SIZE , parms - > readbraw . out . nread ) ;
break ;
2023-10-31 17:48:09 +03:00
2003-08-13 05:53:07 +04:00
case RAW_READ_LOCKREAD :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 5 ) ;
2003-08-13 05:53:07 +04:00
parms - > lockread . out . nread = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
if ( parms - > lockread . out . nread > parms - > lockread . in . count | |
2023-10-31 17:48:09 +03:00
! smbcli_raw_pull_data ( & req - > in . bufinfo , req - > in . data + 3 ,
2003-08-13 05:53:07 +04:00
parms - > lockread . out . nread , parms - > lockread . out . data ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
}
break ;
case RAW_READ_READ :
/* there are 4 reserved words in the reply */
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 5 ) ;
2003-08-13 05:53:07 +04:00
parms - > read . out . nread = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
if ( parms - > read . out . nread > parms - > read . in . count | |
2023-10-31 17:48:09 +03:00
! smbcli_raw_pull_data ( & req - > in . bufinfo , req - > in . data + 3 ,
2003-08-13 05:53:07 +04:00
parms - > read . out . nread , parms - > read . out . data ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
}
break ;
case RAW_READ_READX :
/* there are 5 reserved words in the reply */
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 12 ) ;
2003-08-13 05:53:07 +04:00
parms - > readx . out . remaining = SVAL ( req - > in . vwv , VWV ( 2 ) ) ;
parms - > readx . out . compaction_mode = SVAL ( req - > in . vwv , VWV ( 3 ) ) ;
parms - > readx . out . nread = SVAL ( req - > in . vwv , VWV ( 5 ) ) ;
2014-08-08 01:19:57 +04:00
parms - > readx . out . flags2 = req - > flags2 ;
parms - > readx . out . data_offset = SVAL ( req - > in . vwv , VWV ( 6 ) ) ;
2006-12-08 06:47:02 +03:00
/* handle oversize replies for non-chained readx replies with
CAP_LARGE_READX . The snia spec has must to answer for . */
if ( ( req - > tree - > session - > transport - > negotiate . capabilities & CAP_LARGE_READX )
& & CVAL ( req - > in . vwv , VWV ( 0 ) ) = = SMB_CHAIN_NONE & &
req - > in . size > = 0x10000 ) {
parms - > readx . out . nread + = ( SVAL ( req - > in . vwv , VWV ( 7 ) ) < < 16 ) ;
if ( req - > in . hdr + SVAL ( req - > in . vwv , VWV ( 6 ) ) +
2023-10-31 17:48:09 +03:00
parms - > readx . out . nread < =
2006-12-08 06:47:02 +03:00
req - > in . buffer + req - > in . size ) {
req - > in . data_size + = ( SVAL ( req - > in . vwv , VWV ( 7 ) ) < < 16 ) ;
2008-02-16 05:28:37 +03:00
/* update the bufinfo with the new size */
smb_setup_bufinfo ( req ) ;
2006-12-08 06:47:02 +03:00
}
}
2003-08-13 05:53:07 +04:00
if ( parms - > readx . out . nread > MAX ( parms - > readx . in . mincnt , parms - > readx . in . maxcnt ) | |
2023-10-31 17:48:09 +03:00
! smbcli_raw_pull_data ( & req - > in . bufinfo , req - > in . hdr + SVAL ( req - > in . vwv , VWV ( 6 ) ) ,
parms - > readx . out . nread ,
2003-08-13 05:53:07 +04:00
parms - > readx . out . data ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
}
break ;
2006-05-20 14:46:38 +04:00
case RAW_READ_SMB2 :
req - > status = NT_STATUS_INTERNAL_ERROR ;
break ;
2003-08-13 05:53:07 +04:00
}
failed :
2004-08-04 17:23:35 +04:00
return smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
}
/****************************************************************************
low level read operation ( sync interface )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS smb_raw_read ( struct smbcli_tree * tree , union smb_read * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
struct smbcli_request * req = smb_raw_read_send ( tree , parms ) ;
2003-08-13 05:53:07 +04:00
return smb_raw_read_recv ( req , parms ) ;
}
/****************************************************************************
raw write interface ( async send )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-02 06:53:27 +04:00
_PUBLIC_ struct smbcli_request * smb_raw_write_send ( struct smbcli_tree * tree , union smb_write * parms )
2003-08-13 05:53:07 +04:00
{
2007-10-07 02:28:14 +04:00
bool bigoffset = false ;
2023-10-31 17:48:09 +03:00
struct smbcli_request * req = NULL ;
2003-08-13 05:53:07 +04:00
switch ( parms - > generic . level ) {
case RAW_WRITE_WRITEUNLOCK :
SETUP_REQUEST ( SMBwriteunlock , 5 , 3 + parms - > writeunlock . in . count ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > writeunlock . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > writeunlock . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > writeunlock . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > writeunlock . in . remaining ) ;
SCVAL ( req - > out . data , 0 , SMB_DATA_BLOCK ) ;
SSVAL ( req - > out . data , 1 , parms - > writeunlock . in . count ) ;
if ( parms - > writeunlock . in . count > 0 ) {
2023-10-31 17:48:09 +03:00
memcpy ( req - > out . data + 3 , parms - > writeunlock . in . data ,
2003-08-13 05:53:07 +04:00
parms - > writeunlock . in . count ) ;
}
break ;
case RAW_WRITE_WRITE :
SETUP_REQUEST ( SMBwrite , 5 , 3 + parms - > write . in . count ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > write . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > write . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > write . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > write . in . remaining ) ;
SCVAL ( req - > out . data , 0 , SMB_DATA_BLOCK ) ;
SSVAL ( req - > out . data , 1 , parms - > write . in . count ) ;
if ( parms - > write . in . count > 0 ) {
memcpy ( req - > out . data + 3 , parms - > write . in . data , parms - > write . in . count ) ;
}
break ;
case RAW_WRITE_WRITECLOSE :
SETUP_REQUEST ( SMBwriteclose , 6 , 1 + parms - > writeclose . in . count ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > writeclose . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > writeclose . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > writeclose . in . offset ) ;
2004-04-11 00:18:22 +04:00
raw_push_dos_date3 ( tree - > session - > transport ,
req - > out . vwv , VWV ( 4 ) , parms - > writeclose . in . mtime ) ;
2003-08-13 05:53:07 +04:00
SCVAL ( req - > out . data , 0 , 0 ) ;
if ( parms - > writeclose . in . count > 0 ) {
2023-10-31 17:48:09 +03:00
memcpy ( req - > out . data + 1 , parms - > writeclose . in . data ,
2003-08-13 05:53:07 +04:00
parms - > writeclose . in . count ) ;
}
break ;
case RAW_WRITE_WRITEX :
2004-03-08 10:11:13 +03:00
if ( tree - > session - > transport - > negotiate . capabilities & CAP_LARGE_FILES ) {
2007-10-07 02:28:14 +04:00
bigoffset = true ;
2003-08-13 05:53:07 +04:00
}
SETUP_REQUEST ( SMBwriteX , bigoffset ? 14 : 12 , parms - > writex . in . count ) ;
2004-12-26 11:13:01 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , SMB_CHAIN_NONE ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 1 ) , 0 ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 2 ) , parms - > writex . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( req - > out . vwv , VWV ( 3 ) , parms - > writex . in . offset ) ;
SIVAL ( req - > out . vwv , VWV ( 5 ) , 0 ) ; /* reserved */
SSVAL ( req - > out . vwv , VWV ( 7 ) , parms - > writex . in . wmode ) ;
SSVAL ( req - > out . vwv , VWV ( 8 ) , parms - > writex . in . remaining ) ;
2004-03-08 10:11:13 +03:00
SSVAL ( req - > out . vwv , VWV ( 9 ) , parms - > writex . in . count > > 16 ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 10 ) , parms - > writex . in . count ) ;
SSVAL ( req - > out . vwv , VWV ( 11 ) , PTR_DIFF ( req - > out . data , req - > out . hdr ) ) ;
if ( bigoffset ) {
SIVAL ( req - > out . vwv , VWV ( 12 ) , parms - > writex . in . offset > > 32 ) ;
}
if ( parms - > writex . in . count > 0 ) {
memcpy ( req - > out . data , parms - > writex . in . data , parms - > writex . in . count ) ;
}
break ;
case RAW_WRITE_SPLWRITE :
SETUP_REQUEST ( SMBsplwr , 1 , parms - > splwrite . in . count ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > splwrite . in . file . fnum ) ;
2003-08-13 05:53:07 +04:00
if ( parms - > splwrite . in . count > 0 ) {
memcpy ( req - > out . data , parms - > splwrite . in . data , parms - > splwrite . in . count ) ;
}
break ;
2006-05-20 14:46:38 +04:00
case RAW_WRITE_SMB2 :
return NULL ;
2003-08-13 05:53:07 +04:00
}
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_send ( req ) ) {
2004-11-10 13:56:43 +03:00
smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
return NULL ;
}
return req ;
}
/****************************************************************************
raw write interface ( async recv )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-09-25 17:02:05 +04:00
_PUBLIC_ NTSTATUS smb_raw_write_recv ( struct smbcli_request * req , union smb_write * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_receive ( req ) | |
2009-04-30 19:24:58 +04:00
! NT_STATUS_IS_OK ( req - > status ) ) {
2003-08-13 05:53:07 +04:00
goto failed ;
}
switch ( parms - > generic . level ) {
case RAW_WRITE_WRITEUNLOCK :
2023-10-31 17:48:09 +03:00
SMBCLI_CHECK_WCT ( req , 1 ) ;
2003-08-13 05:53:07 +04:00
parms - > writeunlock . out . nwritten = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
break ;
case RAW_WRITE_WRITE :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 1 ) ;
2003-08-13 05:53:07 +04:00
parms - > write . out . nwritten = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
break ;
case RAW_WRITE_WRITECLOSE :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 1 ) ;
2003-08-13 05:53:07 +04:00
parms - > writeclose . out . nwritten = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
break ;
case RAW_WRITE_WRITEX :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 6 ) ;
2003-08-13 05:53:07 +04:00
parms - > writex . out . nwritten = SVAL ( req - > in . vwv , VWV ( 2 ) ) ;
parms - > writex . out . nwritten + = ( CVAL ( req - > in . vwv , VWV ( 4 ) ) < < 16 ) ;
parms - > writex . out . remaining = SVAL ( req - > in . vwv , VWV ( 3 ) ) ;
break ;
case RAW_WRITE_SPLWRITE :
break ;
2006-05-20 14:46:38 +04:00
case RAW_WRITE_SMB2 :
req - > status = NT_STATUS_INTERNAL_ERROR ;
break ;
2003-08-13 05:53:07 +04:00
}
failed :
2004-08-04 17:23:35 +04:00
return smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
}
/****************************************************************************
raw write interface ( sync interface )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS smb_raw_write ( struct smbcli_tree * tree , union smb_write * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
struct smbcli_request * req = smb_raw_write_send ( tree , parms ) ;
2003-08-13 05:53:07 +04:00
return smb_raw_write_recv ( req , parms ) ;
}