2000-04-25 18:04:06 +04:00
/*
Unix SMB / Netbios implementation .
Version 3.0
client RAP 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"
/****************************************************************************
Call a remote api on an arbitrary pipe . takes param , data and setup buffers .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_api_pipe ( struct cli_state * cli , char * pipe_name , int pipe_name_len ,
uint16 * setup , uint32 setup_count , uint32 max_setup_count ,
char * params , uint32 param_count , uint32 max_param_count ,
char * data , uint32 data_count , uint32 max_data_count ,
char * * rparam , uint32 * rparam_count ,
char * * rdata , uint32 * rdata_count )
{
if ( pipe_name_len = = 0 )
pipe_name_len = strlen ( pipe_name ) ;
cli_send_trans ( cli , SMBtrans ,
pipe_name , pipe_name_len ,
0 , 0 , /* fid, flags */
setup , setup_count , max_setup_count ,
params , param_count , max_param_count ,
data , data_count , max_data_count ) ;
return ( cli_receive_trans ( cli , SMBtrans ,
rparam , ( int * ) rparam_count ,
rdata , ( int * ) rdata_count ) ) ;
}
/****************************************************************************
call a remote api
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_api ( struct cli_state * cli ,
char * param , int prcnt , int mprcnt ,
char * data , int drcnt , int mdrcnt ,
char * * rparam , int * rprcnt ,
char * * rdata , int * rdrcnt )
{
cli_send_trans ( cli , SMBtrans ,
PIPE_LANMAN , strlen ( PIPE_LANMAN ) , /* Name, length */
0 , 0 , /* fid, flags */
NULL , 0 , 0 , /* Setup, length, max */
param , prcnt , mprcnt , /* Params, length, max */
data , drcnt , mdrcnt /* Data, length, max */
) ;
return ( cli_receive_trans ( cli , SMBtrans ,
rparam , rprcnt ,
rdata , rdrcnt ) ) ;
}
/****************************************************************************
perform a NetWkstaUserLogon
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_NetWkstaUserLogon ( struct cli_state * cli , char * user , char * workstation )
{
char * rparam = NULL ;
char * rdata = NULL ;
char * p ;
int rdrcnt , rprcnt ;
pstring param ;
memset ( param , 0 , sizeof ( param ) ) ;
/* send a SMBtrans command with api NetWkstaUserLogon */
p = param ;
SSVAL ( p , 0 , 132 ) ; /* api number */
p + = 2 ;
pstrcpy ( p , " OOWb54WrLh " ) ;
p = skip_string ( p , 1 ) ;
pstrcpy ( p , " WB21BWDWWDDDDDDDzzzD " ) ;
p = skip_string ( p , 1 ) ;
SSVAL ( p , 0 , 1 ) ;
p + = 2 ;
pstrcpy ( p , user ) ;
strupper ( p ) ;
p + = 21 ;
p + + ;
p + = 15 ;
p + + ;
pstrcpy ( p , workstation ) ;
strupper ( p ) ;
p + = 16 ;
SSVAL ( p , 0 , CLI_BUFFER_SIZE ) ;
p + = 2 ;
SSVAL ( p , 0 , CLI_BUFFER_SIZE ) ;
p + = 2 ;
if ( cli_api ( cli ,
param , PTR_DIFF ( p , param ) , 1024 , /* param, length, max */
NULL , 0 , CLI_BUFFER_SIZE , /* data, length, max */
& rparam , & rprcnt , /* return params, return size */
& rdata , & rdrcnt /* return data, return size */
) ) {
2000-04-30 19:13:15 +04:00
cli - > rap_error = rparam ? SVAL ( rparam , 0 ) : - 1 ;
2000-04-25 18:04:06 +04:00
p = rdata ;
if ( cli - > rap_error = = 0 ) {
DEBUG ( 4 , ( " NetWkstaUserLogon success \n " ) ) ;
cli - > privileges = SVAL ( p , 24 ) ;
fstrcpy ( cli - > eff_name , p + 2 ) ;
} else {
DEBUG ( 1 , ( " NetwkstaUserLogon gave error %d \n " , cli - > rap_error ) ) ;
}
}
if ( rparam )
free ( rparam ) ;
if ( rdata )
free ( rdata ) ;
return ( cli - > rap_error = = 0 ) ;
}
/****************************************************************************
call a NetShareEnum - try and browse available connections on a host
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int cli_RNetShareEnum ( struct cli_state * cli , void ( * fn ) ( const char * , uint32 , const char * ) )
{
2000-04-30 19:13:15 +04:00
char * rparam = NULL ;
char * rdata = NULL ;
char * p ;
int rdrcnt , rprcnt ;
pstring param ;
int count = - 1 ;
2000-04-25 18:04:06 +04:00
2000-04-30 19:13:15 +04:00
/* now send a SMBtrans command with api RNetShareEnum */
p = param ;
SSVAL ( p , 0 , 0 ) ; /* api number */
p + = 2 ;
pstrcpy ( p , " WrLeh " ) ;
p = skip_string ( p , 1 ) ;
pstrcpy ( p , " B13BWz " ) ;
p = skip_string ( p , 1 ) ;
SSVAL ( p , 0 , 1 ) ;
/*
* Win2k needs a * smaller * buffer than 0xFFFF here -
* it returns " out of server memory " with 0xFFFF ! ! ! JRA .
*/
SSVAL ( p , 2 , 0xFFE0 ) ;
p + = 4 ;
if ( cli_api ( cli ,
param , PTR_DIFF ( p , param ) , 1024 , /* Param, length, maxlen */
NULL , 0 , 0xFFE0 , /* data, length, maxlen - Win2k needs a small buffer here too ! */
& rparam , & rprcnt , /* return params, length */
& rdata , & rdrcnt ) ) /* return data, length */
{
int res = rparam ? SVAL ( rparam , 0 ) : - 1 ;
if ( res = = 0 | | res = = ERRmoredata ) {
int converter = SVAL ( rparam , 2 ) ;
int i ;
count = SVAL ( rparam , 4 ) ;
p = rdata ;
for ( i = 0 ; i < count ; i + + , p + = 20 ) {
char * sname = p ;
int type = SVAL ( p , 14 ) ;
int comment_offset = IVAL ( p , 16 ) & 0xFFFF ;
char * cmnt = comment_offset ? ( rdata + comment_offset - converter ) : " " ;
dos_to_unix ( sname , True ) ;
dos_to_unix ( cmnt , True ) ;
fn ( sname , type , cmnt ) ;
}
} else {
DEBUG ( 4 , ( " NetShareEnum res=%d \n " , res ) ) ;
}
} else {
DEBUG ( 4 , ( " NetShareEnum failed \n " ) ) ;
}
2000-04-25 18:04:06 +04:00
2000-04-30 19:13:15 +04:00
if ( rparam )
free ( rparam ) ;
if ( rdata )
free ( rdata ) ;
return count ;
2000-04-25 18:04:06 +04:00
}
/****************************************************************************
call a NetServerEnum for the specified workgroup and servertype mask .
This function then calls the specified callback function for each name returned .
The callback function takes 3 arguments : the machine name , the server type and
the comment .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_NetServerEnum ( struct cli_state * cli , char * workgroup , uint32 stype ,
void ( * fn ) ( const char * , uint32 , const char * ) )
{
char * rparam = NULL ;
char * rdata = NULL ;
int rdrcnt , rprcnt ;
char * p ;
pstring param ;
int uLevel = 1 ;
int count = - 1 ;
/* send a SMBtrans command with api NetServerEnum */
p = param ;
SSVAL ( p , 0 , 0x68 ) ; /* api number */
p + = 2 ;
pstrcpy ( p , " WrLehDz " ) ;
p = skip_string ( p , 1 ) ;
pstrcpy ( p , " B16BBDz " ) ;
p = skip_string ( p , 1 ) ;
SSVAL ( p , 0 , uLevel ) ;
SSVAL ( p , 2 , CLI_BUFFER_SIZE ) ;
p + = 4 ;
SIVAL ( p , 0 , stype ) ;
p + = 4 ;
pstrcpy ( p , workgroup ) ;
2000-10-07 05:15:07 +04:00
unix_to_dos ( p , True ) ;
2000-04-25 18:04:06 +04:00
p = skip_string ( p , 1 ) ;
if ( cli_api ( cli ,
param , PTR_DIFF ( p , param ) , 8 , /* params, length, max */
NULL , 0 , CLI_BUFFER_SIZE , /* data, length, max */
& rparam , & rprcnt , /* return params, return size */
& rdata , & rdrcnt /* return data, return size */
) ) {
2000-04-30 19:13:15 +04:00
int res = rparam ? SVAL ( rparam , 0 ) : - 1 ;
2000-04-25 18:04:06 +04:00
if ( res = = 0 | | res = = ERRmoredata ) {
2000-04-30 19:13:15 +04:00
int i ;
int converter = SVAL ( rparam , 2 ) ;
2000-04-25 18:04:06 +04:00
count = SVAL ( rparam , 4 ) ;
p = rdata ;
for ( i = 0 ; i < count ; i + + , p + = 26 ) {
char * sname = p ;
int comment_offset = ( IVAL ( p , 22 ) & 0xFFFF ) - converter ;
char * cmnt = comment_offset ? ( rdata + comment_offset ) : " " ;
if ( comment_offset < 0 | | comment_offset > rdrcnt ) continue ;
stype = IVAL ( p , 18 ) & ~ SV_TYPE_LOCAL_LIST_ONLY ;
dos_to_unix ( sname , True ) ;
dos_to_unix ( cmnt , True ) ;
fn ( sname , stype , cmnt ) ;
}
}
}
if ( rparam )
2000-04-30 19:13:15 +04:00
free ( rparam ) ;
2000-04-25 18:04:06 +04:00
if ( rdata )
2000-04-30 19:13:15 +04:00
free ( rdata ) ;
2000-04-25 18:04:06 +04:00
return ( count > 0 ) ;
}
/****************************************************************************
Send a SamOEMChangePassword command
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_oem_change_password ( struct cli_state * cli , const char * user , const char * new_password ,
const char * old_password )
{
char param [ 16 + sizeof ( fstring ) ] ;
char data [ 532 ] ;
char * p = param ;
fstring upper_case_old_pw ;
fstring upper_case_new_pw ;
unsigned char old_pw_hash [ 16 ] ;
unsigned char new_pw_hash [ 16 ] ;
int data_len ;
int param_len = 0 ;
char * rparam = NULL ;
char * rdata = NULL ;
int rprcnt , rdrcnt ;
pstring dos_new_password ;
if ( strlen ( user ) > = sizeof ( fstring ) - 1 ) {
DEBUG ( 0 , ( " cli_oem_change_password: user name %s is too long. \n " , user ) ) ;
return False ;
}
SSVAL ( p , 0 , 214 ) ; /* SamOEMChangePassword command. */
p + = 2 ;
pstrcpy ( p , " zsT " ) ;
p = skip_string ( p , 1 ) ;
pstrcpy ( p , " B516B16 " ) ;
p = skip_string ( p , 1 ) ;
pstrcpy ( p , user ) ;
p = skip_string ( p , 1 ) ;
SSVAL ( p , 0 , 532 ) ;
p + = 2 ;
param_len = PTR_DIFF ( p , param ) ;
/*
* Get the Lanman hash of the old password , we
* use this as the key to make_oem_passwd_hash ( ) .
*/
memset ( upper_case_old_pw , ' \0 ' , sizeof ( upper_case_old_pw ) ) ;
fstrcpy ( upper_case_old_pw , old_password ) ;
unix_to_dos ( upper_case_old_pw , True ) ;
strupper ( upper_case_old_pw ) ;
E_P16 ( ( uchar * ) upper_case_old_pw , old_pw_hash ) ;
pstrcpy ( dos_new_password , new_password ) ;
unix_to_dos ( dos_new_password , True ) ;
if ( ! make_oem_passwd_hash ( data , dos_new_password , old_pw_hash , False ) )
return False ;
/*
* Now place the old password hash in the data .
*/
memset ( upper_case_new_pw , ' \0 ' , sizeof ( upper_case_new_pw ) ) ;
fstrcpy ( upper_case_new_pw , new_password ) ;
unix_to_dos ( upper_case_new_pw , True ) ;
strupper ( upper_case_new_pw ) ;
E_P16 ( ( uchar * ) upper_case_new_pw , new_pw_hash ) ;
E_old_pw_hash ( new_pw_hash , old_pw_hash , ( uchar * ) & data [ 516 ] ) ;
data_len = 532 ;
if ( cli_send_trans ( cli , SMBtrans ,
PIPE_LANMAN , strlen ( PIPE_LANMAN ) , /* name, length */
0 , 0 , /* fid, flags */
NULL , 0 , 0 , /* setup, length, max */
param , param_len , 2 , /* param, length, max */
data , data_len , 0 /* data, length, max */
) = = False ) {
DEBUG ( 0 , ( " cli_oem_change_password: Failed to send password change for user %s \n " ,
user ) ) ;
return False ;
}
if ( cli_receive_trans ( cli , SMBtrans ,
& rparam , & rprcnt ,
& rdata , & rdrcnt ) ) {
if ( rparam )
cli - > rap_error = SVAL ( rparam , 0 ) ;
}
if ( rparam )
free ( rparam ) ;
if ( rdata )
free ( rdata ) ;
return ( cli - > rap_error = = 0 ) ;
}
/****************************************************************************
send a qpathinfo call
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_qpathinfo ( struct cli_state * cli , const char * fname ,
time_t * c_time , time_t * a_time , time_t * m_time ,
size_t * size , uint16 * mode )
{
int data_len = 0 ;
int param_len = 0 ;
uint16 setup = TRANSACT2_QPATHINFO ;
pstring param ;
char * rparam = NULL , * rdata = NULL ;
int count = 8 ;
BOOL ret ;
time_t ( * date_fn ) ( void * ) ;
param_len = strlen ( fname ) + 7 ;
memset ( param , 0 , param_len ) ;
SSVAL ( param , 0 , SMB_INFO_STANDARD ) ;
pstrcpy ( & param [ 6 ] , fname ) ;
unix_to_dos ( & param [ 6 ] , True ) ;
do {
ret = ( cli_send_trans ( cli , SMBtrans2 ,
NULL , 0 , /* Name, length */
- 1 , 0 , /* fid, flags */
& setup , 1 , 0 , /* setup, length, max */
param , param_len , 10 , /* param, length, max */
NULL , data_len , cli - > max_xmit /* data, length, max */
) & &
cli_receive_trans ( cli , SMBtrans2 ,
& rparam , & param_len ,
& rdata , & data_len ) ) ;
if ( ! ret ) {
/* we need to work around a Win95 bug - sometimes
it gives ERRSRV / ERRerror temprarily */
uint8 eclass ;
uint32 ecode ;
cli_error ( cli , & eclass , & ecode , NULL ) ;
if ( eclass ! = ERRSRV | | ecode ! = ERRerror ) break ;
msleep ( 100 ) ;
}
} while ( count - - & & ret = = False ) ;
if ( ! ret | | ! rdata | | data_len < 22 ) {
return False ;
}
if ( cli - > win95 ) {
date_fn = make_unix_date ;
} else {
date_fn = make_unix_date2 ;
}
if ( c_time ) {
* c_time = date_fn ( rdata + 0 ) ;
}
if ( a_time ) {
* a_time = date_fn ( rdata + 4 ) ;
}
if ( m_time ) {
* m_time = date_fn ( rdata + 8 ) ;
}
if ( size ) {
* size = IVAL ( rdata , 12 ) ;
}
if ( mode ) {
* mode = SVAL ( rdata , l1_attrFile ) ;
}
if ( rdata ) free ( rdata ) ;
if ( rparam ) free ( rparam ) ;
return True ;
}
/****************************************************************************
send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_qpathinfo2 ( struct cli_state * cli , const char * fname ,
time_t * c_time , time_t * a_time , time_t * m_time ,
time_t * w_time , size_t * size , uint16 * mode ,
SMB_INO_T * ino )
{
int data_len = 0 ;
int param_len = 0 ;
uint16 setup = TRANSACT2_QPATHINFO ;
pstring param ;
char * rparam = NULL , * rdata = NULL ;
param_len = strlen ( fname ) + 7 ;
memset ( param , 0 , param_len ) ;
SSVAL ( param , 0 , SMB_QUERY_FILE_ALL_INFO ) ;
pstrcpy ( & param [ 6 ] , fname ) ;
unix_to_dos ( & param [ 6 ] , True ) ;
if ( ! cli_send_trans ( cli , SMBtrans2 ,
NULL , 0 , /* name, length */
- 1 , 0 , /* fid, flags */
& setup , 1 , 0 , /* setup, length, max */
param , param_len , 10 , /* param, length, max */
NULL , data_len , cli - > max_xmit /* data, length, max */
) ) {
return False ;
}
if ( ! cli_receive_trans ( cli , SMBtrans2 ,
& rparam , & param_len ,
& rdata , & data_len ) ) {
return False ;
}
if ( ! rdata | | data_len < 22 ) {
return False ;
}
if ( c_time ) {
* c_time = interpret_long_date ( rdata + 0 ) - cli - > serverzone ;
}
if ( a_time ) {
* a_time = interpret_long_date ( rdata + 8 ) - cli - > serverzone ;
}
if ( m_time ) {
* m_time = interpret_long_date ( rdata + 16 ) - cli - > serverzone ;
}
if ( w_time ) {
* w_time = interpret_long_date ( rdata + 24 ) - cli - > serverzone ;
}
if ( mode ) {
* mode = SVAL ( rdata , 32 ) ;
}
if ( size ) {
* size = IVAL ( rdata , 48 ) ;
}
if ( ino ) {
* ino = IVAL ( rdata , 64 ) ;
}
if ( rdata ) free ( rdata ) ;
if ( rparam ) free ( rparam ) ;
return True ;
}
/****************************************************************************
send a qfileinfo call
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL cli_qfileinfo ( struct cli_state * cli , int fnum ,
uint16 * mode , size_t * size ,
time_t * c_time , time_t * a_time , time_t * m_time ,
time_t * w_time , SMB_INO_T * ino )
{
int data_len = 0 ;
int param_len = 0 ;
uint16 setup = TRANSACT2_QFILEINFO ;
pstring param ;
char * rparam = NULL , * rdata = NULL ;
/* if its a win95 server then fail this - win95 totally screws it
up */
if ( cli - > win95 ) return False ;
param_len = 4 ;
memset ( param , 0 , param_len ) ;
SSVAL ( param , 0 , fnum ) ;
SSVAL ( param , 2 , SMB_QUERY_FILE_ALL_INFO ) ;
if ( ! cli_send_trans ( cli , SMBtrans2 ,
NULL , 0 , /* name, length */
- 1 , 0 , /* fid, flags */
& setup , 1 , 0 , /* setup, length, max */
param , param_len , 2 , /* param, length, max */
NULL , data_len , cli - > max_xmit /* data, length, max */
) ) {
return False ;
}
if ( ! cli_receive_trans ( cli , SMBtrans2 ,
& rparam , & param_len ,
& rdata , & data_len ) ) {
return False ;
}
if ( ! rdata | | data_len < 68 ) {
return False ;
}
if ( c_time ) {
* c_time = interpret_long_date ( rdata + 0 ) - cli - > serverzone ;
}
if ( a_time ) {
* a_time = interpret_long_date ( rdata + 8 ) - cli - > serverzone ;
}
if ( m_time ) {
* m_time = interpret_long_date ( rdata + 16 ) - cli - > serverzone ;
}
if ( w_time ) {
* w_time = interpret_long_date ( rdata + 24 ) - cli - > serverzone ;
}
if ( mode ) {
* mode = SVAL ( rdata , 32 ) ;
}
if ( size ) {
* size = IVAL ( rdata , 48 ) ;
}
if ( ino ) {
* ino = IVAL ( rdata , 64 ) ;
}
if ( rdata ) free ( rdata ) ;
if ( rparam ) free ( rparam ) ;
return True ;
}