2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
SMB torture tester utility functions
Copyright ( C ) Andrew Tridgell 2003
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 .
*/
# include "includes.h"
2004-11-01 04:03:22 +03:00
# include "libcli/raw/libcliraw.h"
2004-11-02 02:45:40 +03:00
# include "system/shmem.h"
2004-11-02 03:24:21 +03:00
# include "system/time.h"
2004-11-30 07:33:27 +03:00
# include "librpc/gen_ndr/ndr_security.h"
2003-08-13 05:53:07 +04:00
2004-11-12 12:37:59 +03:00
/*
setup a directory ready for a test
*/
BOOL torture_setup_dir ( struct smbcli_state * cli , const char * dname )
{
smb_raw_exit ( cli - > session ) ;
if ( smbcli_deltree ( cli - > tree , dname ) = = - 1 | |
NT_STATUS_IS_ERR ( smbcli_mkdir ( cli - > tree , dname ) ) ) {
printf ( " Unable to setup %s - %s \n " , dname , smbcli_errstr ( cli - > tree ) ) ;
return False ;
}
return True ;
}
2003-08-14 02:23:18 +04:00
/*
create a directory , returning a handle to it
*/
2004-08-04 17:23:35 +04:00
int create_directory_handle ( struct smbcli_tree * tree , const char * dname )
2003-08-14 02:23:18 +04:00
{
NTSTATUS status ;
union smb_open io ;
TALLOC_CTX * mem_ctx ;
mem_ctx = talloc_init ( " create_directory_handle " ) ;
io . generic . level = RAW_OPEN_NTCREATEX ;
io . ntcreatex . in . root_fid = 0 ;
io . ntcreatex . in . flags = 0 ;
2004-11-30 07:33:27 +03:00
io . ntcreatex . in . access_mask = SEC_FILE_ALL ;
2003-08-14 02:23:18 +04:00
io . ntcreatex . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
io . ntcreatex . in . file_attr = FILE_ATTRIBUTE_NORMAL ;
io . ntcreatex . in . share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE ;
io . ntcreatex . in . alloc_size = 0 ;
io . ntcreatex . in . open_disposition = NTCREATEX_DISP_CREATE ;
io . ntcreatex . in . impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS ;
io . ntcreatex . in . security_flags = 0 ;
io . ntcreatex . in . fname = dname ;
2003-09-02 08:37:33 +04:00
status = smb_raw_open ( tree , mem_ctx , & io ) ;
2003-08-14 02:23:18 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_destroy ( mem_ctx ) ;
return - 1 ;
}
talloc_destroy ( mem_ctx ) ;
return io . ntcreatex . out . fnum ;
}
2003-08-13 05:53:07 +04:00
/*
sometimes we need a fairly complex file to work with , so we can test
all possible attributes .
*/
2004-08-04 17:23:35 +04:00
int create_complex_file ( struct smbcli_state * cli , TALLOC_CTX * mem_ctx , const char * fname )
2003-08-13 05:53:07 +04:00
{
int fnum ;
char buf [ 7 ] = " abc " ;
union smb_setfileinfo setfile ;
union smb_fileinfo fileinfo ;
time_t t = ( time ( NULL ) & ~ 1 ) ;
NTSTATUS status ;
2004-08-04 17:23:35 +04:00
smbcli_unlink ( cli - > tree , fname ) ;
2004-11-30 07:33:27 +03:00
fnum = smbcli_nt_create_full ( cli - > tree , fname , 0 ,
2004-12-02 07:37:36 +03:00
SEC_RIGHTS_FILE_ALL ,
2004-11-30 07:33:27 +03:00
FILE_ATTRIBUTE_NORMAL ,
NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ,
NTCREATEX_DISP_OVERWRITE_IF ,
0 , 0 ) ;
2003-08-13 05:53:07 +04:00
if ( fnum = = - 1 ) return - 1 ;
2004-08-04 17:23:35 +04:00
smbcli_write ( cli - > tree , fnum , 0 , buf , 0 , sizeof ( buf ) ) ;
2003-08-13 05:53:07 +04:00
/* setup some EAs */
setfile . generic . level = RAW_SFILEINFO_EA_SET ;
setfile . generic . file . fnum = fnum ;
2004-12-17 07:51:23 +03:00
setfile . ea_set . in . num_eas = 2 ;
setfile . ea_set . in . eas = talloc_array_p ( mem_ctx , struct ea_struct , 2 ) ;
setfile . ea_set . in . eas [ 0 ] . flags = 0 ;
setfile . ea_set . in . eas [ 0 ] . name . s = " EAONE " ;
setfile . ea_set . in . eas [ 0 ] . value = data_blob_talloc ( mem_ctx , " VALUE1 " , 6 ) ;
setfile . ea_set . in . eas [ 1 ] . flags = 0 ;
setfile . ea_set . in . eas [ 1 ] . name . s = " SECONDEA " ;
setfile . ea_set . in . eas [ 1 ] . value = data_blob_talloc ( mem_ctx , " ValueTwo " , 8 ) ;
2003-08-13 05:53:07 +04:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to setup EAs \n " ) ;
}
2004-04-11 00:18:22 +04:00
/* make sure all the timestamps aren't the same, and are also
in different DST zones */
2003-08-13 05:53:07 +04:00
setfile . generic . level = RAW_SFILEINFO_SETATTRE ;
setfile . generic . file . fnum = fnum ;
2004-04-11 00:18:22 +04:00
setfile . setattre . in . create_time = t + 9 * 30 * 24 * 60 * 60 ;
setfile . setattre . in . access_time = t + 6 * 30 * 24 * 60 * 60 ;
setfile . setattre . in . write_time = t + 3 * 30 * 24 * 60 * 60 ;
2003-08-13 05:53:07 +04:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to setup file times - %s \n " , nt_errstr ( status ) ) ;
}
/* make sure all the timestamps aren't the same */
fileinfo . generic . level = RAW_FILEINFO_GETATTRE ;
fileinfo . generic . in . fnum = fnum ;
status = smb_raw_fileinfo ( cli - > tree , mem_ctx , & fileinfo ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to query file times - %s \n " , nt_errstr ( status ) ) ;
}
if ( setfile . setattre . in . create_time ! = fileinfo . getattre . out . create_time ) {
printf ( " create_time not setup correctly \n " ) ;
}
if ( setfile . setattre . in . access_time ! = fileinfo . getattre . out . access_time ) {
printf ( " access_time not setup correctly \n " ) ;
}
if ( setfile . setattre . in . write_time ! = fileinfo . getattre . out . write_time ) {
printf ( " write_time not setup correctly \n " ) ;
}
return fnum ;
}
/* return a pointer to a anonymous shared memory segment of size "size"
which will persist across fork ( ) but will disappear when all processes
exit
The memory is not zeroed
This function uses system5 shared memory . It takes advantage of a property
that the memory is not destroyed if it is attached when the id is removed
*/
void * shm_setup ( int size )
{
int shmid ;
void * ret ;
shmid = shmget ( IPC_PRIVATE , size , SHM_R | SHM_W ) ;
if ( shmid = = - 1 ) {
printf ( " can't get shared memory \n " ) ;
exit ( 1 ) ;
}
ret = ( void * ) shmat ( shmid , 0 , 0 ) ;
if ( ! ret | | ret = = ( void * ) - 1 ) {
printf ( " can't attach to shared memory \n " ) ;
return NULL ;
}
/* the following releases the ipc, but note that this process
and all its children will still have access to the memory , its
just that the shmid is no longer valid for other shm calls . This
means we don ' t leave behind lots of shm segments after we exit
See Stevens " advanced programming in unix env " for details
*/
shmctl ( shmid , IPC_RMID , 0 ) ;
return ret ;
}
/*
check that a wire string matches the flags specified
not 100 % accurate , but close enough for testing
*/
2004-08-12 01:11:37 +04:00
BOOL wire_bad_flags ( WIRE_STRING * str , int flags , struct smbcli_state * cli )
2003-08-13 05:53:07 +04:00
{
2004-08-12 01:11:37 +04:00
BOOL server_unicode ;
2003-08-13 05:53:07 +04:00
int len ;
2003-08-15 20:19:48 +04:00
if ( ! str | | ! str - > s ) return True ;
2003-08-13 05:53:07 +04:00
len = strlen ( str - > s ) ;
if ( flags & STR_TERMINATE ) len + + ;
2004-08-12 01:11:37 +04:00
server_unicode = ( cli - > transport - > negotiate . capabilities & CAP_UNICODE ) ? True : False ;
if ( getenv ( " CLI_FORCE_ASCII " ) | | ! lp_unicode ( ) ) {
server_unicode = False ;
}
if ( ( flags & STR_UNICODE ) | | server_unicode ) {
2003-08-13 05:53:07 +04:00
len * = 2 ;
} else if ( flags & STR_TERMINATE_ASCII ) {
len + + ;
}
if ( str - > private_length ! = len ) {
printf ( " Expected wire_length %d but got %d for '%s' \n " ,
len , str - > private_length , str - > s ) ;
return True ;
}
return False ;
}
/*
check if 2 NTTIMEs are equal
*/
BOOL nt_time_equal ( NTTIME * t1 , NTTIME * t2 )
{
2004-05-25 17:57:39 +04:00
return * t1 = = * t2 ;
2003-08-13 05:53:07 +04:00
}
/*
dump a all_info QFILEINFO structure
*/
void dump_all_info ( TALLOC_CTX * mem_ctx , union smb_fileinfo * finfo )
{
2004-05-25 17:57:39 +04:00
d_printf ( " \t create_time: %s \n " , nt_time_string ( mem_ctx , finfo - > all_info . out . create_time ) ) ;
d_printf ( " \t access_time: %s \n " , nt_time_string ( mem_ctx , finfo - > all_info . out . access_time ) ) ;
d_printf ( " \t write_time: %s \n " , nt_time_string ( mem_ctx , finfo - > all_info . out . write_time ) ) ;
d_printf ( " \t change_time: %s \n " , nt_time_string ( mem_ctx , finfo - > all_info . out . change_time ) ) ;
2003-08-13 05:53:07 +04:00
d_printf ( " \t attrib: 0x%x \n " , finfo - > all_info . out . attrib ) ;
2004-06-23 19:19:22 +04:00
d_printf ( " \t alloc_size: %llu \n " , ( uint64_t ) finfo - > all_info . out . alloc_size ) ;
d_printf ( " \t size: %llu \n " , ( uint64_t ) finfo - > all_info . out . size ) ;
2003-08-13 05:53:07 +04:00
d_printf ( " \t nlink: %u \n " , finfo - > all_info . out . nlink ) ;
d_printf ( " \t delete_pending: %u \n " , finfo - > all_info . out . delete_pending ) ;
d_printf ( " \t directory: %u \n " , finfo - > all_info . out . directory ) ;
d_printf ( " \t ea_size: %u \n " , finfo - > all_info . out . ea_size ) ;
d_printf ( " \t fname: '%s' \n " , finfo - > all_info . out . fname . s ) ;
}
/*
dump file infor by name
*/
2004-08-04 17:23:35 +04:00
void torture_all_info ( struct smbcli_tree * tree , const char * fname )
2003-08-13 05:53:07 +04:00
{
2004-08-25 14:21:14 +04:00
TALLOC_CTX * mem_ctx = talloc_init ( " %s " , fname ) ;
2003-08-13 05:53:07 +04:00
union smb_fileinfo finfo ;
NTSTATUS status ;
finfo . generic . level = RAW_FILEINFO_ALL_INFO ;
finfo . generic . in . fname = fname ;
status = smb_raw_pathinfo ( tree , mem_ctx , & finfo ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " %s - %s \n " , fname , nt_errstr ( status ) ) ;
return ;
}
d_printf ( " %s: \n " , fname ) ;
dump_all_info ( mem_ctx , & finfo ) ;
talloc_destroy ( mem_ctx ) ;
}
/*
split a UNC name into server and share names
*/
BOOL split_unc_name ( const char * unc , char * * server , char * * share )
{
char * p = strdup ( unc ) ;
if ( ! p ) return False ;
all_string_sub ( p , " \\ " , " / " , 0 ) ;
if ( strncmp ( p , " // " , 2 ) ! = 0 ) return False ;
( * server ) = p + 2 ;
p = strchr ( * server , ' / ' ) ;
if ( ! p ) return False ;
* p = 0 ;
( * share ) = p + 1 ;
return True ;
}
/*
split a USER % PASS pair into username and password
*/
BOOL split_username ( const char * pair , char * * user , char * * pass )
{
char * p = strdup ( pair ) ;
if ( ! p ) return False ;
( * user ) = p ;
p = strchr ( * user , ' % ' ) ;
if ( ! p ) return False ;
* p = 0 ;
( * pass ) = p + 1 ;
return True ;
}
/*
set a attribute on a file
*/
2004-08-04 17:23:35 +04:00
BOOL torture_set_file_attribute ( struct smbcli_tree * tree , const char * fname , uint16_t attrib )
2003-08-13 05:53:07 +04:00
{
union smb_setfileinfo sfinfo ;
NTSTATUS status ;
sfinfo . generic . level = RAW_SFILEINFO_BASIC_INFORMATION ;
sfinfo . generic . file . fname = fname ;
ZERO_STRUCT ( sfinfo . basic_info . in ) ;
sfinfo . basic_info . in . attrib = attrib ;
status = smb_raw_setpathinfo ( tree , & sfinfo ) ;
return NT_STATUS_IS_OK ( status ) ;
}
/*
set a file descriptor as sparse
*/
2004-08-04 17:23:35 +04:00
NTSTATUS torture_set_sparse ( struct smbcli_tree * tree , int fnum )
2003-08-13 05:53:07 +04:00
{
2003-12-04 05:03:06 +03:00
union smb_ioctl nt ;
NTSTATUS status ;
TALLOC_CTX * mem_ctx ;
mem_ctx = talloc_init ( " torture_set_sparse " ) ;
if ( ! mem_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
2003-08-13 05:53:07 +04:00
2003-12-04 05:03:06 +03:00
nt . ntioctl . level = RAW_IOCTL_NTIOCTL ;
nt . ntioctl . in . function = 0x900c4 ;
nt . ntioctl . in . fnum = fnum ;
nt . ntioctl . in . fsctl = True ;
nt . ntioctl . in . filter = 0 ;
status = smb_raw_ioctl ( tree , mem_ctx , & nt ) ;
talloc_destroy ( mem_ctx ) ;
2003-08-13 05:53:07 +04:00
2003-12-04 05:03:06 +03:00
return status ;
2003-08-13 05:53:07 +04:00
}
2004-12-13 13:48:21 +03:00
/*
check that an EA has the right value
*/
NTSTATUS torture_check_ea ( struct smbcli_state * cli ,
const char * fname , const char * eaname , const char * value )
{
union smb_fileinfo info ;
NTSTATUS status ;
2004-12-18 01:47:49 +03:00
struct ea_name ea ;
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx = talloc_new ( cli ) ;
2004-12-13 13:48:21 +03:00
2004-12-18 01:47:49 +03:00
info . ea_list . level = RAW_FILEINFO_EA_LIST ;
info . ea_list . file . fname = fname ;
info . ea_list . in . num_names = 1 ;
info . ea_list . in . ea_names = & ea ;
ea . name . s = eaname ;
2004-12-13 13:48:21 +03:00
status = smb_raw_pathinfo ( cli - > tree , mem_ctx , & info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx ) ;
return status ;
}
2004-12-18 01:47:49 +03:00
if ( info . ea_list . out . num_eas ! = 1 ) {
printf ( " Expected 1 ea in ea_list \n " ) ;
talloc_free ( mem_ctx ) ;
return NT_STATUS_EA_CORRUPT_ERROR ;
2004-12-13 13:48:21 +03:00
}
2004-12-18 01:47:49 +03:00
if ( StrCaseCmp ( eaname , info . ea_list . out . eas [ 0 ] . name . s ) ! = 0 ) {
printf ( " Expected ea '%s' not '%s' in ea_list \n " ,
eaname , info . ea_list . out . eas [ 0 ] . name . s ) ;
talloc_free ( mem_ctx ) ;
return NT_STATUS_EA_CORRUPT_ERROR ;
}
if ( value = = NULL ) {
if ( info . ea_list . out . eas [ 0 ] . value . length ! = 0 ) {
printf ( " Expected zero length ea for %s \n " , eaname ) ;
talloc_free ( mem_ctx ) ;
return NT_STATUS_EA_CORRUPT_ERROR ;
}
talloc_free ( mem_ctx ) ;
return NT_STATUS_OK ;
}
2004-12-13 13:48:21 +03:00
2004-12-18 01:47:49 +03:00
if ( strlen ( value ) = = info . ea_list . out . eas [ 0 ] . value . length & &
memcmp ( value , info . ea_list . out . eas [ 0 ] . value . data ,
info . ea_list . out . eas [ 0 ] . value . length ) = = 0 ) {
talloc_free ( mem_ctx ) ;
return NT_STATUS_OK ;
2004-12-13 13:48:21 +03:00
}
2004-12-18 01:47:49 +03:00
printf ( " Expected value '%s' not '%*.*s' for ea %s \n " ,
value ,
info . ea_list . out . eas [ 0 ] . value . length ,
info . ea_list . out . eas [ 0 ] . value . length ,
info . ea_list . out . eas [ 0 ] . value . data ,
eaname ) ;
talloc_free ( mem_ctx ) ;
return NT_STATUS_EA_CORRUPT_ERROR ;
2004-12-13 13:48:21 +03:00
}