2000-04-25 18:04:06 +04:00
/*
Unix SMB / Netbios implementation .
Version 3.0
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# define NO_SYSLOG
# include "includes.h"
/****************************************************************************
send a SMB trans or trans2 request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_send_trans ( struct cli_state * cli , int trans ,
2001-07-04 11:15:53 +04:00
const char * pipe_name ,
2000-04-25 18:04:06 +04:00
int fid , int flags ,
uint16 * setup , int lsetup , int msetup ,
char * param , int lparam , int mparam ,
char * data , int ldata , int mdata )
{
int i ;
int this_ldata , this_lparam ;
int tot_data = 0 , tot_param = 0 ;
char * outdata , * outparam ;
char * p ;
2001-02-20 13:11:40 +03:00
int pipe_name_len = 0 ;
2000-04-25 18:04:06 +04:00
this_lparam = MIN ( lparam , cli - > max_xmit - ( 500 + lsetup * 2 ) ) ; /* hack */
this_ldata = MIN ( ldata , cli - > max_xmit - ( 500 + lsetup * 2 + this_lparam ) ) ;
memset ( cli - > outbuf , ' \0 ' , smb_size ) ;
set_message ( cli - > outbuf , 14 + lsetup , 0 , True ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_com , trans ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_tid , cli - > cnum ) ;
cli_setup_packet ( cli ) ;
2001-02-20 13:11:40 +03:00
if ( pipe_name ) {
2001-03-14 15:42:43 +03:00
pipe_name_len = clistr_push ( cli , smb_buf ( cli - > outbuf ) , pipe_name , - 1 , STR_TERMINATE ) ;
2001-02-20 13:11:40 +03:00
}
outparam = smb_buf ( cli - > outbuf ) + ( trans = = SMBtrans ? pipe_name_len : 3 ) ;
2000-04-25 18:04:06 +04:00
outdata = outparam + this_lparam ;
/* primary request */
SSVAL ( cli - > outbuf , smb_tpscnt , lparam ) ; /* tpscnt */
SSVAL ( cli - > outbuf , smb_tdscnt , ldata ) ; /* tdscnt */
SSVAL ( cli - > outbuf , smb_mprcnt , mparam ) ; /* mprcnt */
SSVAL ( cli - > outbuf , smb_mdrcnt , mdata ) ; /* mdrcnt */
SCVAL ( cli - > outbuf , smb_msrcnt , msetup ) ; /* msrcnt */
SSVAL ( cli - > outbuf , smb_flags , flags ) ; /* flags */
SIVAL ( cli - > outbuf , smb_timeout , 0 ) ; /* timeout */
SSVAL ( cli - > outbuf , smb_pscnt , this_lparam ) ; /* pscnt */
SSVAL ( cli - > outbuf , smb_psoff , smb_offset ( outparam , cli - > outbuf ) ) ; /* psoff */
SSVAL ( cli - > outbuf , smb_dscnt , this_ldata ) ; /* dscnt */
SSVAL ( cli - > outbuf , smb_dsoff , smb_offset ( outdata , cli - > outbuf ) ) ; /* dsoff */
SCVAL ( cli - > outbuf , smb_suwcnt , lsetup ) ; /* suwcnt */
for ( i = 0 ; i < lsetup ; i + + ) /* setup[] */
SSVAL ( cli - > outbuf , smb_setup + i * 2 , setup [ i ] ) ;
p = smb_buf ( cli - > outbuf ) ;
2001-03-14 15:42:43 +03:00
if ( trans ! = SMBtrans ) {
2000-04-25 18:04:06 +04:00
* p + + = 0 ; /* put in a null smb_name */
* p + + = ' D ' ; * p + + = ' ' ; /* observed in OS/2 */
}
if ( this_lparam ) /* param[] */
memcpy ( outparam , param , this_lparam ) ;
if ( this_ldata ) /* data[] */
memcpy ( outdata , data , this_ldata ) ;
2001-02-20 15:45:50 +03:00
cli_setup_bcc ( cli , outdata + this_ldata ) ;
2000-04-25 18:04:06 +04:00
show_msg ( cli - > outbuf ) ;
cli_send_smb ( cli ) ;
if ( this_ldata < ldata | | this_lparam < lparam ) {
/* receive interim response */
if ( ! cli_receive_smb ( cli ) | |
2001-09-05 15:32:59 +04:00
cli_is_error ( cli ) ) {
2000-04-25 18:04:06 +04:00
return ( False ) ;
}
tot_data = this_ldata ;
tot_param = this_lparam ;
while ( tot_data < ldata | | tot_param < lparam ) {
this_lparam = MIN ( lparam - tot_param , cli - > max_xmit - 500 ) ; /* hack */
this_ldata = MIN ( ldata - tot_data , cli - > max_xmit - ( 500 + this_lparam ) ) ;
set_message ( cli - > outbuf , trans = = SMBtrans ? 8 : 9 , 0 , True ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_com , ( trans = = SMBtrans ? SMBtranss : SMBtranss2 ) ) ;
2000-04-25 18:04:06 +04:00
outparam = smb_buf ( cli - > outbuf ) ;
outdata = outparam + this_lparam ;
/* secondary request */
SSVAL ( cli - > outbuf , smb_tpscnt , lparam ) ; /* tpscnt */
SSVAL ( cli - > outbuf , smb_tdscnt , ldata ) ; /* tdscnt */
SSVAL ( cli - > outbuf , smb_spscnt , this_lparam ) ; /* pscnt */
SSVAL ( cli - > outbuf , smb_spsoff , smb_offset ( outparam , cli - > outbuf ) ) ; /* psoff */
SSVAL ( cli - > outbuf , smb_spsdisp , tot_param ) ; /* psdisp */
SSVAL ( cli - > outbuf , smb_sdscnt , this_ldata ) ; /* dscnt */
SSVAL ( cli - > outbuf , smb_sdsoff , smb_offset ( outdata , cli - > outbuf ) ) ; /* dsoff */
SSVAL ( cli - > outbuf , smb_sdsdisp , tot_data ) ; /* dsdisp */
if ( trans = = SMBtrans2 )
SSVALS ( cli - > outbuf , smb_sfid , fid ) ; /* fid */
if ( this_lparam ) /* param[] */
memcpy ( outparam , param + tot_param , this_lparam ) ;
if ( this_ldata ) /* data[] */
memcpy ( outdata , data + tot_data , this_ldata ) ;
2001-02-20 15:45:50 +03:00
cli_setup_bcc ( cli , outdata + this_ldata ) ;
2000-04-25 18:04:06 +04:00
show_msg ( cli - > outbuf ) ;
cli_send_smb ( cli ) ;
tot_data + = this_ldata ;
tot_param + = this_lparam ;
}
}
return ( True ) ;
}
/****************************************************************************
receive a SMB trans or trans2 response allocating the necessary memory
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_receive_trans ( struct cli_state * cli , int trans ,
char * * param , int * param_len ,
char * * data , int * data_len )
{
int total_data = 0 ;
int total_param = 0 ;
int this_data , this_param ;
2001-08-27 21:52:23 +04:00
NTSTATUS status ;
2001-08-12 21:30:01 +04:00
char * tdata ;
2001-08-17 22:16:42 +04:00
char * tparam ;
2000-04-25 18:04:06 +04:00
* data_len = * param_len = 0 ;
if ( ! cli_receive_smb ( cli ) )
return False ;
show_msg ( cli - > inbuf ) ;
/* sanity check */
if ( CVAL ( cli - > inbuf , smb_com ) ! = trans ) {
DEBUG ( 0 , ( " Expected %s response, got command 0x%02x \n " ,
trans = = SMBtrans ? " SMBtrans " : " SMBtrans2 " ,
CVAL ( cli - > inbuf , smb_com ) ) ) ;
return ( False ) ;
}
/*
* An NT RPC pipe call can return ERRDOS , ERRmoredata
* to a trans call . This is not an error and should not
* be treated as such .
*/
2001-08-27 21:52:23 +04:00
status = cli_nt_error ( cli ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
2001-08-20 09:15:26 +04:00
return False ;
2000-04-25 18:04:06 +04:00
}
/* parse out the lengths */
total_data = SVAL ( cli - > inbuf , smb_tdrcnt ) ;
total_param = SVAL ( cli - > inbuf , smb_tprcnt ) ;
/* allocate it */
2001-08-17 21:07:40 +04:00
if ( total_data ! = 0 ) {
tdata = Realloc ( * data , total_data ) ;
if ( ! tdata ) {
DEBUG ( 0 , ( " cli_receive_trans: failed to enlarge data buffer \n " ) ) ;
return False ;
}
else
* data = tdata ;
2001-08-12 21:30:01 +04:00
}
2001-08-17 21:07:40 +04:00
if ( total_param ! = 0 ) {
2001-08-17 22:16:42 +04:00
tparam = Realloc ( * param , total_param ) ;
if ( ! tparam ) {
2001-08-17 21:07:40 +04:00
DEBUG ( 0 , ( " cli_receive_trans: failed to enlarge param buffer \n " ) ) ;
return False ;
}
else
2001-08-17 22:16:42 +04:00
* param = tparam ;
2001-08-12 21:30:01 +04:00
}
2000-04-25 18:04:06 +04:00
while ( 1 ) {
this_data = SVAL ( cli - > inbuf , smb_drcnt ) ;
this_param = SVAL ( cli - > inbuf , smb_prcnt ) ;
if ( this_data + * data_len > total_data | |
this_param + * param_len > total_param ) {
DEBUG ( 1 , ( " Data overflow in cli_receive_trans \n " ) ) ;
return False ;
}
if ( this_data )
memcpy ( * data + SVAL ( cli - > inbuf , smb_drdisp ) ,
smb_base ( cli - > inbuf ) + SVAL ( cli - > inbuf , smb_droff ) ,
this_data ) ;
if ( this_param )
memcpy ( * param + SVAL ( cli - > inbuf , smb_prdisp ) ,
smb_base ( cli - > inbuf ) + SVAL ( cli - > inbuf , smb_proff ) ,
this_param ) ;
* data_len + = this_data ;
* param_len + = this_param ;
/* parse out the total lengths again - they can shrink! */
total_data = SVAL ( cli - > inbuf , smb_tdrcnt ) ;
total_param = SVAL ( cli - > inbuf , smb_tprcnt ) ;
if ( total_data < = * data_len & & total_param < = * param_len )
break ;
if ( ! cli_receive_smb ( cli ) )
return False ;
show_msg ( cli - > inbuf ) ;
/* sanity check */
if ( CVAL ( cli - > inbuf , smb_com ) ! = trans ) {
DEBUG ( 0 , ( " Expected %s response, got command 0x%02x \n " ,
trans = = SMBtrans ? " SMBtrans " : " SMBtrans2 " ,
CVAL ( cli - > inbuf , smb_com ) ) ) ;
return ( False ) ;
}
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_IS_ERR ( cli_nt_error ( cli ) ) ) {
return ( False ) ;
2000-04-25 18:04:06 +04:00
}
}
return ( True ) ;
}
2000-12-03 05:18:14 +03:00
/****************************************************************************
send a SMB nttrans request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_send_nt_trans ( struct cli_state * cli ,
int function ,
int flags ,
uint16 * setup , int lsetup , int msetup ,
char * param , int lparam , int mparam ,
char * data , int ldata , int mdata )
{
int i ;
int this_ldata , this_lparam ;
int tot_data = 0 , tot_param = 0 ;
char * outdata , * outparam ;
this_lparam = MIN ( lparam , cli - > max_xmit - ( 500 + lsetup * 2 ) ) ; /* hack */
this_ldata = MIN ( ldata , cli - > max_xmit - ( 500 + lsetup * 2 + this_lparam ) ) ;
memset ( cli - > outbuf , ' \0 ' , smb_size ) ;
set_message ( cli - > outbuf , 19 + lsetup , 0 , True ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_com , SMBnttrans ) ;
2000-12-03 05:18:14 +03:00
SSVAL ( cli - > outbuf , smb_tid , cli - > cnum ) ;
cli_setup_packet ( cli ) ;
outparam = smb_buf ( cli - > outbuf ) + 3 ;
outdata = outparam + this_lparam ;
/* primary request */
SCVAL ( cli - > outbuf , smb_nt_MaxSetupCount , msetup ) ;
SCVAL ( cli - > outbuf , smb_nt_Flags , flags ) ;
SIVAL ( cli - > outbuf , smb_nt_TotalParameterCount , lparam ) ;
SIVAL ( cli - > outbuf , smb_nt_TotalDataCount , ldata ) ;
SIVAL ( cli - > outbuf , smb_nt_MaxParameterCount , mparam ) ;
SIVAL ( cli - > outbuf , smb_nt_MaxDataCount , mdata ) ;
SIVAL ( cli - > outbuf , smb_nt_ParameterCount , this_lparam ) ;
SIVAL ( cli - > outbuf , smb_nt_ParameterOffset , smb_offset ( outparam , cli - > outbuf ) ) ;
SIVAL ( cli - > outbuf , smb_nt_DataCount , this_ldata ) ;
SIVAL ( cli - > outbuf , smb_nt_DataOffset , smb_offset ( outdata , cli - > outbuf ) ) ;
SIVAL ( cli - > outbuf , smb_nt_SetupCount , lsetup ) ;
SIVAL ( cli - > outbuf , smb_nt_Function , function ) ;
for ( i = 0 ; i < lsetup ; i + + ) /* setup[] */
SSVAL ( cli - > outbuf , smb_nt_SetupStart + i * 2 , setup [ i ] ) ;
if ( this_lparam ) /* param[] */
memcpy ( outparam , param , this_lparam ) ;
if ( this_ldata ) /* data[] */
memcpy ( outdata , data , this_ldata ) ;
2001-02-20 15:45:50 +03:00
cli_setup_bcc ( cli , outdata + this_ldata ) ;
2000-12-03 05:18:14 +03:00
show_msg ( cli - > outbuf ) ;
cli_send_smb ( cli ) ;
if ( this_ldata < ldata | | this_lparam < lparam ) {
/* receive interim response */
if ( ! cli_receive_smb ( cli ) | |
2001-09-05 15:32:59 +04:00
cli_is_error ( cli ) ) {
2000-12-03 05:18:14 +03:00
return ( False ) ;
}
tot_data = this_ldata ;
tot_param = this_lparam ;
while ( tot_data < ldata | | tot_param < lparam ) {
this_lparam = MIN ( lparam - tot_param , cli - > max_xmit - 500 ) ; /* hack */
this_ldata = MIN ( ldata - tot_data , cli - > max_xmit - ( 500 + this_lparam ) ) ;
set_message ( cli - > outbuf , 18 , 0 , True ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_com , SMBnttranss ) ;
2000-12-03 05:18:14 +03:00
/* XXX - these should probably be aligned */
outparam = smb_buf ( cli - > outbuf ) ;
outdata = outparam + this_lparam ;
/* secondary request */
SIVAL ( cli - > outbuf , smb_nts_TotalParameterCount , lparam ) ;
SIVAL ( cli - > outbuf , smb_nts_TotalDataCount , ldata ) ;
SIVAL ( cli - > outbuf , smb_nts_ParameterCount , this_lparam ) ;
SIVAL ( cli - > outbuf , smb_nts_ParameterOffset , smb_offset ( outparam , cli - > outbuf ) ) ;
SIVAL ( cli - > outbuf , smb_nts_ParameterDisplacement , tot_param ) ;
SIVAL ( cli - > outbuf , smb_nts_DataCount , this_ldata ) ;
SIVAL ( cli - > outbuf , smb_nts_DataOffset , smb_offset ( outdata , cli - > outbuf ) ) ;
SIVAL ( cli - > outbuf , smb_nts_DataDisplacement , tot_data ) ;
if ( this_lparam ) /* param[] */
memcpy ( outparam , param + tot_param , this_lparam ) ;
if ( this_ldata ) /* data[] */
memcpy ( outdata , data + tot_data , this_ldata ) ;
2001-02-20 15:45:50 +03:00
cli_setup_bcc ( cli , outdata + this_ldata ) ;
2000-12-03 05:18:14 +03:00
show_msg ( cli - > outbuf ) ;
cli_send_smb ( cli ) ;
tot_data + = this_ldata ;
tot_param + = this_lparam ;
}
}
return ( True ) ;
}
/****************************************************************************
receive a SMB nttrans response allocating the necessary memory
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_receive_nt_trans ( struct cli_state * cli ,
char * * param , int * param_len ,
char * * data , int * data_len )
{
int total_data = 0 ;
int total_param = 0 ;
int this_data , this_param ;
uint8 eclass ;
uint32 ecode ;
2001-08-12 21:30:01 +04:00
char * tdata ;
2001-08-17 22:16:42 +04:00
char * tparam ;
2000-12-03 05:18:14 +03:00
* data_len = * param_len = 0 ;
if ( ! cli_receive_smb ( cli ) )
return False ;
show_msg ( cli - > inbuf ) ;
/* sanity check */
if ( CVAL ( cli - > inbuf , smb_com ) ! = SMBnttrans ) {
DEBUG ( 0 , ( " Expected SMBnttrans response, got command 0x%02x \n " ,
CVAL ( cli - > inbuf , smb_com ) ) ) ;
return ( False ) ;
}
/*
* An NT RPC pipe call can return ERRDOS , ERRmoredata
* to a trans call . This is not an error and should not
* be treated as such .
*/
2001-08-10 10:00:33 +04:00
if ( cli_is_dos_error ( cli ) ) {
cli_dos_error ( cli , & eclass , & ecode ) ;
2000-12-03 05:18:14 +03:00
if ( cli - > nt_pipe_fnum = = 0 | | ! ( eclass = = ERRDOS & & ecode = = ERRmoredata ) )
return ( False ) ;
}
/* parse out the lengths */
total_data = SVAL ( cli - > inbuf , smb_ntr_TotalDataCount ) ;
total_param = SVAL ( cli - > inbuf , smb_ntr_TotalParameterCount ) ;
/* allocate it */
2001-08-27 12:19:43 +04:00
if ( total_data ) {
tdata = Realloc ( * data , total_data ) ;
if ( ! tdata ) {
DEBUG ( 0 , ( " cli_receive_nt_trans: failed to enlarge data buffer to %d \n " , total_data ) ) ;
return False ;
} else {
* data = tdata ;
}
2001-08-12 21:30:01 +04:00
}
2001-08-27 12:19:43 +04:00
if ( total_param ) {
tparam = Realloc ( * param , total_param ) ;
if ( ! tparam ) {
DEBUG ( 0 , ( " cli_receive_nt_trans: failed to enlarge param buffer to %d \n " , total_param ) ) ;
return False ;
} else {
* param = tparam ;
}
2001-08-12 21:30:01 +04:00
}
2000-12-03 05:18:14 +03:00
while ( 1 ) {
this_data = SVAL ( cli - > inbuf , smb_ntr_DataCount ) ;
this_param = SVAL ( cli - > inbuf , smb_ntr_ParameterCount ) ;
if ( this_data + * data_len > total_data | |
this_param + * param_len > total_param ) {
DEBUG ( 1 , ( " Data overflow in cli_receive_trans \n " ) ) ;
return False ;
}
if ( this_data )
memcpy ( * data + SVAL ( cli - > inbuf , smb_ntr_DataDisplacement ) ,
smb_base ( cli - > inbuf ) + SVAL ( cli - > inbuf , smb_ntr_DataOffset ) ,
this_data ) ;
if ( this_param )
memcpy ( * param + SVAL ( cli - > inbuf , smb_ntr_ParameterDisplacement ) ,
smb_base ( cli - > inbuf ) + SVAL ( cli - > inbuf , smb_ntr_ParameterOffset ) ,
this_param ) ;
* data_len + = this_data ;
* param_len + = this_param ;
/* parse out the total lengths again - they can shrink! */
total_data = SVAL ( cli - > inbuf , smb_ntr_TotalDataCount ) ;
total_param = SVAL ( cli - > inbuf , smb_ntr_TotalParameterCount ) ;
if ( total_data < = * data_len & & total_param < = * param_len )
break ;
if ( ! cli_receive_smb ( cli ) )
return False ;
show_msg ( cli - > inbuf ) ;
/* sanity check */
if ( CVAL ( cli - > inbuf , smb_com ) ! = SMBnttrans ) {
DEBUG ( 0 , ( " Expected SMBnttrans response, got command 0x%02x \n " ,
CVAL ( cli - > inbuf , smb_com ) ) ) ;
return ( False ) ;
}
2001-08-10 10:00:33 +04:00
if ( cli_is_dos_error ( cli ) ) {
cli_dos_error ( cli , & eclass , & ecode ) ;
if ( cli - > nt_pipe_fnum = = 0 | |
! ( eclass = = ERRDOS & & ecode = = ERRmoredata ) )
2000-12-03 05:18:14 +03:00
return ( False ) ;
}
}
return ( True ) ;
}