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-02-20 13:11:40 +03:00
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 ) ;
CVAL ( cli - > outbuf , smb_com ) = trans ;
SSVAL ( cli - > outbuf , smb_tid , cli - > cnum ) ;
cli_setup_packet ( cli ) ;
2001-02-20 13:11:40 +03:00
if ( pipe_name ) {
pipe_name_len = clistr_push_size ( cli , smb_buf ( cli - > outbuf ) ,
pipe_name , - 1 ,
CLISTR_TERMINATE ) ;
}
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 ) ;
if ( trans = = SMBtrans ) {
2001-02-20 13:11:40 +03:00
clistr_push ( cli , p , pipe_name , - 1 , CLISTR_TERMINATE ) ;
2000-04-25 18:04:06 +04:00
} else {
* 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 ) ;
set_message ( cli - > outbuf , 14 + lsetup , /* wcnt, bcc */
PTR_DIFF ( outdata + this_ldata , smb_buf ( cli - > outbuf ) ) , False ) ;
show_msg ( cli - > outbuf ) ;
cli_send_smb ( cli ) ;
if ( this_ldata < ldata | | this_lparam < lparam ) {
/* receive interim response */
if ( ! cli_receive_smb ( cli ) | |
CVAL ( cli - > inbuf , smb_rcls ) ! = 0 ) {
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 ) ;
CVAL ( cli - > outbuf , smb_com ) = trans = = SMBtrans ? SMBtranss : SMBtranss2 ;
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 ) ;
set_message ( cli - > outbuf , trans = = SMBtrans ? 8 : 9 , /* wcnt, bcc */
PTR_DIFF ( outdata + this_ldata , smb_buf ( cli - > outbuf ) ) , False ) ;
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 ;
uint8 eclass ;
uint32 ecode ;
* 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 .
*/
if ( cli_error ( cli , & eclass , & ecode , NULL ) )
{
2000-12-15 04:02:11 +03:00
if ( cli - > nt_pipe_fnum = = 0 )
2000-04-25 18:04:06 +04:00
return ( False ) ;
2000-12-15 04:02:11 +03:00
if ( ! ( eclass = = ERRDOS & & ecode = = ERRmoredata ) ) {
if ( eclass ! = 0 & & ( ecode ! = ( 0x80000000 | STATUS_BUFFER_OVERFLOW ) ) )
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 */
* data = Realloc ( * data , total_data ) ;
* param = Realloc ( * param , total_param ) ;
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 ) ;
}
if ( cli_error ( cli , & eclass , & ecode , NULL ) )
{
if ( cli - > nt_pipe_fnum = = 0 | | ! ( eclass = = ERRDOS & & ecode = = ERRmoredata ) )
return ( False ) ;
}
}
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 ) ;
CVAL ( cli - > outbuf , smb_com ) = SMBnttrans ;
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 ) ;
set_message ( cli - > outbuf , 19 + lsetup , /* wcnt, bcc */
PTR_DIFF ( outdata + this_ldata , smb_buf ( cli - > outbuf ) ) , False ) ;
show_msg ( cli - > outbuf ) ;
cli_send_smb ( cli ) ;
if ( this_ldata < ldata | | this_lparam < lparam ) {
/* receive interim response */
if ( ! cli_receive_smb ( cli ) | |
CVAL ( cli - > inbuf , smb_rcls ) ! = 0 ) {
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 ) ;
CVAL ( cli - > outbuf , smb_com ) = SMBnttranss ;
/* 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 ) ;
set_message ( cli - > outbuf , 18 ,
PTR_DIFF ( outdata + this_ldata , smb_buf ( cli - > outbuf ) ) , False ) ;
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 ;
* 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 .
*/
if ( cli_error ( cli , & eclass , & ecode , NULL ) ) {
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 */
* data = Realloc ( * data , total_data ) ;
* param = Realloc ( * param , total_param ) ;
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 ) ;
}
if ( cli_error ( cli , & eclass , & ecode , NULL ) ) {
if ( cli - > nt_pipe_fnum = = 0 | | ! ( eclass = = ERRDOS & & ecode = = ERRmoredata ) )
return ( False ) ;
}
}
return ( True ) ;
}