2004-11-15 09:55:27 +03:00
/*
Unix SMB / CIFS implementation .
test DOS extended attributes
Copyright ( C ) Andrew Tridgell 2004
2005-06-30 05:36:02 +04:00
Copyright ( C ) Guenter Kukkukk 2005
2004-11-15 09:55:27 +03: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
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"
2006-01-03 16:41:17 +03:00
# include "torture/torture.h"
2004-11-15 09:55:27 +03:00
# include "libcli/raw/libcliraw.h"
2006-01-03 18:40:05 +03:00
# include "libcli/libcli.h"
2006-03-17 20:59:58 +03:00
# include "torture/util.h"
2004-11-15 09:55:27 +03:00
# define BASEDIR "\\testeas"
# define CHECK_STATUS(status, correct) do { \
if ( ! NT_STATUS_EQUAL ( status , correct ) ) { \
printf ( " (%s) Incorrect status %s - should be %s \n " , \
__location__ , nt_errstr ( status ) , nt_errstr ( correct ) ) ; \
ret = False ; \
goto done ; \
} } while ( 0 )
2005-07-01 15:50:30 +04:00
static BOOL maxeadebug ; /* need that here, to allow no file delete in debug case */
2005-06-30 05:36:02 +04:00
2004-12-13 13:48:21 +03:00
static BOOL check_ea ( struct smbcli_state * cli ,
const char * fname , const char * eaname , const char * value )
{
NTSTATUS status = torture_check_ea ( cli , fname , eaname , value ) ;
return NT_STATUS_IS_OK ( status ) ;
}
2004-11-15 09:55:27 +03:00
static BOOL test_eas ( struct smbcli_state * cli , TALLOC_CTX * mem_ctx )
{
NTSTATUS status ;
union smb_setfileinfo setfile ;
union smb_open io ;
const char * fname = BASEDIR " \\ ea.txt " ;
BOOL ret = True ;
2004-12-02 07:51:56 +03:00
int fnum = - 1 ;
2004-11-15 09:55:27 +03:00
2004-11-18 01:00:15 +03:00
printf ( " TESTING SETFILEINFO EA_SET \n " ) ;
2004-11-15 09:55:27 +03:00
io . generic . level = RAW_OPEN_NTCREATEX ;
io . ntcreatex . in . root_fid = 0 ;
io . ntcreatex . in . flags = 0 ;
2004-12-02 07:37:36 +03:00
io . ntcreatex . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
2004-11-15 09:55:27 +03:00
io . ntcreatex . in . create_options = 0 ;
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 = fname ;
status = smb_raw_open ( cli - > tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2006-03-13 01:48:25 +03:00
fnum = io . ntcreatex . out . file . fnum ;
2004-11-15 09:55:27 +03:00
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " EAONE " , NULL ) ;
2004-11-15 09:55:27 +03:00
2004-12-17 07:51:23 +03:00
printf ( " Adding first two EAs \n " ) ;
2004-11-15 09:55:27 +03:00
setfile . generic . level = RAW_SFILEINFO_EA_SET ;
2006-03-13 01:48:25 +03:00
setfile . generic . in . file . fnum = fnum ;
2004-12-17 07:51:23 +03:00
setfile . ea_set . in . num_eas = 2 ;
2005-01-27 10:08:20 +03:00
setfile . ea_set . in . eas = talloc_array ( mem_ctx , struct ea_struct , 2 ) ;
2004-12-17 07:51:23 +03:00
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_string_const ( " VALUE1 " ) ;
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_string_const ( " ValueTwo " ) ;
2004-11-15 09:55:27 +03:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " EAONE " , " VALUE1 " ) ;
ret & = check_ea ( cli , fname , " SECONDEA " , " ValueTwo " ) ;
2004-11-15 09:55:27 +03:00
printf ( " Modifying 2nd EA \n " ) ;
2004-12-17 07:51:23 +03:00
setfile . ea_set . in . num_eas = 1 ;
setfile . ea_set . in . eas [ 0 ] . name . s = " SECONDEA " ;
setfile . ea_set . in . eas [ 0 ] . value = data_blob_string_const ( " Changed Value " ) ;
2004-11-15 09:55:27 +03:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " EAONE " , " VALUE1 " ) ;
ret & = check_ea ( cli , fname , " SECONDEA " , " Changed Value " ) ;
2004-11-15 09:55:27 +03:00
printf ( " Setting a NULL EA \n " ) ;
2004-12-17 07:51:23 +03:00
setfile . ea_set . in . eas [ 0 ] . value = data_blob ( NULL , 0 ) ;
setfile . ea_set . in . eas [ 0 ] . name . s = " NULLEA " ;
2004-11-15 09:55:27 +03:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " EAONE " , " VALUE1 " ) ;
ret & = check_ea ( cli , fname , " SECONDEA " , " Changed Value " ) ;
ret & = check_ea ( cli , fname , " NULLEA " , NULL ) ;
2004-11-15 09:55:27 +03:00
printf ( " Deleting first EA \n " ) ;
2004-12-17 07:51:23 +03:00
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 ( NULL , 0 ) ;
2004-11-15 09:55:27 +03:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " EAONE " , NULL ) ;
ret & = check_ea ( cli , fname , " SECONDEA " , " Changed Value " ) ;
2004-11-15 09:55:27 +03:00
printf ( " Deleting second EA \n " ) ;
2004-12-17 07:51:23 +03:00
setfile . ea_set . in . eas [ 0 ] . flags = 0 ;
setfile . ea_set . in . eas [ 0 ] . name . s = " SECONDEA " ;
setfile . ea_set . in . eas [ 0 ] . value = data_blob ( NULL , 0 ) ;
2004-11-15 09:55:27 +03:00
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " EAONE " , NULL ) ;
ret & = check_ea ( cli , fname , " SECONDEA " , NULL ) ;
2004-11-15 09:55:27 +03:00
done :
smbcli_close ( cli - > tree , fnum ) ;
2004-11-18 01:00:15 +03:00
return ret ;
}
2005-06-30 05:36:02 +04:00
/*
* Helper function to retrieve the max . ea size for one ea name
*/
static int test_one_eamax ( struct smbcli_state * cli , const int fnum ,
const char * eaname , DATA_BLOB eablob ,
const int eastart , const int eadebug )
{
NTSTATUS status ;
struct ea_struct eastruct ;
union smb_setfileinfo setfile ;
int i , high , low , maxeasize ;
setfile . generic . level = RAW_SFILEINFO_EA_SET ;
2006-03-13 01:48:25 +03:00
setfile . generic . in . file . fnum = fnum ;
2005-06-30 05:36:02 +04:00
setfile . ea_set . in . num_eas = 1 ;
setfile . ea_set . in . eas = & eastruct ;
setfile . ea_set . in . eas - > flags = 0 ;
setfile . ea_set . in . eas - > name . s = eaname ;
setfile . ea_set . in . eas - > value = eablob ;
maxeasize = eablob . length ;
i = eastart ;
low = 0 ;
high = maxeasize ;
do {
if ( eadebug ) {
printf ( " Testing EA size: %d \n " , i ) ;
}
setfile . ea_set . in . eas - > value . length = i ;
status = smb_raw_setfileinfo ( cli - > tree , & setfile ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OK ) ) {
if ( eadebug ) {
printf ( " [%s] EA size %d succeeded! "
" (high=%d low=%d) \n " ,
eaname , i , high , low ) ;
}
low = i ;
if ( low = = maxeasize ) {
printf ( " Max. EA size for \" %s \" =%d "
" [but could be possibly larger] \n " ,
eaname , low ) ;
break ;
}
if ( high - low = = 1 & & high ! = maxeasize ) {
printf ( " Max. EA size for \" %s \" =%d \n " ,
eaname , low ) ;
break ;
}
i + = ( high - low + 1 ) / 2 ;
} else {
if ( eadebug ) {
printf ( " [%s] EA size %d failed! "
2005-07-04 09:05:28 +04:00
" (high=%d low=%d) [%s] \n " ,
2005-06-30 05:36:02 +04:00
eaname , i , high , low ,
nt_errstr ( status ) ) ;
}
high = i ;
if ( high - low < = 1 ) {
printf ( " Max. EA size for \" %s \" =%d \n " ,
eaname , low ) ;
break ;
}
i - = ( high - low + 1 ) / 2 ;
}
} while ( True ) ;
return low ;
}
/*
* Test for maximum ea size - more than one ea name is checked .
*
* Additional parameters can be passed , to allow further testing :
*
* default
* maxeasize 65536 limit the max . size for a single EA name
* maxeanames 101 limit of the number of tested names
* maxeastart 1 this EA size is used to test for the 1 st EA ( atm )
* maxeadebug 0 if set True , further debug output is done - in addition
* the testfile is not deleted for further inspection !
*
* Set some / all of these options on the cmdline with :
* - - option torture : maxeasize = 1024 - - option torture : maxeadebug = 1 . . .
*
*/
static BOOL test_max_eas ( struct smbcli_state * cli , TALLOC_CTX * mem_ctx )
{
NTSTATUS status ;
union smb_open io ;
const char * fname = BASEDIR " \\ ea_max.txt " ;
int fnum = - 1 ;
BOOL ret = True ;
BOOL err = False ;
int i , j , k , last , total ;
DATA_BLOB eablob ;
char * eaname = NULL ;
int maxeasize ;
int maxeanames ;
int maxeastart ;
printf ( " TESTING SETFILEINFO MAX. EA_SET \n " ) ;
maxeasize = lp_parm_int ( - 1 , " torture " , " maxeasize " , 65536 ) ;
maxeanames = lp_parm_int ( - 1 , " torture " , " maxeanames " , 101 ) ;
maxeastart = lp_parm_int ( - 1 , " torture " , " maxeastart " , 1 ) ;
maxeadebug = lp_parm_int ( - 1 , " torture " , " maxeadebug " , 0 ) ;
/* Do some sanity check on possibly passed parms */
if ( maxeasize < = 0 ) {
printf ( " Invalid parameter 'maxeasize=%d' " , maxeasize ) ;
err = True ;
}
if ( maxeanames < = 0 ) {
printf ( " Invalid parameter 'maxeanames=%d' " , maxeanames ) ;
err = True ;
}
if ( maxeastart < = 0 ) {
printf ( " Invalid parameter 'maxeastart=%d' " , maxeastart ) ;
err = True ;
}
if ( maxeadebug < 0 ) {
printf ( " Invalid parameter 'maxeadebug=%d' " , maxeadebug ) ;
err = True ;
}
if ( err ) {
printf ( " \n \n " ) ;
goto done ;
}
if ( maxeastart > maxeasize ) {
maxeastart = maxeasize ;
printf ( " 'maxeastart' outside range - corrected to %d \n " ,
maxeastart ) ;
}
printf ( " MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d "
" maxeadebug=%d \n " , maxeasize , maxeanames , maxeastart ,
maxeadebug ) ;
io . generic . level = RAW_OPEN_NTCREATEX ;
io . ntcreatex . in . root_fid = 0 ;
io . ntcreatex . in . flags = 0 ;
io . ntcreatex . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
io . ntcreatex . in . create_options = 0 ;
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 = fname ;
status = smb_raw_open ( cli - > tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2006-03-13 01:48:25 +03:00
fnum = io . ntcreatex . out . file . fnum ;
2005-06-30 05:36:02 +04:00
eablob = data_blob_talloc ( mem_ctx , NULL , maxeasize ) ;
if ( eablob . data = = NULL ) {
goto done ;
}
/*
* Fill in some EA data - the offset could be easily checked
* during a hexdump .
*/
for ( i = 0 , k = 0 ; i < eablob . length / 4 ; i + + , k + = 4 ) {
eablob . data [ k ] = k & 0xff ;
eablob . data [ k + 1 ] = ( k > > 8 ) & 0xff ;
eablob . data [ k + 2 ] = ( k > > 16 ) & 0xff ;
eablob . data [ k + 3 ] = ( k > > 24 ) & 0xff ;
}
i = eablob . length % 4 ;
if ( i - - > 0 ) {
eablob . data [ k ] = k & 0xff ;
if ( i - - > 0 ) {
eablob . data [ k + 1 ] = ( k > > 8 ) & 0xff ;
if ( i - - > 0 ) {
eablob . data [ k + 2 ] = ( k > > 16 ) & 0xff ;
}
}
}
/*
* Filesystems might allow max . EAs data for different EA names .
* So more than one EA name should be checked .
*/
total = 0 ;
last = maxeastart ;
for ( i = 0 ; i < maxeanames ; i + + ) {
if ( eaname ! = NULL ) {
talloc_free ( eaname ) ;
}
eaname = talloc_asprintf ( mem_ctx , " MAX%d " , i ) ;
if ( eaname = = NULL ) {
goto done ;
}
j = test_one_eamax ( cli , fnum , eaname , eablob , last , maxeadebug ) ;
if ( j < = 0 ) {
break ;
}
total + = j ;
last = j ;
}
printf ( " Total EA size:%d \n " , total ) ;
if ( i = = maxeanames ) {
printf ( " NOTE: More EAs could be available! \n " ) ;
}
if ( total = = 0 ) {
ret = False ;
}
done :
smbcli_close ( cli - > tree , fnum ) ;
return ret ;
}
2004-11-18 01:00:15 +03:00
/*
test using NTTRANS CREATE to create a file with an initial EA set
*/
2004-11-18 01:13:30 +03:00
static BOOL test_nttrans_create ( struct smbcli_state * cli , TALLOC_CTX * mem_ctx )
2004-11-18 01:00:15 +03:00
{
NTSTATUS status ;
union smb_open io ;
const char * fname = BASEDIR " \\ ea2.txt " ;
BOOL ret = True ;
int fnum = - 1 ;
struct ea_struct eas [ 3 ] ;
struct smb_ea_list ea_list ;
printf ( " TESTING NTTRANS CREATE WITH EAS \n " ) ;
io . generic . level = RAW_OPEN_NTTRANS_CREATE ;
io . ntcreatex . in . root_fid = 0 ;
io . ntcreatex . in . flags = 0 ;
2004-12-02 07:37:36 +03:00
io . ntcreatex . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
2004-11-18 01:00:15 +03:00
io . ntcreatex . in . create_options = 0 ;
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 = fname ;
ea_list . num_eas = 3 ;
ea_list . eas = eas ;
eas [ 0 ] . flags = 0 ;
eas [ 0 ] . name . s = " 1st EA " ;
eas [ 0 ] . value = data_blob_string_const ( " Value One " ) ;
eas [ 1 ] . flags = 0 ;
eas [ 1 ] . name . s = " 2nd EA " ;
eas [ 1 ] . value = data_blob_string_const ( " Second Value " ) ;
eas [ 2 ] . flags = 0 ;
eas [ 2 ] . name . s = " and 3rd " ;
eas [ 2 ] . value = data_blob_string_const ( " final value " ) ;
io . ntcreatex . in . ea_list = & ea_list ;
io . ntcreatex . in . sec_desc = NULL ;
status = smb_raw_open ( cli - > tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2006-03-13 01:48:25 +03:00
fnum = io . ntcreatex . out . file . fnum ;
2004-11-18 01:00:15 +03:00
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " EAONE " , NULL ) ;
ret & = check_ea ( cli , fname , " 1st EA " , " Value One " ) ;
ret & = check_ea ( cli , fname , " 2nd EA " , " Second Value " ) ;
ret & = check_ea ( cli , fname , " and 3rd " , " final value " ) ;
2004-11-18 01:00:15 +03:00
2004-11-18 01:13:30 +03:00
smbcli_close ( cli - > tree , fnum ) ;
printf ( " Trying to add EAs on non-create \n " ) ;
io . ntcreatex . in . open_disposition = NTCREATEX_DISP_OPEN ;
io . ntcreatex . in . fname = fname ;
ea_list . num_eas = 1 ;
eas [ 0 ] . flags = 0 ;
eas [ 0 ] . name . s = " Fourth EA " ;
eas [ 0 ] . value = data_blob_string_const ( " Value Four " ) ;
status = smb_raw_open ( cli - > tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2006-03-13 01:48:25 +03:00
fnum = io . ntcreatex . out . file . fnum ;
2004-11-18 01:13:30 +03:00
2004-12-13 13:48:21 +03:00
ret & = check_ea ( cli , fname , " 1st EA " , " Value One " ) ;
ret & = check_ea ( cli , fname , " 2nd EA " , " Second Value " ) ;
ret & = check_ea ( cli , fname , " and 3rd " , " final value " ) ;
ret & = check_ea ( cli , fname , " Fourth EA " , NULL ) ;
2004-11-18 01:13:30 +03:00
2004-11-18 01:00:15 +03:00
done :
smbcli_close ( cli - > tree , fnum ) ;
return ret ;
2004-11-15 09:55:27 +03:00
}
/*
basic testing of EA calls
*/
2006-03-25 19:01:28 +03:00
BOOL torture_raw_eas ( struct torture_context * torture )
2004-11-15 09:55:27 +03:00
{
struct smbcli_state * cli ;
BOOL ret = True ;
TALLOC_CTX * mem_ctx ;
2006-07-10 12:00:06 +04:00
if ( ! torture_open_connection ( & cli , 0 ) ) {
2004-11-15 09:55:27 +03:00
return False ;
}
mem_ctx = talloc_init ( " torture_raw_eas " ) ;
if ( ! torture_setup_dir ( cli , BASEDIR ) ) {
return False ;
}
ret & = test_eas ( cli , mem_ctx ) ;
2004-11-18 01:13:30 +03:00
ret & = test_nttrans_create ( cli , mem_ctx ) ;
2004-11-15 09:55:27 +03:00
2005-07-01 15:50:30 +04:00
smb_raw_exit ( cli - > session ) ;
torture_close_connection ( cli ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
/*
test max EA size
*/
2006-03-25 19:01:28 +03:00
BOOL torture_max_eas ( struct torture_context * torture )
2005-07-01 15:50:30 +04:00
{
struct smbcli_state * cli ;
BOOL ret = True ;
TALLOC_CTX * mem_ctx ;
2006-07-10 12:00:06 +04:00
if ( ! torture_open_connection ( & cli , 0 ) ) {
2005-07-01 15:50:30 +04:00
return False ;
}
mem_ctx = talloc_init ( " torture_raw_eas " ) ;
if ( ! torture_setup_dir ( cli , BASEDIR ) ) {
return False ;
}
ret & = test_max_eas ( cli , mem_ctx ) ;
2004-11-15 09:55:27 +03:00
smb_raw_exit ( cli - > session ) ;
2005-06-30 05:36:02 +04:00
if ( ! maxeadebug ) {
/* in no ea debug case, all files are gone now */
smbcli_deltree ( cli - > tree , BASEDIR ) ;
}
2004-11-15 09:55:27 +03:00
torture_close_connection ( cli ) ;
2005-01-27 10:08:20 +03:00
talloc_free ( mem_ctx ) ;
2004-11-15 09:55:27 +03:00
return ret ;
}