2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
SMB torture tester utility functions
Copyright ( C ) Andrew Tridgell 2003
2006-10-16 17:06:41 +04:00
Copyright ( C ) Jelmer Vernooij 2006
2003-08-13 05:53:07 +04:00
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2006-05-14 02:17:58 +04:00
# include "lib/cmdline/popt_common.h"
2004-11-01 04:03:22 +03:00
# include "libcli/raw/libcliraw.h"
2008-04-02 06:53:27 +04:00
# include "libcli/raw/raw_proto.h"
2006-05-19 18:10:14 +04:00
# include "libcli/raw/ioctl.h"
2006-01-03 18:40:05 +03:00
# include "libcli/libcli.h"
2006-06-17 06:20:39 +04:00
# include "system/filesys.h"
2004-11-02 02:45:40 +03:00
# include "system/shmem.h"
2006-06-17 06:20:39 +04:00
# include "system/wait.h"
2004-11-02 03:24:21 +03:00
# include "system/time.h"
2006-03-17 19:45:24 +03:00
# include "torture/torture.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/dlinklist.h"
2008-01-03 03:39:01 +03:00
# include "libcli/resolve/resolve.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2009-10-16 11:23:42 +04:00
# include "libcli/security/security.h"
# include "libcli/util/clilsa.h"
2011-03-19 02:45:16 +03:00
# include "torture/util.h"
2003-08-13 05:53:07 +04:00
2006-03-17 19:11:02 +03:00
/**
2004-11-12 12:37:59 +03:00
setup a directory ready for a test
*/
2006-10-16 17:06:41 +04:00
_PUBLIC_ bool torture_setup_dir ( struct smbcli_state * cli , const char * dname )
2004-11-12 12:37:59 +03:00
{
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 ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2004-11-12 12:37:59 +03:00
}
2007-10-07 02:28:14 +04:00
return true ;
2004-11-12 12:37:59 +03:00
}
2003-08-14 02:23:18 +04:00
/*
create a directory , returning a handle to it
*/
2005-08-03 22:02:45 +04:00
NTSTATUS create_directory_handle ( struct smbcli_tree * tree , const char * dname , int * fnum )
2003-08-14 02:23:18 +04:00
{
NTSTATUS status ;
union smb_open io ;
TALLOC_CTX * mem_ctx ;
2006-08-31 13:26:43 +04:00
mem_ctx = talloc_named_const ( tree , 0 , " create_directory_handle " ) ;
2003-08-14 02:23:18 +04:00
io . generic . level = RAW_OPEN_NTCREATEX ;
2009-10-15 11:26:19 +04:00
io . ntcreatex . in . root_fid . fnum = 0 ;
2003-08-14 02:23:18 +04:00
io . ntcreatex . in . flags = 0 ;
2005-07-01 16:47:10 +04:00
io . ntcreatex . in . access_mask = SEC_RIGHTS_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 ;
2009-12-15 04:00:43 +03:00
io . ntcreatex . in . share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE ;
2003-08-14 02:23:18 +04:00
io . ntcreatex . in . alloc_size = 0 ;
2005-08-04 08:20:26 +04:00
io . ntcreatex . in . open_disposition = NTCREATEX_DISP_OPEN_IF ;
2003-08-14 02:23:18 +04:00
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 ) ;
2005-08-03 22:02:45 +04:00
talloc_free ( mem_ctx ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2006-03-13 01:48:25 +03:00
* fnum = io . ntcreatex . out . file . fnum ;
2003-08-14 02:23:18 +04:00
}
2005-08-03 22:02:45 +04:00
return status ;
2003-08-14 02:23:18 +04:00
}
2005-08-04 08:20:26 +04:00
2006-03-17 19:11:02 +03:00
/**
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 .
*/
2006-03-17 19:11:02 +03:00
_PUBLIC_ 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
2005-11-15 07:38:59 +03:00
if ( strchr ( fname , ' : ' ) = = NULL ) {
/* setup some EAs */
setfile . generic . level = RAW_SFILEINFO_EA_SET ;
2006-03-13 01:48:25 +03:00
setfile . generic . in . file . fnum = fnum ;
2005-11-15 07:38:59 +03:00
setfile . ea_set . in . num_eas = 2 ;
setfile . ea_set . in . eas = talloc_array ( 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 ) ;
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to setup EAs \n " ) ;
}
}
2009-11-25 02:42:56 +03:00
/* make sure all the timestamps aren't the same */
ZERO_STRUCT ( setfile ) ;
setfile . generic . level = RAW_SFILEINFO_BASIC_INFO ;
2006-03-13 01:48:25 +03:00
setfile . generic . in . file . fnum = fnum ;
2005-11-15 07:38:59 +03:00
2009-11-25 02:42:56 +03:00
unix_to_nt_time ( & setfile . basic_info . in . create_time ,
t + 9 * 30 * 24 * 60 * 60 ) ;
unix_to_nt_time ( & setfile . basic_info . in . access_time ,
t + 6 * 30 * 24 * 60 * 60 ) ;
unix_to_nt_time ( & setfile . basic_info . in . write_time ,
t + 3 * 30 * 24 * 60 * 60 ) ;
2005-11-15 07:38:59 +03:00
2003-08-13 05:53:07 +04:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-11-15 07:38:59 +03:00
printf ( " Failed to setup file times - %s \n " , nt_errstr ( status ) ) ;
}
/* make sure all the timestamps aren't the same */
2009-11-25 02:42:56 +03:00
fileinfo . generic . level = RAW_FILEINFO_BASIC_INFO ;
2006-03-13 01:48:25 +03:00
fileinfo . generic . in . file . fnum = fnum ;
2005-11-15 07:38:59 +03:00
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 ) ) ;
}
2009-11-25 02:42:56 +03:00
if ( setfile . basic_info . in . create_time ! = fileinfo . basic_info . out . create_time ) {
2005-11-15 07:38:59 +03:00
printf ( " create_time not setup correctly \n " ) ;
}
2009-11-25 02:42:56 +03:00
if ( setfile . basic_info . in . access_time ! = fileinfo . basic_info . out . access_time ) {
2005-11-15 07:38:59 +03:00
printf ( " access_time not setup correctly \n " ) ;
}
2009-11-25 02:42:56 +03:00
if ( setfile . basic_info . in . write_time ! = fileinfo . basic_info . out . write_time ) {
2005-11-15 07:38:59 +03:00
printf ( " write_time not setup correctly \n " ) ;
}
return fnum ;
}
/*
sometimes we need a fairly complex directory to work with , so we can test
all possible attributes .
*/
int create_complex_dir ( struct smbcli_state * cli , TALLOC_CTX * mem_ctx , const char * dname )
{
int fnum ;
union smb_setfileinfo setfile ;
union smb_fileinfo fileinfo ;
time_t t = ( time ( NULL ) & ~ 1 ) ;
NTSTATUS status ;
smbcli_deltree ( cli - > tree , dname ) ;
fnum = smbcli_nt_create_full ( cli - > tree , dname , 0 ,
SEC_RIGHTS_DIR_ALL ,
FILE_ATTRIBUTE_DIRECTORY ,
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ,
NTCREATEX_DISP_OPEN_IF ,
NTCREATEX_OPTIONS_DIRECTORY , 0 ) ;
if ( fnum = = - 1 ) return - 1 ;
if ( strchr ( dname , ' : ' ) = = NULL ) {
/* setup some EAs */
setfile . generic . level = RAW_SFILEINFO_EA_SET ;
2006-03-13 01:48:25 +03:00
setfile . generic . in . file . fnum = fnum ;
2005-11-15 07:38:59 +03:00
setfile . ea_set . in . num_eas = 2 ;
setfile . ea_set . in . eas = talloc_array ( 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 ) ;
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to setup EAs \n " ) ;
}
2003-08-13 05:53:07 +04:00
}
2009-11-25 02:42:56 +03:00
/* make sure all the timestamps aren't the same */
ZERO_STRUCT ( setfile ) ;
setfile . generic . level = RAW_SFILEINFO_BASIC_INFO ;
2006-03-13 01:48:25 +03:00
setfile . generic . in . file . fnum = fnum ;
2003-08-13 05:53:07 +04:00
2009-11-25 02:42:56 +03:00
unix_to_nt_time ( & setfile . basic_info . in . create_time ,
t + 9 * 30 * 24 * 60 * 60 ) ;
unix_to_nt_time ( & setfile . basic_info . in . access_time ,
t + 6 * 30 * 24 * 60 * 60 ) ;
unix_to_nt_time ( & setfile . basic_info . 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 */
2009-11-25 02:42:56 +03:00
fileinfo . generic . level = RAW_FILEINFO_BASIC_INFO ;
2006-03-13 01:48:25 +03:00
fileinfo . generic . in . file . fnum = fnum ;
2003-08-13 05:53:07 +04:00
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 ) ) ;
}
2009-11-25 02:42:56 +03:00
if ( setfile . basic_info . in . create_time ! = fileinfo . basic_info . out . create_time ) {
2003-08-13 05:53:07 +04:00
printf ( " create_time not setup correctly \n " ) ;
}
2009-11-25 02:42:56 +03:00
if ( setfile . basic_info . in . access_time ! = fileinfo . basic_info . out . access_time ) {
2003-08-13 05:53:07 +04:00
printf ( " access_time not setup correctly \n " ) ;
}
2009-11-25 02:42:56 +03:00
if ( setfile . basic_info . in . write_time ! = fileinfo . basic_info . out . write_time ) {
2003-08-13 05:53:07 +04:00
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 ;
2009-09-17 03:04:02 +04:00
# ifdef __QNXNTO__
shmid = shm_open ( " private " , O_RDWR | O_CREAT | O_EXCL , S_IRUSR | S_IWUSR ) ;
if ( shmid = = - 1 ) {
printf ( " can't get shared memory \n " ) ;
exit ( 1 ) ;
}
shm_unlink ( " private " ) ;
if ( ftruncate ( shmid , size ) = = - 1 ) {
printf ( " can't set shared memory size \n " ) ;
exit ( 1 ) ;
}
ret = mmap ( 0 , size , PROT_READ | PROT_WRITE , MAP_SHARED , shmid , 0 ) ;
if ( ret = = MAP_FAILED ) {
printf ( " can't map shared memory \n " ) ;
exit ( 1 ) ;
}
# else
2003-08-13 05:53:07 +04:00
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 ) ;
2009-09-17 03:04:02 +04:00
# endif
2003-08-13 05:53:07 +04:00
return ret ;
}
2007-12-04 01:33:16 +03:00
/**
2003-08-13 05:53:07 +04:00
check that a wire string matches the flags specified
not 100 % accurate , but close enough for testing
*/
2007-12-04 01:33:16 +03:00
bool wire_bad_flags ( struct smb_wire_string * str , int flags ,
struct smbcli_transport * transport )
2003-08-13 05:53:07 +04:00
{
2006-10-16 17:06:41 +04:00
bool server_unicode ;
2003-08-13 05:53:07 +04:00
int len ;
2007-10-07 02:28:14 +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
2007-10-07 02:28:14 +04:00
server_unicode = ( transport - > negotiate . capabilities & CAP_UNICODE ) ? true : false ;
2008-01-06 04:03:43 +03:00
if ( getenv ( " CLI_FORCE_ASCII " ) | | ! transport - > options . unicode ) {
2007-10-07 02:28:14 +04:00
server_unicode = false ;
2004-08-12 01:11:37 +04:00
}
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 ) ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2007-10-07 02:28:14 +04:00
return false ;
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 ) ;
2005-11-30 05:08:15 +03:00
d_printf ( " \t alloc_size: %llu \n " , ( long long ) finfo - > all_info . out . alloc_size ) ;
d_printf ( " \t size: %llu \n " , ( long long ) 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
{
2006-08-31 13:26:43 +04:00
TALLOC_CTX * mem_ctx = talloc_named ( tree , 0 , " %s " , fname ) ;
2003-08-13 05:53:07 +04:00
union smb_fileinfo finfo ;
NTSTATUS status ;
finfo . generic . level = RAW_FILEINFO_ALL_INFO ;
2006-03-13 01:48:25 +03:00
finfo . generic . in . file . path = fname ;
2003-08-13 05:53:07 +04:00
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 ) ;
2005-01-27 10:08:20 +03:00
talloc_free ( mem_ctx ) ;
2003-08-13 05:53:07 +04:00
}
/*
set a attribute on a file
*/
2006-10-16 17:06:41 +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 ;
ZERO_STRUCT ( sfinfo . basic_info . in ) ;
2006-03-13 15:43:59 +03:00
sfinfo . basic_info . level = RAW_SFILEINFO_BASIC_INFORMATION ;
sfinfo . basic_info . in . file . path = fname ;
2003-08-13 05:53:07 +04:00
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 ;
2006-08-31 13:26:43 +04:00
mem_ctx = talloc_named_const ( tree , 0 , " torture_set_sparse " ) ;
2003-12-04 05:03:06 +03:00
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 ;
2006-05-19 18:10:14 +04:00
nt . ntioctl . in . function = FSCTL_SET_SPARSE ;
2006-03-13 01:48:25 +03:00
nt . ntioctl . in . file . fnum = fnum ;
2007-10-07 02:28:14 +04:00
nt . ntioctl . in . fsctl = true ;
2003-12-04 05:03:06 +03:00
nt . ntioctl . in . filter = 0 ;
2006-05-19 18:10:14 +04:00
nt . ntioctl . in . max_data = 0 ;
nt . ntioctl . in . blob = data_blob ( NULL , 0 ) ;
2003-12-04 05:03:06 +03:00
status = smb_raw_ioctl ( tree , mem_ctx , & nt ) ;
2005-01-27 10:08:20 +03:00
talloc_free ( 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 ;
2006-03-13 01:48:25 +03:00
info . ea_list . in . file . path = fname ;
2004-12-18 01:47:49 +03:00
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
}
2005-08-30 15:55:05 +04:00
if ( strcasecmp_m ( eaname , info . ea_list . out . eas [ 0 ] . name . s ) ! = 0 ) {
2004-12-18 01:47:49 +03:00
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 ,
2005-07-17 13:20:52 +04:00
( int ) info . ea_list . out . eas [ 0 ] . value . length ,
( int ) info . ea_list . out . eas [ 0 ] . value . length ,
2004-12-18 01:47:49 +03:00
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
}
2006-10-29 20:40:19 +03:00
_PUBLIC_ bool torture_open_connection_share ( TALLOC_CTX * mem_ctx ,
2006-03-17 20:59:58 +03:00
struct smbcli_state * * c ,
2007-12-03 17:53:07 +03:00
struct torture_context * tctx ,
2006-03-17 20:59:58 +03:00
const char * hostname ,
const char * sharename ,
2008-12-29 22:24:57 +03:00
struct tevent_context * ev )
2006-03-17 20:59:58 +03:00
{
NTSTATUS status ;
2008-01-04 02:22:12 +03:00
struct smbcli_options options ;
2008-09-30 05:07:08 +04:00
struct smbcli_session_options session_options ;
2008-01-04 02:22:12 +03:00
2010-07-16 08:32:42 +04:00
lpcfg_smbcli_options ( tctx - > lp_ctx , & options ) ;
lpcfg_smbcli_session_options ( tctx - > lp_ctx , & session_options ) ;
2008-01-04 02:22:12 +03:00
2008-03-06 17:11:16 +03:00
options . use_oplocks = torture_setting_bool ( tctx , " use_oplocks " , true ) ;
options . use_level2_oplocks = torture_setting_bool ( tctx , " use_level2_oplocks " , true ) ;
2006-03-17 20:59:58 +03:00
status = smbcli_full_connection ( mem_ctx , c , hostname ,
2010-07-16 08:32:42 +04:00
lpcfg_smb_ports ( tctx - > lp_ctx ) ,
2006-03-17 20:59:58 +03:00
sharename , NULL ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( tctx - > lp_ctx ) ,
2008-01-03 03:39:01 +03:00
cmdline_credentials ,
2010-07-16 08:32:42 +04:00
lpcfg_resolve_context ( tctx - > lp_ctx ) ,
2008-10-24 15:13:27 +04:00
ev , & options , & session_options ,
2010-07-16 08:32:42 +04:00
lpcfg_gensec_settings ( tctx , tctx - > lp_ctx ) ) ;
2006-03-17 20:59:58 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to open connection - %s \n " , nt_errstr ( status ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-03-17 20:59:58 +03:00
}
2007-10-07 02:28:14 +04:00
return true ;
2006-03-17 20:59:58 +03:00
}
2007-05-14 05:04:01 +04:00
_PUBLIC_ bool torture_get_conn_index ( int conn_index ,
TALLOC_CTX * mem_ctx ,
2007-12-03 17:53:07 +03:00
struct torture_context * tctx ,
2007-05-14 05:04:01 +04:00
char * * host , char * * share )
2006-03-17 20:59:58 +03:00
{
2006-07-10 13:39:14 +04:00
char * * unc_list = NULL ;
int num_unc_names = 0 ;
const char * p ;
2007-05-14 05:04:01 +04:00
2007-12-03 17:53:07 +03:00
( * host ) = talloc_strdup ( mem_ctx , torture_setting_string ( tctx , " host " , NULL ) ) ;
( * share ) = talloc_strdup ( mem_ctx , torture_setting_string ( tctx , " share " , NULL ) ) ;
2006-07-10 13:39:14 +04:00
2007-12-03 17:53:07 +03:00
p = torture_setting_string ( tctx , " unclist " , NULL ) ;
2007-05-14 05:04:01 +04:00
if ( ! p ) {
2007-10-07 02:28:14 +04:00
return true ;
2007-05-14 05:04:01 +04:00
}
2006-07-10 13:39:14 +04:00
2008-10-12 21:46:38 +04:00
unc_list = file_lines_load ( p , & num_unc_names , 0 , NULL ) ;
2007-05-14 05:04:01 +04:00
if ( ! unc_list | | num_unc_names < = 0 ) {
DEBUG ( 0 , ( " Failed to load unc names list from '%s' \n " , p ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-07-10 13:39:14 +04:00
}
2006-03-17 20:59:58 +03:00
2010-02-09 05:18:31 +03:00
p = unc_list [ conn_index % num_unc_names ] ;
if ( p [ 0 ] ! = ' / ' & & p [ 0 ] ! = ' \\ ' ) {
/* allow UNC lists of hosts */
( * host ) = talloc_strdup ( mem_ctx , p ) ;
} else if ( ! smbcli_parse_unc ( p , mem_ctx , host , share ) ) {
2007-05-14 05:04:01 +04:00
DEBUG ( 0 , ( " Failed to parse UNC name %s \n " ,
unc_list [ conn_index % num_unc_names ] ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2007-05-14 05:04:01 +04:00
}
talloc_free ( unc_list ) ;
2007-10-07 02:28:14 +04:00
return true ;
2006-03-17 20:59:58 +03:00
}
2007-05-14 05:04:01 +04:00
2006-10-16 17:06:41 +04:00
_PUBLIC_ bool torture_open_connection_ev ( struct smbcli_state * * c ,
2006-07-19 20:44:50 +04:00
int conn_index ,
2007-12-03 17:53:07 +03:00
struct torture_context * tctx ,
2008-12-29 22:24:57 +03:00
struct tevent_context * ev )
2006-04-10 08:51:52 +04:00
{
2007-05-14 05:04:01 +04:00
char * host , * share ;
bool ret ;
2006-07-19 20:44:50 +04:00
2007-12-03 17:53:07 +03:00
if ( ! torture_get_conn_index ( conn_index , ev , tctx , & host , & share ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2006-07-19 20:44:50 +04:00
}
2007-12-03 17:53:07 +03:00
ret = torture_open_connection_share ( NULL , c , tctx , host , share , ev ) ;
2007-05-14 05:04:01 +04:00
talloc_free ( host ) ;
talloc_free ( share ) ;
return ret ;
}
2006-04-10 08:51:52 +04:00
2007-12-03 17:53:07 +03:00
_PUBLIC_ bool torture_open_connection ( struct smbcli_state * * c , struct torture_context * tctx , int conn_index )
2007-05-14 05:04:01 +04:00
{
2008-04-14 20:43:37 +04:00
return torture_open_connection_ev ( c , conn_index , tctx , tctx - > ev ) ;
2006-04-10 08:51:52 +04:00
}
2006-03-17 20:59:58 +03:00
2006-10-16 17:06:41 +04:00
_PUBLIC_ bool torture_close_connection ( struct smbcli_state * c )
2006-03-17 20:59:58 +03:00
{
2007-10-07 02:28:14 +04:00
bool ret = true ;
if ( ! c ) return true ;
2006-03-17 20:59:58 +03:00
if ( NT_STATUS_IS_ERR ( smbcli_tdis ( c ) ) ) {
printf ( " tdis failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
ret = false ;
2006-03-17 20:59:58 +03:00
}
talloc_free ( c ) ;
return ret ;
}
/* check if the server produced the expected error code */
2006-10-16 17:06:41 +04:00
_PUBLIC_ bool check_error ( const char * location , struct smbcli_state * c ,
2006-03-17 20:59:58 +03:00
uint8_t eclass , uint32_t ecode , NTSTATUS nterr )
{
NTSTATUS status ;
status = smbcli_nt_error ( c - > tree ) ;
if ( NT_STATUS_IS_DOS ( status ) ) {
2009-02-02 15:03:36 +03:00
int classnum , num ;
classnum = NT_STATUS_DOS_CLASS ( status ) ;
2006-03-17 20:59:58 +03:00
num = NT_STATUS_DOS_CODE ( status ) ;
2009-02-02 15:03:36 +03:00
if ( eclass ! = classnum | | ecode ! = num ) {
2006-03-17 20:59:58 +03:00
printf ( " unexpected error code %s \n " , nt_errstr ( status ) ) ;
printf ( " expected %s or %s (at %s) \n " ,
nt_errstr ( NT_STATUS_DOS ( eclass , ecode ) ) ,
nt_errstr ( nterr ) , location ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-03-17 20:59:58 +03:00
}
} else {
if ( ! NT_STATUS_EQUAL ( nterr , status ) ) {
printf ( " unexpected error code %s \n " , nt_errstr ( status ) ) ;
printf ( " expected %s (at %s) \n " , nt_errstr ( nterr ) , location ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-03-17 20:59:58 +03:00
}
}
2007-10-07 02:28:14 +04:00
return true ;
2006-03-17 20:59:58 +03:00
}
2006-06-17 06:20:39 +04:00
static struct smbcli_state * current_cli ;
static int procnum ; /* records process count number when forking */
2006-03-17 20:59:58 +03:00
2006-06-17 06:20:39 +04:00
static void sigcont ( int sig )
{
}
2006-10-16 17:06:41 +04:00
double torture_create_procs ( struct torture_context * tctx ,
bool ( * fn ) ( struct torture_context * , struct smbcli_state * , int ) , bool * result )
2006-06-17 06:20:39 +04:00
{
int i , status ;
volatile pid_t * child_status ;
2006-10-16 17:06:41 +04:00
volatile bool * child_status_out ;
2006-06-17 06:20:39 +04:00
int synccount ;
int tries = 8 ;
2007-08-26 22:24:12 +04:00
int torture_nprocs = torture_setting_int ( tctx , " nprocs " , 4 ) ;
2006-06-17 06:20:39 +04:00
double start_time_limit = 10 + ( torture_nprocs * 1.5 ) ;
struct timeval tv ;
2007-10-07 02:28:14 +04:00
* result = true ;
2006-06-17 06:20:39 +04:00
synccount = 0 ;
signal ( SIGCONT , sigcont ) ;
child_status = ( volatile pid_t * ) shm_setup ( sizeof ( pid_t ) * torture_nprocs ) ;
if ( ! child_status ) {
printf ( " Failed to setup shared memory \n " ) ;
return - 1 ;
}
2006-10-16 17:06:41 +04:00
child_status_out = ( volatile bool * ) shm_setup ( sizeof ( bool ) * torture_nprocs ) ;
2006-06-17 06:20:39 +04:00
if ( ! child_status_out ) {
printf ( " Failed to setup result status shared memory \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < torture_nprocs ; i + + ) {
child_status [ i ] = 0 ;
2007-10-07 02:28:14 +04:00
child_status_out [ i ] = true ;
2006-06-17 06:20:39 +04:00
}
tv = timeval_current ( ) ;
for ( i = 0 ; i < torture_nprocs ; i + + ) {
procnum = i ;
if ( fork ( ) = = 0 ) {
char * myname ;
pid_t mypid = getpid ( ) ;
srandom ( ( ( int ) mypid ) ^ ( ( int ) time ( NULL ) ) ) ;
2009-01-02 22:38:24 +03:00
if ( asprintf ( & myname , " CLIENT%d " , i ) = = - 1 ) {
printf ( " asprintf failed \n " ) ;
return - 1 ;
}
2010-07-16 08:32:42 +04:00
lpcfg_set_cmdline ( tctx - > lp_ctx , " netbios name " , myname ) ;
2006-06-17 06:20:39 +04:00
free ( myname ) ;
while ( 1 ) {
2007-12-03 17:53:07 +03:00
if ( torture_open_connection ( & current_cli , tctx , i ) ) {
2006-07-10 13:39:14 +04:00
break ;
2006-06-17 06:20:39 +04:00
}
if ( tries - - = = 0 ) {
printf ( " pid %d failed to start \n " , ( int ) getpid ( ) ) ;
_exit ( 1 ) ;
}
2010-09-16 23:36:37 +04:00
smb_msleep ( 100 ) ;
2006-06-17 06:20:39 +04:00
}
child_status [ i ] = getpid ( ) ;
pause ( ) ;
if ( child_status [ i ] ) {
printf ( " Child %d failed to start! \n " , i ) ;
child_status_out [ i ] = 1 ;
_exit ( 1 ) ;
}
2006-10-16 17:06:41 +04:00
child_status_out [ i ] = fn ( tctx , current_cli , i ) ;
2006-06-17 06:20:39 +04:00
_exit ( 0 ) ;
}
}
do {
synccount = 0 ;
for ( i = 0 ; i < torture_nprocs ; i + + ) {
if ( child_status [ i ] ) synccount + + ;
}
if ( synccount = = torture_nprocs ) break ;
2010-09-16 23:36:37 +04:00
smb_msleep ( 100 ) ;
2006-06-17 06:20:39 +04:00
} while ( timeval_elapsed ( & tv ) < start_time_limit ) ;
if ( synccount ! = torture_nprocs ) {
printf ( " FAILED TO START %d CLIENTS (started %d) \n " , torture_nprocs , synccount ) ;
2007-10-07 02:28:14 +04:00
* result = false ;
2006-06-17 06:20:39 +04:00
return timeval_elapsed ( & tv ) ;
}
printf ( " Starting %d clients \n " , torture_nprocs ) ;
/* start the client load */
tv = timeval_current ( ) ;
for ( i = 0 ; i < torture_nprocs ; i + + ) {
child_status [ i ] = 0 ;
}
printf ( " %d clients started \n " , torture_nprocs ) ;
kill ( 0 , SIGCONT ) ;
for ( i = 0 ; i < torture_nprocs ; i + + ) {
int ret ;
while ( ( ret = waitpid ( 0 , & status , 0 ) ) = = - 1 & & errno = = EINTR ) /* noop */ ;
if ( ret = = - 1 | | WEXITSTATUS ( status ) ! = 0 ) {
2007-10-07 02:28:14 +04:00
* result = false ;
2006-06-17 06:20:39 +04:00
}
}
printf ( " \n " ) ;
for ( i = 0 ; i < torture_nprocs ; i + + ) {
if ( ! child_status_out [ i ] ) {
2007-10-07 02:28:14 +04:00
* result = false ;
2006-06-17 06:20:39 +04:00
}
}
return timeval_elapsed ( & tv ) ;
}
2006-10-16 17:06:41 +04:00
static bool wrap_smb_multi_test ( struct torture_context * torture ,
struct torture_tcase * tcase ,
struct torture_test * test )
2006-06-17 06:20:39 +04:00
{
2006-10-16 17:06:41 +04:00
bool ( * fn ) ( struct torture_context * , struct smbcli_state * , int ) = test - > fn ;
bool result ;
2006-06-17 06:20:39 +04:00
2006-10-16 17:06:41 +04:00
torture_create_procs ( torture , fn , & result ) ;
2006-06-17 06:20:39 +04:00
return result ;
}
2006-10-16 17:06:41 +04:00
_PUBLIC_ struct torture_test * torture_suite_add_smb_multi_test (
struct torture_suite * suite ,
const char * name ,
bool ( * run ) ( struct torture_context * ,
struct smbcli_state * ,
int i ) )
2006-06-17 06:20:39 +04:00
{
2006-10-16 17:06:41 +04:00
struct torture_test * test ;
struct torture_tcase * tcase ;
tcase = torture_suite_add_tcase ( suite , name ) ;
test = talloc ( tcase , struct torture_test ) ;
test - > name = talloc_strdup ( test , name ) ;
test - > description = NULL ;
test - > run = wrap_smb_multi_test ;
test - > fn = run ;
test - > dangerous = false ;
DLIST_ADD_END ( tcase - > tests , test , struct torture_test * ) ;
return test ;
}
static bool wrap_simple_2smb_test ( struct torture_context * torture_ctx ,
struct torture_tcase * tcase ,
struct torture_test * test )
{
bool ( * fn ) ( struct torture_context * , struct smbcli_state * ,
struct smbcli_state * ) ;
bool ret ;
struct smbcli_state * cli1 , * cli2 ;
2007-12-03 17:53:07 +03:00
if ( ! torture_open_connection ( & cli1 , torture_ctx , 0 ) | |
! torture_open_connection ( & cli2 , torture_ctx , 1 ) )
2006-10-16 17:06:41 +04:00
return false ;
fn = test - > fn ;
ret = fn ( torture_ctx , cli1 , cli2 ) ;
talloc_free ( cli1 ) ;
talloc_free ( cli2 ) ;
return ret ;
}
_PUBLIC_ struct torture_test * torture_suite_add_2smb_test (
struct torture_suite * suite ,
const char * name ,
bool ( * run ) ( struct torture_context * ,
struct smbcli_state * ,
struct smbcli_state * ) )
{
struct torture_test * test ;
struct torture_tcase * tcase ;
tcase = torture_suite_add_tcase ( suite , name ) ;
test = talloc ( tcase , struct torture_test ) ;
test - > name = talloc_strdup ( test , name ) ;
test - > description = NULL ;
test - > run = wrap_simple_2smb_test ;
test - > fn = run ;
test - > dangerous = false ;
DLIST_ADD_END ( tcase - > tests , test , struct torture_test * ) ;
return test ;
}
static bool wrap_simple_1smb_test ( struct torture_context * torture_ctx ,
struct torture_tcase * tcase ,
struct torture_test * test )
{
bool ( * fn ) ( struct torture_context * , struct smbcli_state * ) ;
bool ret ;
struct smbcli_state * cli1 ;
2007-12-03 17:53:07 +03:00
if ( ! torture_open_connection ( & cli1 , torture_ctx , 0 ) )
2006-10-16 17:06:41 +04:00
return false ;
fn = test - > fn ;
ret = fn ( torture_ctx , cli1 ) ;
talloc_free ( cli1 ) ;
return ret ;
}
_PUBLIC_ struct torture_test * torture_suite_add_1smb_test (
2007-09-02 06:07:55 +04:00
struct torture_suite * suite ,
const char * name ,
bool ( * run ) ( struct torture_context * , struct smbcli_state * ) )
2006-10-16 17:06:41 +04:00
{
struct torture_test * test ;
struct torture_tcase * tcase ;
tcase = torture_suite_add_tcase ( suite , name ) ;
test = talloc ( tcase , struct torture_test ) ;
2006-06-17 06:20:39 +04:00
2006-10-16 17:06:41 +04:00
test - > name = talloc_strdup ( test , name ) ;
test - > description = NULL ;
test - > run = wrap_simple_1smb_test ;
test - > fn = run ;
test - > dangerous = false ;
2006-06-17 06:20:39 +04:00
2006-10-16 17:06:41 +04:00
DLIST_ADD_END ( tcase - > tests , test , struct torture_test * ) ;
2006-06-17 06:20:39 +04:00
2006-10-16 17:06:41 +04:00
return test ;
2006-06-17 06:20:39 +04:00
}
2006-06-26 15:33:37 +04:00
2008-02-09 16:26:46 +03:00
NTSTATUS torture_second_tcon ( TALLOC_CTX * mem_ctx ,
struct smbcli_session * session ,
const char * sharename ,
struct smbcli_tree * * res )
{
union smb_tcon tcon ;
struct smbcli_tree * result ;
TALLOC_CTX * tmp_ctx ;
NTSTATUS status ;
if ( ( tmp_ctx = talloc_new ( mem_ctx ) ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
result = smbcli_tree_init ( session , tmp_ctx , false ) ;
if ( result = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
tcon . generic . level = RAW_TCON_TCONX ;
tcon . tconx . in . flags = 0 ;
/* Ignore share mode security here */
tcon . tconx . in . password = data_blob ( NULL , 0 ) ;
tcon . tconx . in . path = sharename ;
tcon . tconx . in . device = " ????? " ;
status = smb_raw_tcon ( result , tmp_ctx , & tcon ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return status ;
}
result - > tid = tcon . tconx . out . tid ;
* res = talloc_steal ( mem_ctx , result ) ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2009-10-16 11:23:42 +04:00
/*
a wrapper around smblsa_sid_check_privilege , that tries to take
account of the fact that the lsa privileges calls don ' t expand
group memberships , using an explicit check for administrator . There
must be a better way . . .
*/
NTSTATUS torture_check_privilege ( struct smbcli_state * cli ,
const char * sid_str ,
const char * privilege )
{
struct dom_sid * sid ;
TALLOC_CTX * tmp_ctx = talloc_new ( cli ) ;
uint32_t rid ;
NTSTATUS status ;
sid = dom_sid_parse_talloc ( tmp_ctx , sid_str ) ;
if ( sid = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NT_STATUS_INVALID_SID ;
}
status = dom_sid_split_rid ( tmp_ctx , sid , NULL , & rid ) ;
NT_STATUS_NOT_OK_RETURN_AND_FREE ( status , tmp_ctx ) ;
if ( rid = = DOMAIN_RID_ADMINISTRATOR ) {
/* assume the administrator has them all */
return NT_STATUS_OK ;
}
talloc_free ( tmp_ctx ) ;
return smblsa_sid_check_privilege ( cli , sid_str , privilege ) ;
}