2011-09-18 01:34:12 +04:00
/*
Unix SMB / CIFS implementation .
client transaction calls
Copyright ( C ) Andrew Tridgell 1994 - 1998
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
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-09-18 01:38:09 +04:00
# include "system/network.h"
2011-09-18 01:34:12 +04:00
# include "../lib/util/tevent_ntstatus.h"
2011-09-18 01:38:09 +04:00
# include "../libcli/smb/smb_common.h"
# include "../libcli/smb/smbXcli_base.h"
2011-09-18 01:34:12 +04:00
struct trans_recvblob {
uint8_t * data ;
uint32_t max , total , received ;
} ;
2011-09-18 01:38:09 +04:00
struct smb1cli_trans_state {
struct smbXcli_conn * conn ;
2011-09-18 01:34:12 +04:00
struct tevent_context * ev ;
uint8_t cmd ;
2011-09-18 01:38:09 +04:00
uint8_t additional_flags ;
uint8_t clear_flags ;
uint16_t additional_flags2 ;
uint16_t clear_flags2 ;
uint32_t timeout_msec ;
2011-09-18 01:34:12 +04:00
uint16_t mid ;
2011-09-18 01:38:09 +04:00
uint32_t pid ;
2012-07-23 23:34:58 +04:00
struct smbXcli_tcon * tcon ;
2012-07-23 22:15:21 +04:00
struct smbXcli_session * session ;
2011-09-18 01:34:12 +04:00
const char * pipe_name ;
uint8_t * pipe_name_conv ;
size_t pipe_name_conv_len ;
uint16_t fid ;
uint16_t function ;
int flags ;
uint16_t * setup ;
uint8_t num_setup , max_setup ;
uint8_t * param ;
uint32_t num_param , param_sent ;
uint8_t * data ;
uint32_t num_data , data_sent ;
uint8_t num_rsetup ;
uint16_t * rsetup ;
struct trans_recvblob rparam ;
struct trans_recvblob rdata ;
uint16_t recv_flags2 ;
struct iovec iov [ 6 ] ;
uint8_t pad [ 4 ] ;
uint8_t zero_pad [ 4 ] ;
uint16_t vwv [ 32 ] ;
2011-11-28 12:15:11 +04:00
NTSTATUS status ;
2011-09-18 01:34:12 +04:00
struct tevent_req * primary_subreq ;
} ;
2011-09-18 01:38:09 +04:00
static void smb1cli_trans_cleanup_primary ( struct smb1cli_trans_state * state )
2011-09-18 01:34:12 +04:00
{
if ( state - > primary_subreq ) {
2011-09-18 01:38:09 +04:00
smb1cli_req_set_mid ( state - > primary_subreq , 0 ) ;
smbXcli_req_unset_pending ( state - > primary_subreq ) ;
2011-09-18 01:34:12 +04:00
TALLOC_FREE ( state - > primary_subreq ) ;
}
}
2011-09-18 01:38:09 +04:00
static int smb1cli_trans_state_destructor ( struct smb1cli_trans_state * state )
2011-09-18 01:34:12 +04:00
{
2011-09-18 01:38:09 +04:00
smb1cli_trans_cleanup_primary ( state ) ;
2011-09-18 01:34:12 +04:00
return 0 ;
}
2011-09-18 01:38:09 +04:00
static NTSTATUS smb1cli_pull_trans ( uint8_t * inhdr ,
uint8_t wct ,
uint16_t * vwv ,
uint32_t vwv_ofs ,
uint32_t num_bytes ,
uint8_t * bytes ,
uint32_t bytes_ofs ,
uint8_t smb_cmd , bool expect_first_reply ,
uint8_t * pnum_setup , uint16_t * * psetup ,
uint32_t * ptotal_param , uint32_t * pnum_param ,
uint32_t * pparam_disp , uint8_t * * pparam ,
uint32_t * ptotal_data , uint32_t * pnum_data ,
uint32_t * pdata_disp , uint8_t * * pdata )
2011-09-18 01:34:12 +04:00
{
uint32_t param_ofs , data_ofs ;
uint8_t expected_num_setup ;
2011-09-18 01:38:09 +04:00
uint32_t max_bytes = UINT32_MAX - bytes_ofs ;
uint32_t bytes_end ;
if ( num_bytes > max_bytes ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
bytes_end = bytes_ofs + num_bytes ;
2011-09-18 01:34:12 +04:00
if ( expect_first_reply ) {
if ( ( wct ! = 0 ) | | ( num_bytes ! = 0 ) ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
return NT_STATUS_OK ;
}
switch ( smb_cmd ) {
case SMBtrans :
case SMBtrans2 :
if ( wct < 10 ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
expected_num_setup = wct - 10 ;
* ptotal_param = SVAL ( vwv + 0 , 0 ) ;
* ptotal_data = SVAL ( vwv + 1 , 0 ) ;
* pnum_param = SVAL ( vwv + 3 , 0 ) ;
param_ofs = SVAL ( vwv + 4 , 0 ) ;
* pparam_disp = SVAL ( vwv + 5 , 0 ) ;
* pnum_data = SVAL ( vwv + 6 , 0 ) ;
data_ofs = SVAL ( vwv + 7 , 0 ) ;
* pdata_disp = SVAL ( vwv + 8 , 0 ) ;
* pnum_setup = CVAL ( vwv + 9 , 0 ) ;
if ( expected_num_setup < ( * pnum_setup ) ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
* psetup = vwv + 10 ;
break ;
case SMBnttrans :
if ( wct < 18 ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
expected_num_setup = wct - 18 ;
* ptotal_param = IVAL ( vwv , 3 ) ;
* ptotal_data = IVAL ( vwv , 7 ) ;
* pnum_param = IVAL ( vwv , 11 ) ;
param_ofs = IVAL ( vwv , 15 ) ;
* pparam_disp = IVAL ( vwv , 19 ) ;
* pnum_data = IVAL ( vwv , 23 ) ;
data_ofs = IVAL ( vwv , 27 ) ;
* pdata_disp = IVAL ( vwv , 31 ) ;
* pnum_setup = CVAL ( vwv , 35 ) ;
if ( expected_num_setup < ( * pnum_setup ) ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
* psetup = vwv + 18 ;
break ;
default :
return NT_STATUS_INTERNAL_ERROR ;
}
/*
* Check for buffer overflows . data_ofs needs to be checked against
* the incoming buffer length , data_disp against the total
* length . Likewise for param_ofs / param_disp .
*/
2011-09-18 01:38:09 +04:00
if ( smb_buffer_oob ( bytes_end , param_ofs , * pnum_param )
2011-09-18 01:34:12 +04:00
| | smb_buffer_oob ( * ptotal_param , * pparam_disp , * pnum_param )
2011-09-18 01:38:09 +04:00
| | smb_buffer_oob ( bytes_end , data_ofs , * pnum_data )
2011-09-18 01:34:12 +04:00
| | smb_buffer_oob ( * ptotal_data , * pdata_disp , * pnum_data ) ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-09-18 01:38:09 +04:00
* pparam = ( uint8_t * ) inhdr + param_ofs ;
* pdata = ( uint8_t * ) inhdr + data_ofs ;
2011-09-18 01:34:12 +04:00
return NT_STATUS_OK ;
}
2011-09-18 01:38:09 +04:00
static NTSTATUS smb1cli_trans_pull_blob ( TALLOC_CTX * mem_ctx ,
struct trans_recvblob * blob ,
uint32_t total , uint32_t thistime ,
uint8_t * buf , uint32_t displacement )
2011-09-18 01:34:12 +04:00
{
if ( blob - > data = = NULL ) {
if ( total > blob - > max ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
blob - > total = total ;
blob - > data = talloc_array ( mem_ctx , uint8_t , total ) ;
if ( blob - > data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
}
if ( total > blob - > total ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( thistime ) {
memcpy ( blob - > data + displacement , buf , thistime ) ;
blob - > received + = thistime ;
}
return NT_STATUS_OK ;
}
2011-09-18 01:38:09 +04:00
static void smb1cli_trans_format ( struct smb1cli_trans_state * state ,
uint8_t * pwct ,
int * piov_count )
2011-09-18 01:34:12 +04:00
{
uint8_t wct = 0 ;
struct iovec * iov = state - > iov ;
uint8_t * pad = state - > pad ;
uint16_t * vwv = state - > vwv ;
uint32_t param_offset ;
uint32_t this_param = 0 ;
uint32_t param_pad ;
uint32_t data_offset ;
uint32_t this_data = 0 ;
uint32_t data_pad ;
uint32_t useable_space ;
uint8_t cmd ;
2011-09-18 01:38:09 +04:00
uint32_t max_trans = smb1cli_conn_max_xmit ( state - > conn ) ;
2011-09-18 01:34:12 +04:00
cmd = state - > cmd ;
if ( ( state - > param_sent ! = 0 ) | | ( state - > data_sent ! = 0 ) ) {
/* The secondary commands are one after the primary ones */
cmd + = 1 ;
}
param_offset = MIN_SMB_SIZE ;
switch ( cmd ) {
case SMBtrans :
2011-09-18 01:38:09 +04:00
if ( smbXcli_conn_use_unicode ( state - > conn ) ) {
2011-09-18 01:34:12 +04:00
pad [ 0 ] = 0 ;
iov [ 0 ] . iov_base = ( void * ) pad ;
iov [ 0 ] . iov_len = 1 ;
param_offset + = 1 ;
iov + = 1 ;
}
iov [ 0 ] . iov_base = ( void * ) state - > pipe_name_conv ;
iov [ 0 ] . iov_len = state - > pipe_name_conv_len ;
wct = 14 + state - > num_setup ;
param_offset + = iov [ 0 ] . iov_len ;
iov + = 1 ;
break ;
case SMBtrans2 :
pad [ 0 ] = 0 ;
pad [ 1 ] = ' D ' ; /* Copy this from "old" 3.0 behaviour */
pad [ 2 ] = ' ' ;
iov [ 0 ] . iov_base = ( void * ) pad ;
iov [ 0 ] . iov_len = 3 ;
wct = 14 + state - > num_setup ;
param_offset + = 3 ;
iov + = 1 ;
break ;
case SMBtranss :
wct = 8 ;
break ;
case SMBtranss2 :
wct = 9 ;
break ;
case SMBnttrans :
wct = 19 + state - > num_setup ;
break ;
case SMBnttranss :
wct = 18 ;
break ;
}
param_offset + = wct * sizeof ( uint16_t ) ;
2011-09-18 01:38:09 +04:00
useable_space = max_trans - param_offset ;
2011-09-18 01:34:12 +04:00
param_pad = param_offset % 4 ;
if ( param_pad > 0 ) {
param_pad = MIN ( param_pad , useable_space ) ;
iov [ 0 ] . iov_base = ( void * ) state - > zero_pad ;
iov [ 0 ] . iov_len = param_pad ;
iov + = 1 ;
param_offset + = param_pad ;
}
2011-09-18 01:38:09 +04:00
useable_space = max_trans - param_offset ;
2011-09-18 01:34:12 +04:00
if ( state - > param_sent < state - > num_param ) {
this_param = MIN ( state - > num_param - state - > param_sent ,
useable_space ) ;
iov [ 0 ] . iov_base = ( void * ) ( state - > param + state - > param_sent ) ;
iov [ 0 ] . iov_len = this_param ;
iov + = 1 ;
}
data_offset = param_offset + this_param ;
2011-09-18 01:38:09 +04:00
useable_space = max_trans - data_offset ;
2011-09-18 01:34:12 +04:00
data_pad = data_offset % 4 ;
if ( data_pad > 0 ) {
data_pad = MIN ( data_pad , useable_space ) ;
iov [ 0 ] . iov_base = ( void * ) state - > zero_pad ;
iov [ 0 ] . iov_len = data_pad ;
iov + = 1 ;
data_offset + = data_pad ;
}
2011-09-18 01:38:09 +04:00
useable_space = max_trans - data_offset ;
2011-09-18 01:34:12 +04:00
if ( state - > data_sent < state - > num_data ) {
this_data = MIN ( state - > num_data - state - > data_sent ,
useable_space ) ;
iov [ 0 ] . iov_base = ( void * ) ( state - > data + state - > data_sent ) ;
iov [ 0 ] . iov_len = this_data ;
iov + = 1 ;
}
DEBUG ( 10 , ( " num_setup=%u, max_setup=%u, "
" param_total=%u, this_param=%u, max_param=%u, "
" data_total=%u, this_data=%u, max_data=%u, "
" param_offset=%u, param_pad=%u, param_disp=%u, "
" data_offset=%u, data_pad=%u, data_disp=%u \n " ,
( unsigned ) state - > num_setup , ( unsigned ) state - > max_setup ,
( unsigned ) state - > num_param , ( unsigned ) this_param ,
( unsigned ) state - > rparam . max ,
( unsigned ) state - > num_data , ( unsigned ) this_data ,
( unsigned ) state - > rdata . max ,
( unsigned ) param_offset , ( unsigned ) param_pad ,
( unsigned ) state - > param_sent ,
( unsigned ) data_offset , ( unsigned ) data_pad ,
( unsigned ) state - > data_sent ) ) ;
switch ( cmd ) {
case SMBtrans :
case SMBtrans2 :
SSVAL ( vwv + 0 , 0 , state - > num_param ) ;
SSVAL ( vwv + 1 , 0 , state - > num_data ) ;
SSVAL ( vwv + 2 , 0 , state - > rparam . max ) ;
SSVAL ( vwv + 3 , 0 , state - > rdata . max ) ;
SCVAL ( vwv + 4 , 0 , state - > max_setup ) ;
SCVAL ( vwv + 4 , 1 , 0 ) ; /* reserved */
SSVAL ( vwv + 5 , 0 , state - > flags ) ;
SIVAL ( vwv + 6 , 0 , 0 ) ; /* timeout */
SSVAL ( vwv + 8 , 0 , 0 ) ; /* reserved */
SSVAL ( vwv + 9 , 0 , this_param ) ;
SSVAL ( vwv + 10 , 0 , param_offset ) ;
SSVAL ( vwv + 11 , 0 , this_data ) ;
SSVAL ( vwv + 12 , 0 , data_offset ) ;
SCVAL ( vwv + 13 , 0 , state - > num_setup ) ;
SCVAL ( vwv + 13 , 1 , 0 ) ; /* reserved */
2019-06-05 23:40:42 +03:00
if ( state - > num_setup > 0 ) {
memcpy ( vwv + 14 , state - > setup ,
sizeof ( uint16_t ) * state - > num_setup ) ;
}
2011-09-18 01:34:12 +04:00
break ;
case SMBtranss :
case SMBtranss2 :
SSVAL ( vwv + 0 , 0 , state - > num_param ) ;
SSVAL ( vwv + 1 , 0 , state - > num_data ) ;
SSVAL ( vwv + 2 , 0 , this_param ) ;
SSVAL ( vwv + 3 , 0 , param_offset ) ;
SSVAL ( vwv + 4 , 0 , state - > param_sent ) ;
SSVAL ( vwv + 5 , 0 , this_data ) ;
SSVAL ( vwv + 6 , 0 , data_offset ) ;
SSVAL ( vwv + 7 , 0 , state - > data_sent ) ;
if ( cmd = = SMBtranss2 ) {
SSVAL ( vwv + 8 , 0 , state - > fid ) ;
}
break ;
case SMBnttrans :
SCVAL ( vwv + 0 , 0 , state - > max_setup ) ;
SSVAL ( vwv + 0 , 1 , 0 ) ; /* reserved */
SIVAL ( vwv + 1 , 1 , state - > num_param ) ;
SIVAL ( vwv + 3 , 1 , state - > num_data ) ;
SIVAL ( vwv + 5 , 1 , state - > rparam . max ) ;
SIVAL ( vwv + 7 , 1 , state - > rdata . max ) ;
SIVAL ( vwv + 9 , 1 , this_param ) ;
SIVAL ( vwv + 11 , 1 , param_offset ) ;
SIVAL ( vwv + 13 , 1 , this_data ) ;
SIVAL ( vwv + 15 , 1 , data_offset ) ;
SCVAL ( vwv + 17 , 1 , state - > num_setup ) ;
SSVAL ( vwv + 18 , 0 , state - > function ) ;
memcpy ( vwv + 19 , state - > setup ,
sizeof ( uint16_t ) * state - > num_setup ) ;
break ;
case SMBnttranss :
SSVAL ( vwv + 0 , 0 , 0 ) ; /* reserved */
SCVAL ( vwv + 1 , 0 , 0 ) ; /* reserved */
SIVAL ( vwv + 1 , 1 , state - > num_param ) ;
SIVAL ( vwv + 3 , 1 , state - > num_data ) ;
SIVAL ( vwv + 5 , 1 , this_param ) ;
SIVAL ( vwv + 7 , 1 , param_offset ) ;
SIVAL ( vwv + 9 , 1 , state - > param_sent ) ;
SIVAL ( vwv + 11 , 1 , this_data ) ;
SIVAL ( vwv + 13 , 1 , data_offset ) ;
SIVAL ( vwv + 15 , 1 , state - > data_sent ) ;
SCVAL ( vwv + 17 , 1 , 0 ) ; /* reserved */
break ;
}
state - > param_sent + = this_param ;
state - > data_sent + = this_data ;
* pwct = wct ;
* piov_count = iov - state - > iov ;
}
2011-11-28 13:41:25 +04:00
static bool smb1cli_trans_cancel ( struct tevent_req * req ) ;
2011-09-18 01:38:09 +04:00
static void smb1cli_trans_done ( struct tevent_req * subreq ) ;
2011-09-18 01:34:12 +04:00
2011-09-18 01:38:09 +04:00
struct tevent_req * smb1cli_trans_send (
2011-09-18 01:34:12 +04:00
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
2011-09-18 01:38:09 +04:00
struct smbXcli_conn * conn , uint8_t cmd ,
uint8_t additional_flags , uint8_t clear_flags ,
uint16_t additional_flags2 , uint16_t clear_flags2 ,
uint32_t timeout_msec ,
2012-07-23 23:34:58 +04:00
uint32_t pid ,
struct smbXcli_tcon * tcon ,
2012-07-23 22:15:21 +04:00
struct smbXcli_session * session ,
2011-09-18 01:34:12 +04:00
const char * pipe_name , uint16_t fid , uint16_t function , int flags ,
uint16_t * setup , uint8_t num_setup , uint8_t max_setup ,
uint8_t * param , uint32_t num_param , uint32_t max_param ,
uint8_t * data , uint32_t num_data , uint32_t max_data )
{
struct tevent_req * req , * subreq ;
2011-09-18 01:38:09 +04:00
struct smb1cli_trans_state * state ;
2011-09-18 01:34:12 +04:00
int iov_count ;
uint8_t wct ;
NTSTATUS status ;
2011-09-18 01:38:09 +04:00
charset_t charset ;
2011-09-18 01:34:12 +04:00
2011-09-18 01:38:09 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct smb1cli_trans_state ) ;
2011-09-18 01:34:12 +04:00
if ( req = = NULL ) {
return NULL ;
}
if ( ( cmd = = SMBtrans ) | | ( cmd = = SMBtrans2 ) ) {
if ( ( num_param > 0xffff ) | | ( max_param > 0xffff )
| | ( num_data > 0xffff ) | | ( max_data > 0xffff ) ) {
DEBUG ( 3 , ( " Attempt to send invalid trans2 request "
" (setup %u, params %u/%u, data %u/%u) \n " ,
( unsigned ) num_setup ,
( unsigned ) num_param , ( unsigned ) max_param ,
( unsigned ) num_data , ( unsigned ) max_data ) ) ;
2011-09-18 01:38:09 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER_MIX ) ;
2011-09-18 01:34:12 +04:00
return tevent_req_post ( req , ev ) ;
}
}
/*
* The largest wct will be for nttrans ( 19 + num_setup ) . Make sure we
2011-09-18 01:38:09 +04:00
* don ' t overflow state - > vwv in smb1cli_trans_format .
2011-09-18 01:34:12 +04:00
*/
if ( ( num_setup + 19 ) > ARRAY_SIZE ( state - > vwv ) ) {
2011-09-18 01:38:09 +04:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER_MIX ) ;
2011-09-18 01:34:12 +04:00
return tevent_req_post ( req , ev ) ;
}
2011-09-18 01:38:09 +04:00
state - > conn = conn ;
2011-09-18 01:34:12 +04:00
state - > ev = ev ;
state - > cmd = cmd ;
2011-09-18 01:38:09 +04:00
state - > additional_flags = additional_flags ;
state - > clear_flags = clear_flags ;
state - > additional_flags2 = additional_flags2 ;
state - > clear_flags2 = clear_flags2 ;
state - > timeout_msec = timeout_msec ;
2011-09-18 01:34:12 +04:00
state - > flags = flags ;
state - > num_rsetup = 0 ;
state - > rsetup = NULL ;
2011-09-18 01:38:09 +04:00
state - > pid = pid ;
2012-07-23 23:34:58 +04:00
state - > tcon = tcon ;
2012-07-23 22:15:21 +04:00
state - > session = session ;
2011-09-18 01:34:12 +04:00
ZERO_STRUCT ( state - > rparam ) ;
ZERO_STRUCT ( state - > rdata ) ;
2011-09-18 01:38:09 +04:00
if ( smbXcli_conn_use_unicode ( conn ) ) {
charset = CH_UTF16LE ;
} else {
charset = CH_DOS ;
}
2011-09-18 01:34:12 +04:00
if ( ( pipe_name ! = NULL )
2011-09-18 01:38:09 +04:00
& & ( ! convert_string_talloc ( state , CH_UNIX , charset ,
2011-09-18 01:34:12 +04:00
pipe_name , strlen ( pipe_name ) + 1 ,
& state - > pipe_name_conv ,
& state - > pipe_name_conv_len ) ) ) {
tevent_req_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return tevent_req_post ( req , ev ) ;
}
state - > fid = fid ; /* trans2 */
state - > function = function ; /* nttrans */
state - > setup = setup ;
state - > num_setup = num_setup ;
state - > max_setup = max_setup ;
state - > param = param ;
state - > num_param = num_param ;
state - > param_sent = 0 ;
state - > rparam . max = max_param ;
state - > data = data ;
state - > num_data = num_data ;
state - > data_sent = 0 ;
state - > rdata . max = max_data ;
2011-09-18 01:38:09 +04:00
smb1cli_trans_format ( state , & wct , & iov_count ) ;
2011-09-18 01:34:12 +04:00
2011-09-18 01:38:09 +04:00
subreq = smb1cli_req_create ( state , ev , conn , cmd ,
state - > additional_flags ,
state - > clear_flags ,
state - > additional_flags2 ,
state - > clear_flags2 ,
state - > timeout_msec ,
2012-07-23 23:34:58 +04:00
state - > pid ,
state - > tcon ,
2012-07-23 22:15:21 +04:00
state - > session ,
2011-09-18 01:38:09 +04:00
wct , state - > vwv ,
2011-09-18 01:34:12 +04:00
iov_count , state - > iov ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2011-09-18 01:38:09 +04:00
status = smb1cli_req_chain_submit ( & subreq , 1 ) ;
if ( tevent_req_nterror ( req , status ) ) {
2011-09-18 01:34:12 +04:00
return tevent_req_post ( req , state - > ev ) ;
}
2011-09-18 01:38:09 +04:00
tevent_req_set_callback ( subreq , smb1cli_trans_done , req ) ;
2011-09-18 01:34:12 +04:00
/*
* Now get the MID of the primary request
* and mark it as persistent . This means
* we will able to send and receive multiple
* SMB pdus using this MID in both directions
* ( including correct SMB signing ) .
*/
2011-09-18 01:38:09 +04:00
state - > mid = smb1cli_req_mid ( subreq ) ;
smb1cli_req_set_mid ( subreq , state - > mid ) ;
2011-09-18 01:34:12 +04:00
state - > primary_subreq = subreq ;
2011-09-18 01:38:09 +04:00
talloc_set_destructor ( state , smb1cli_trans_state_destructor ) ;
2011-09-18 01:34:12 +04:00
2011-11-28 13:41:25 +04:00
tevent_req_set_cancel_fn ( req , smb1cli_trans_cancel ) ;
2011-09-18 01:34:12 +04:00
return req ;
}
2011-11-28 13:41:25 +04:00
static bool smb1cli_trans_cancel ( struct tevent_req * req )
{
struct smb1cli_trans_state * state =
tevent_req_data ( req ,
struct smb1cli_trans_state ) ;
if ( state - > primary_subreq = = NULL ) {
return false ;
}
return tevent_req_cancel ( state - > primary_subreq ) ;
}
2011-09-18 01:38:09 +04:00
static void smb1cli_trans_done2 ( struct tevent_req * subreq ) ;
2011-09-18 01:34:12 +04:00
2011-09-18 01:38:09 +04:00
static void smb1cli_trans_done ( struct tevent_req * subreq )
2011-09-18 01:34:12 +04:00
{
2011-09-18 01:38:09 +04:00
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smb1cli_trans_state * state =
tevent_req_data ( req ,
struct smb1cli_trans_state ) ;
2011-09-18 01:34:12 +04:00
NTSTATUS status ;
bool sent_all ;
2011-09-18 01:38:09 +04:00
struct iovec * recv_iov = NULL ;
uint8_t * inhdr ;
2011-09-18 01:34:12 +04:00
uint8_t wct ;
uint16_t * vwv ;
2011-09-18 01:38:09 +04:00
uint32_t vwv_ofs ;
2011-09-18 01:34:12 +04:00
uint32_t num_bytes ;
uint8_t * bytes ;
2011-09-18 01:38:09 +04:00
uint32_t bytes_ofs ;
2011-09-18 01:34:12 +04:00
uint8_t num_setup = 0 ;
uint16_t * setup = NULL ;
uint32_t total_param = 0 ;
uint32_t num_param = 0 ;
uint32_t param_disp = 0 ;
uint32_t total_data = 0 ;
uint32_t num_data = 0 ;
uint32_t data_disp = 0 ;
uint8_t * param = NULL ;
uint8_t * data = NULL ;
2011-09-18 01:38:09 +04:00
status = smb1cli_req_recv ( subreq , state ,
& recv_iov ,
& inhdr ,
& wct ,
& vwv ,
& vwv_ofs ,
& num_bytes ,
& bytes ,
& bytes_ofs ,
NULL , /* pinbuf */
NULL , 0 ) ; /* expected */
2011-09-18 01:34:12 +04:00
/*
* Do not TALLOC_FREE ( subreq ) here , we might receive more than
* one response for the same mid .
*/
/*
* We can receive something like STATUS_MORE_ENTRIES , so don ' t use
* ! NT_STATUS_IS_OK ( status ) here .
*/
if ( NT_STATUS_IS_ERR ( status ) ) {
goto fail ;
}
2011-11-28 12:15:11 +04:00
if ( recv_iov = = NULL ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto fail ;
}
state - > status = status ;
2011-09-18 01:34:12 +04:00
sent_all = ( ( state - > param_sent = = state - > num_param )
& & ( state - > data_sent = = state - > num_data ) ) ;
2011-09-18 01:38:09 +04:00
status = smb1cli_pull_trans (
inhdr , wct , vwv , vwv_ofs ,
num_bytes , bytes , bytes_ofs ,
2011-09-18 01:34:12 +04:00
state - > cmd , ! sent_all , & num_setup , & setup ,
& total_param , & num_param , & param_disp , & param ,
& total_data , & num_data , & data_disp , & data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
if ( ! sent_all ) {
int iov_count ;
struct tevent_req * subreq2 ;
2011-09-18 01:38:09 +04:00
smb1cli_trans_format ( state , & wct , & iov_count ) ;
subreq2 = smb1cli_req_create ( state , state - > ev , state - > conn ,
state - > cmd + 1 ,
state - > additional_flags ,
state - > clear_flags ,
state - > additional_flags2 ,
state - > clear_flags2 ,
state - > timeout_msec ,
2012-07-23 23:34:58 +04:00
state - > pid ,
state - > tcon ,
2012-07-23 22:15:21 +04:00
state - > session ,
2011-09-18 01:38:09 +04:00
wct , state - > vwv ,
2011-09-18 01:34:12 +04:00
iov_count , state - > iov ) ;
if ( tevent_req_nomem ( subreq2 , req ) ) {
return ;
}
2011-09-18 01:38:09 +04:00
smb1cli_req_set_mid ( subreq2 , state - > mid ) ;
2011-09-18 01:34:12 +04:00
2011-09-18 01:38:09 +04:00
status = smb1cli_req_chain_submit ( & subreq2 , 1 ) ;
2011-09-18 01:34:12 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2011-09-18 01:38:09 +04:00
tevent_req_set_callback ( subreq2 , smb1cli_trans_done2 , req ) ;
2011-09-18 01:34:12 +04:00
return ;
}
2011-09-18 01:38:09 +04:00
status = smb1cli_trans_pull_blob (
2011-09-18 01:34:12 +04:00
state , & state - > rparam , total_param , num_param , param ,
param_disp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Pulling params failed: %s \n " , nt_errstr ( status ) ) ) ;
goto fail ;
}
2011-09-18 01:38:09 +04:00
status = smb1cli_trans_pull_blob (
2011-09-18 01:34:12 +04:00
state , & state - > rdata , total_data , num_data , data ,
data_disp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Pulling data failed: %s \n " , nt_errstr ( status ) ) ) ;
goto fail ;
}
if ( ( state - > rparam . total = = state - > rparam . received )
& & ( state - > rdata . total = = state - > rdata . received ) ) {
state - > recv_flags2 = SVAL ( inhdr , HDR_FLG2 ) ;
2011-09-18 01:38:09 +04:00
smb1cli_trans_cleanup_primary ( state ) ;
2011-09-18 01:34:12 +04:00
tevent_req_done ( req ) ;
return ;
}
2011-09-18 01:38:09 +04:00
TALLOC_FREE ( recv_iov ) ;
2011-09-18 01:34:12 +04:00
return ;
fail :
2011-09-18 01:38:09 +04:00
smb1cli_trans_cleanup_primary ( state ) ;
2011-09-18 01:34:12 +04:00
tevent_req_nterror ( req , status ) ;
}
2011-09-18 01:38:09 +04:00
static void smb1cli_trans_done2 ( struct tevent_req * subreq2 )
2011-09-18 01:34:12 +04:00
{
2011-09-18 01:38:09 +04:00
struct tevent_req * req =
tevent_req_callback_data ( subreq2 ,
struct tevent_req ) ;
struct smb1cli_trans_state * state =
tevent_req_data ( req ,
struct smb1cli_trans_state ) ;
2011-09-18 01:34:12 +04:00
NTSTATUS status ;
bool sent_all ;
uint32_t seqnum ;
/*
* First backup the seqnum of the secondary request
* and attach it to the primary request .
*/
2011-09-18 01:38:09 +04:00
seqnum = smb1cli_req_seqnum ( subreq2 ) ;
smb1cli_req_set_seqnum ( state - > primary_subreq , seqnum ) ;
/* This was a one way request */
status = smb1cli_req_recv ( subreq2 , state ,
NULL , /* recv_iov */
NULL , /* phdr */
NULL , /* pwct */
NULL , /* pvwv */
NULL , /* pvwv_offset */
NULL , /* pnum_bytes */
NULL , /* pbytes */
NULL , /* pbytes_offset */
NULL , /* pinbuf */
NULL , 0 ) ; /* expected */
2011-09-18 01:34:12 +04:00
TALLOC_FREE ( subreq2 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
sent_all = ( ( state - > param_sent = = state - > num_param )
& & ( state - > data_sent = = state - > num_data ) ) ;
if ( ! sent_all ) {
2011-09-18 01:38:09 +04:00
uint8_t wct ;
2011-09-18 01:34:12 +04:00
int iov_count ;
2011-09-18 01:38:09 +04:00
smb1cli_trans_format ( state , & wct , & iov_count ) ;
subreq2 = smb1cli_req_create ( state , state - > ev , state - > conn ,
state - > cmd + 1 ,
state - > additional_flags ,
state - > clear_flags ,
state - > additional_flags2 ,
state - > clear_flags2 ,
state - > timeout_msec ,
2012-07-23 23:34:58 +04:00
state - > pid ,
state - > tcon ,
2012-07-23 22:15:21 +04:00
state - > session ,
2011-09-18 01:38:09 +04:00
wct , state - > vwv ,
2011-09-18 01:34:12 +04:00
iov_count , state - > iov ) ;
if ( tevent_req_nomem ( subreq2 , req ) ) {
return ;
}
2011-09-18 01:38:09 +04:00
smb1cli_req_set_mid ( subreq2 , state - > mid ) ;
2011-09-18 01:34:12 +04:00
2011-09-18 01:38:09 +04:00
status = smb1cli_req_chain_submit ( & subreq2 , 1 ) ;
2011-09-18 01:34:12 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2011-09-18 01:38:09 +04:00
tevent_req_set_callback ( subreq2 , smb1cli_trans_done2 , req ) ;
2011-09-18 01:34:12 +04:00
return ;
}
return ;
fail :
2011-09-18 01:38:09 +04:00
smb1cli_trans_cleanup_primary ( state ) ;
2011-09-18 01:34:12 +04:00
tevent_req_nterror ( req , status ) ;
}
2011-09-18 01:38:09 +04:00
NTSTATUS smb1cli_trans_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
uint16_t * recv_flags2 ,
uint16_t * * setup , uint8_t min_setup ,
uint8_t * num_setup ,
uint8_t * * param , uint32_t min_param ,
uint32_t * num_param ,
uint8_t * * data , uint32_t min_data ,
uint32_t * num_data )
2011-09-18 01:34:12 +04:00
{
2011-09-18 01:38:09 +04:00
struct smb1cli_trans_state * state =
tevent_req_data ( req ,
struct smb1cli_trans_state ) ;
2011-09-18 01:34:12 +04:00
NTSTATUS status ;
2011-09-18 01:38:09 +04:00
smb1cli_trans_cleanup_primary ( state ) ;
2011-09-18 01:34:12 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2011-11-28 12:15:11 +04:00
if ( ! NT_STATUS_IS_ERR ( status ) ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
tevent_req_received ( req ) ;
2011-09-18 01:34:12 +04:00
return status ;
}
if ( ( state - > num_rsetup < min_setup )
| | ( state - > rparam . total < min_param )
| | ( state - > rdata . total < min_data ) ) {
2011-11-28 12:15:11 +04:00
tevent_req_received ( req ) ;
2011-09-18 01:34:12 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( recv_flags2 ! = NULL ) {
* recv_flags2 = state - > recv_flags2 ;
}
if ( setup ! = NULL ) {
* setup = talloc_move ( mem_ctx , & state - > rsetup ) ;
* num_setup = state - > num_rsetup ;
} else {
TALLOC_FREE ( state - > rsetup ) ;
}
if ( param ! = NULL ) {
* param = talloc_move ( mem_ctx , & state - > rparam . data ) ;
* num_param = state - > rparam . total ;
} else {
TALLOC_FREE ( state - > rparam . data ) ;
}
if ( data ! = NULL ) {
* data = talloc_move ( mem_ctx , & state - > rdata . data ) ;
* num_data = state - > rdata . total ;
} else {
TALLOC_FREE ( state - > rdata . data ) ;
}
2011-11-28 12:15:11 +04:00
status = state - > status ;
tevent_req_received ( req ) ;
return status ;
2011-09-18 01:34:12 +04:00
}
2011-09-18 01:38:09 +04:00
NTSTATUS smb1cli_trans ( TALLOC_CTX * mem_ctx , struct smbXcli_conn * conn ,
uint8_t trans_cmd ,
uint8_t additional_flags , uint8_t clear_flags ,
uint16_t additional_flags2 , uint16_t clear_flags2 ,
uint32_t timeout_msec ,
2012-07-23 23:34:58 +04:00
uint32_t pid ,
struct smbXcli_tcon * tcon ,
2012-07-23 22:15:21 +04:00
struct smbXcli_session * session ,
2011-09-18 01:38:09 +04:00
const char * pipe_name , uint16_t fid , uint16_t function ,
int flags ,
uint16_t * setup , uint8_t num_setup , uint8_t max_setup ,
uint8_t * param , uint32_t num_param , uint32_t max_param ,
uint8_t * data , uint32_t num_data , uint32_t max_data ,
uint16_t * recv_flags2 ,
uint16_t * * rsetup , uint8_t min_rsetup , uint8_t * num_rsetup ,
uint8_t * * rparam , uint32_t min_rparam , uint32_t * num_rparam ,
uint8_t * * rdata , uint32_t min_rdata , uint32_t * num_rdata )
2011-09-18 01:34:12 +04:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
2015-06-26 17:15:18 +03:00
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2011-09-18 01:34:12 +04:00
2011-09-18 01:38:09 +04:00
if ( smbXcli_conn_has_async_calls ( conn ) ) {
2011-09-18 01:34:12 +04:00
/*
* Can ' t use sync call while an async call is in flight
*/
2011-09-18 01:38:09 +04:00
status = NT_STATUS_INVALID_PARAMETER_MIX ;
2011-09-18 01:34:12 +04:00
goto fail ;
}
2013-02-18 12:07:11 +04:00
ev = samba_tevent_context_init ( frame ) ;
2011-09-18 01:34:12 +04:00
if ( ev = = NULL ) {
goto fail ;
}
2011-09-18 01:38:09 +04:00
req = smb1cli_trans_send ( frame , ev , conn , trans_cmd ,
additional_flags , clear_flags ,
additional_flags2 , clear_flags2 ,
timeout_msec ,
2012-07-23 23:34:58 +04:00
pid , tcon , session ,
2011-09-18 01:38:09 +04:00
pipe_name , fid , function , flags ,
setup , num_setup , max_setup ,
param , num_param , max_param ,
data , num_data , max_data ) ;
2011-09-18 01:34:12 +04:00
if ( req = = NULL ) {
goto fail ;
}
2015-02-25 23:42:33 +03:00
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
2011-09-18 01:34:12 +04:00
goto fail ;
}
2011-09-18 01:38:09 +04:00
status = smb1cli_trans_recv ( req , mem_ctx , recv_flags2 ,
rsetup , min_rsetup , num_rsetup ,
rparam , min_rparam , num_rparam ,
rdata , min_rdata , num_rdata ) ;
2011-09-18 01:34:12 +04:00
fail :
TALLOC_FREE ( frame ) ;
return status ;
}