2007-03-06 01:26:38 +03:00
/*
Test the SMB_QUERY_FILE_UNIX_INFO2 Unix extension .
Copyright ( C ) 2007 James Peach
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
2007-03-06 01:26:38 +03: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/>.
2007-03-06 01:26:38 +03:00
*/
# include "includes.h"
# include "libcli/libcli.h"
# include "torture/util.h"
2014-02-27 12:08:17 +04:00
# include "torture/unix/proto.h"
2007-03-06 01:26:38 +03:00
# include "lib/cmdline/popt_common.h"
2008-01-03 03:39:01 +03:00
# include "libcli/resolve/resolve.h"
2007-12-12 04:15:29 +03:00
# include "param/param.h"
2007-03-06 01:26:38 +03:00
struct unix_info2 {
uint64_t end_of_file ;
uint64_t num_bytes ;
NTTIME status_change_time ;
NTTIME access_time ;
NTTIME change_time ;
uint64_t uid ;
uint64_t gid ;
uint32_t file_type ;
uint64_t dev_major ;
uint64_t dev_minor ;
uint64_t unique_id ;
uint64_t permissions ;
uint64_t nlink ;
NTTIME create_time ;
uint32_t file_flags ;
uint32_t flags_mask ;
} ;
2007-08-28 04:16:58 +04:00
static struct smbcli_state * connect_to_server ( struct torture_context * tctx )
2007-03-06 01:26:38 +03:00
{
NTSTATUS status ;
struct smbcli_state * cli ;
2007-08-28 04:16:58 +04:00
const char * host = torture_setting_string ( tctx , " host " , NULL ) ;
const char * share = torture_setting_string ( tctx , " share " , NULL ) ;
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 ) ;
2007-03-06 01:26:38 +03:00
2007-12-12 04:15:29 +03:00
status = smbcli_full_connection ( tctx , & cli , host ,
2010-07-16 08:32:42 +04:00
lpcfg_smb_ports ( tctx - > lp_ctx ) ,
share , NULL , lpcfg_socket_options ( tctx - > lp_ctx ) ,
2017-05-10 02:10:03 +03:00
popt_get_cmdline_credentials ( ) ,
2010-07-16 08:32:42 +04:00
lpcfg_resolve_context ( tctx - > lp_ctx ) ,
2008-10-24 15:13:27 +04:00
tctx - > ev , & options , & session_options ,
2010-07-16 08:32:42 +04:00
lpcfg_gensec_settings ( tctx , tctx - > lp_ctx ) ) ;
2007-03-06 01:26:38 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-08-20 15:29:26 +04:00
torture_comment ( tctx , " failed to connect to //%s/%s: %s \n " ,
host , share , nt_errstr ( status ) ) ;
torture_fail ( tctx , " Failed to connect to server " ) ;
2007-03-06 01:26:38 +03:00
return NULL ;
}
return cli ;
}
2007-10-07 02:28:14 +04:00
static bool check_unix_info2 ( struct torture_context * torture ,
2007-03-06 01:26:38 +03:00
struct unix_info2 * info2 )
{
printf ( " \t create_time=0x%016llu flags=0x%08x mask=0x%08x \n " ,
( unsigned long long ) info2 - > create_time ,
info2 - > file_flags , info2 - > flags_mask ) ;
if ( info2 - > file_flags = = 0 ) {
2007-10-07 02:28:14 +04:00
return true ;
2007-03-06 01:26:38 +03:00
}
/* If we have any file_flags set, they must be within the range
* defined by flags_mask .
*/
if ( ( info2 - > flags_mask & info2 - > file_flags ) = = 0 ) {
torture_result ( torture , TORTURE_FAIL ,
2007-04-12 14:35:21 +04:00
__location__ " : UNIX_INFO2 flags field 0x%08x, "
2007-03-06 01:26:38 +03:00
" does not match mask 0x%08x \n " ,
info2 - > file_flags , info2 - > flags_mask ) ;
}
2007-10-07 02:28:14 +04:00
return true ;
2007-03-06 01:26:38 +03:00
}
static NTSTATUS set_path_info2 ( void * mem_ctx ,
struct smbcli_state * cli ,
const char * fname ,
struct unix_info2 * info2 )
{
union smb_setfileinfo sfinfo ;
2007-03-23 23:28:45 +03:00
ZERO_STRUCT ( sfinfo . basic_info . in ) ;
2007-03-06 01:26:38 +03:00
sfinfo . generic . level = RAW_SFILEINFO_UNIX_INFO2 ;
sfinfo . generic . in . file . path = fname ;
sfinfo . unix_info2 . in . end_of_file = info2 - > end_of_file ;
sfinfo . unix_info2 . in . num_bytes = info2 - > num_bytes ;
sfinfo . unix_info2 . in . status_change_time = info2 - > status_change_time ;
sfinfo . unix_info2 . in . access_time = info2 - > access_time ;
sfinfo . unix_info2 . in . change_time = info2 - > change_time ;
sfinfo . unix_info2 . in . uid = info2 - > uid ;
sfinfo . unix_info2 . in . gid = info2 - > gid ;
sfinfo . unix_info2 . in . file_type = info2 - > file_type ;
sfinfo . unix_info2 . in . dev_major = info2 - > dev_major ;
sfinfo . unix_info2 . in . dev_minor = info2 - > dev_minor ;
sfinfo . unix_info2 . in . unique_id = info2 - > unique_id ;
sfinfo . unix_info2 . in . permissions = info2 - > permissions ;
sfinfo . unix_info2 . in . nlink = info2 - > nlink ;
sfinfo . unix_info2 . in . create_time = info2 - > create_time ;
sfinfo . unix_info2 . in . file_flags = info2 - > file_flags ;
sfinfo . unix_info2 . in . flags_mask = info2 - > flags_mask ;
return smb_raw_setpathinfo ( cli - > tree , & sfinfo ) ;
}
2007-10-07 02:28:14 +04:00
static bool query_file_path_info2 ( void * mem_ctx ,
2007-03-06 01:26:38 +03:00
struct torture_context * torture ,
struct smbcli_state * cli ,
int fnum ,
const char * fname ,
struct unix_info2 * info2 )
{
NTSTATUS result ;
union smb_fileinfo finfo ;
finfo . generic . level = RAW_FILEINFO_UNIX_INFO2 ;
if ( fname ) {
finfo . generic . in . file . path = fname ;
result = smb_raw_pathinfo ( cli - > tree , mem_ctx , & finfo ) ;
} else {
finfo . generic . in . file . fnum = fnum ;
result = smb_raw_fileinfo ( cli - > tree , mem_ctx , & finfo ) ;
}
torture_assert_ntstatus_equal ( torture , result , NT_STATUS_OK ,
smbcli_errstr ( cli - > tree ) ) ;
info2 - > end_of_file = finfo . unix_info2 . out . end_of_file ;
info2 - > num_bytes = finfo . unix_info2 . out . num_bytes ;
info2 - > status_change_time = finfo . unix_info2 . out . status_change_time ;
info2 - > access_time = finfo . unix_info2 . out . access_time ;
info2 - > change_time = finfo . unix_info2 . out . change_time ;
info2 - > uid = finfo . unix_info2 . out . uid ;
info2 - > gid = finfo . unix_info2 . out . gid ;
info2 - > file_type = finfo . unix_info2 . out . file_type ;
info2 - > dev_major = finfo . unix_info2 . out . dev_major ;
info2 - > dev_minor = finfo . unix_info2 . out . dev_minor ;
info2 - > unique_id = finfo . unix_info2 . out . unique_id ;
info2 - > permissions = finfo . unix_info2 . out . permissions ;
info2 - > nlink = finfo . unix_info2 . out . nlink ;
info2 - > create_time = finfo . unix_info2 . out . create_time ;
info2 - > file_flags = finfo . unix_info2 . out . file_flags ;
info2 - > flags_mask = finfo . unix_info2 . out . flags_mask ;
if ( ! check_unix_info2 ( torture , info2 ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2007-03-06 01:26:38 +03:00
}
2007-10-07 02:28:14 +04:00
return true ;
2007-03-06 01:26:38 +03:00
}
2007-10-07 02:28:14 +04:00
static bool query_file_info2 ( void * mem_ctx ,
2007-03-06 01:26:38 +03:00
struct torture_context * torture ,
struct smbcli_state * cli ,
int fnum ,
struct unix_info2 * info2 )
{
return query_file_path_info2 ( mem_ctx , torture , cli ,
fnum , NULL , info2 ) ;
}
2007-10-07 02:28:14 +04:00
static bool query_path_info2 ( void * mem_ctx ,
2007-03-06 01:26:38 +03:00
struct torture_context * torture ,
struct smbcli_state * cli ,
const char * fname ,
struct unix_info2 * info2 )
{
return query_file_path_info2 ( mem_ctx , torture , cli ,
- 1 , fname , info2 ) ;
}
2009-02-02 10:44:44 +03:00
static bool search_callback ( void * private_data , const union smb_search_data * fdata )
2007-03-06 01:26:38 +03:00
{
2009-02-02 10:44:44 +03:00
struct unix_info2 * info2 = ( struct unix_info2 * ) private_data ;
2007-03-06 01:26:38 +03:00
info2 - > end_of_file = fdata - > unix_info2 . end_of_file ;
info2 - > num_bytes = fdata - > unix_info2 . num_bytes ;
info2 - > status_change_time = fdata - > unix_info2 . status_change_time ;
info2 - > access_time = fdata - > unix_info2 . access_time ;
info2 - > change_time = fdata - > unix_info2 . change_time ;
info2 - > uid = fdata - > unix_info2 . uid ;
info2 - > gid = fdata - > unix_info2 . gid ;
info2 - > file_type = fdata - > unix_info2 . file_type ;
info2 - > dev_major = fdata - > unix_info2 . dev_major ;
info2 - > dev_minor = fdata - > unix_info2 . dev_minor ;
info2 - > unique_id = fdata - > unix_info2 . unique_id ;
info2 - > permissions = fdata - > unix_info2 . permissions ;
info2 - > nlink = fdata - > unix_info2 . nlink ;
info2 - > create_time = fdata - > unix_info2 . create_time ;
info2 - > file_flags = fdata - > unix_info2 . file_flags ;
info2 - > flags_mask = fdata - > unix_info2 . flags_mask ;
2007-10-07 02:28:14 +04:00
return true ;
2007-03-06 01:26:38 +03:00
}
2007-10-07 02:28:14 +04:00
static bool find_single_info2 ( void * mem_ctx ,
2007-03-06 01:26:38 +03:00
struct torture_context * torture ,
struct smbcli_state * cli ,
const char * fname ,
struct unix_info2 * info2 )
{
union smb_search_first search ;
NTSTATUS status ;
/* Set up a new search for a single item, not using resume keys. */
ZERO_STRUCT ( search ) ;
search . t2ffirst . level = RAW_SEARCH_TRANS2 ;
search . t2ffirst . data_level = SMB_FIND_UNIX_INFO2 ;
search . t2ffirst . in . max_count = 1 ;
search . t2ffirst . in . flags = FLAG_TRANS2_FIND_CLOSE ;
search . t2ffirst . in . pattern = fname ;
status = smb_raw_search_first ( cli - > tree , mem_ctx ,
& search , info2 , search_callback ) ;
torture_assert_ntstatus_equal ( torture , status , NT_STATUS_OK ,
smbcli_errstr ( cli - > tree ) ) ;
torture_assert_int_equal ( torture , search . t2ffirst . out . count , 1 ,
" expected exactly one result " ) ;
torture_assert_int_equal ( torture , search . t2ffirst . out . end_of_search , 1 ,
" expected end_of_search to be true " ) ;
return check_unix_info2 ( torture , info2 ) ;
}
# define ASSERT_FLAGS_MATCH(info2, expected) \
if ( ( info2 ) - > file_flags ! = ( 1 < < i ) ) { \
torture_result ( torture , TORTURE_FAIL , \
__location__ " : INFO2 flags field was 0x%08x, " \
" expected 0x%08x \n " , \
( info2 ) - > file_flags , expected ) ; \
}
static void set_no_metadata_change ( struct unix_info2 * info2 )
{
info2 - > uid = SMB_UID_NO_CHANGE ;
info2 - > gid = SMB_GID_NO_CHANGE ;
info2 - > permissions = SMB_MODE_NO_CHANGE ;
info2 - > end_of_file =
( ( uint64_t ) SMB_SIZE_NO_CHANGE_HI < < 32 ) | SMB_SIZE_NO_CHANGE_LO ;
info2 - > status_change_time =
info2 - > access_time =
info2 - > change_time =
info2 - > create_time =
( ( uint64_t ) SMB_SIZE_NO_CHANGE_HI < < 32 ) | SMB_SIZE_NO_CHANGE_LO ;
}
2007-10-07 02:28:14 +04:00
static bool verify_setinfo_flags ( void * mem_ctx ,
2007-03-06 01:26:38 +03:00
struct torture_context * torture ,
struct smbcli_state * cli ,
const char * fname )
{
struct unix_info2 info2 ;
uint32_t smb_fmask ;
int i ;
2007-10-07 02:28:14 +04:00
bool ret = true ;
2007-03-06 01:26:38 +03:00
NTSTATUS status ;
if ( ! query_path_info2 ( mem_ctx , torture , cli , fname , & info2 ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2007-03-06 01:26:38 +03:00
}
smb_fmask = info2 . flags_mask ;
/* For each possible flag, ask to set exactly 1 flag, making sure
* that flag is in our requested mask .
*/
for ( i = 0 ; i < 32 ; + + i ) {
2019-05-22 16:10:47 +03:00
info2 . file_flags = ( ( uint32_t ) 1 < < i ) ;
2007-03-06 01:26:38 +03:00
info2 . flags_mask = smb_fmask | info2 . file_flags ;
set_no_metadata_change ( & info2 ) ;
status = set_path_info2 ( mem_ctx , cli , fname , & info2 ) ;
if ( info2 . file_flags & smb_fmask ) {
torture_assert_ntstatus_equal ( torture ,
status , NT_STATUS_OK ,
2007-03-23 22:24:21 +03:00
" setting valid UNIX_INFO2 flag " ) ;
2007-03-06 01:26:38 +03:00
if ( ! query_path_info2 ( mem_ctx , torture , cli ,
fname , & info2 ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2007-03-06 01:26:38 +03:00
}
ASSERT_FLAGS_MATCH ( & info2 , 1 < < i ) ;
} else {
/* We tried to set a flag the server doesn't
* understand .
*/
torture_assert_ntstatus_equal ( torture ,
status , NT_STATUS_INVALID_PARAMETER ,
2007-03-23 22:24:21 +03:00
" setting invalid UNIX_INFO2 flag " ) ;
2007-03-06 01:26:38 +03:00
}
}
/* Make sure that a zero flags field does nothing. */
set_no_metadata_change ( & info2 ) ;
info2 . file_flags = 0xFFFFFFFF ;
info2 . flags_mask = 0 ;
status = set_path_info2 ( mem_ctx , cli , fname , & info2 ) ;
torture_assert_ntstatus_equal ( torture , status , NT_STATUS_OK ,
" setting empty flags mask " ) ;
return ret ;
}
static int create_file ( struct smbcli_state * cli , const char * fname )
{
return smbcli_nt_create_full ( cli - > tree , fname , 0 ,
SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA , FILE_ATTRIBUTE_NORMAL ,
NTCREATEX_SHARE_ACCESS_NONE , NTCREATEX_DISP_OPEN_IF ,
0 , 0 ) ;
}
2007-10-07 02:28:14 +04:00
static bool match_info2 ( struct torture_context * torture ,
2007-03-06 01:26:38 +03:00
const struct unix_info2 * pinfo ,
const struct unix_info2 * finfo )
{
printf ( " checking results match \n " ) ;
torture_assert_u64_equal ( torture , finfo - > end_of_file , 0 ,
" end_of_file should be 0 " ) ;
torture_assert_u64_equal ( torture , finfo - > num_bytes , 0 ,
" num_bytes should be 0 " ) ;
torture_assert_u64_equal ( torture , finfo - > end_of_file ,
pinfo - > end_of_file , " end_of_file mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > num_bytes , pinfo - > num_bytes ,
" num_bytes mismatch " ) ;
/* Don't match access_time. */
torture_assert_u64_equal ( torture , finfo - > status_change_time ,
pinfo - > status_change_time ,
" status_change_time mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > change_time ,
pinfo - > change_time , " change_time mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > uid , pinfo - > uid ,
" UID mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > gid , pinfo - > gid ,
" GID mismatch " ) ;
torture_assert_int_equal ( torture , finfo - > file_type , pinfo - > file_type ,
" file_type mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > dev_major , pinfo - > dev_major ,
" dev_major mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > dev_minor , pinfo - > dev_minor ,
" dev_minor mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > unique_id , pinfo - > unique_id ,
" unique_id mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > permissions ,
pinfo - > permissions , " permissions mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > nlink , pinfo - > nlink ,
" nlink mismatch " ) ;
torture_assert_u64_equal ( torture , finfo - > create_time , pinfo - > create_time ,
" create_time mismatch " ) ;
2007-10-07 02:28:14 +04:00
return true ;
2007-03-06 01:26:38 +03:00
}
# define FILENAME "\\smb_unix_info2.txt"
2007-10-07 02:28:14 +04:00
bool unix_torture_unix_info2 ( struct torture_context * torture )
2007-03-06 01:26:38 +03:00
{
void * mem_ctx ;
struct smbcli_state * cli ;
int fnum ;
struct unix_info2 pinfo , finfo ;
mem_ctx = talloc_init ( " smb_query_unix_info2 " ) ;
torture_assert ( torture , mem_ctx ! = NULL , " out of memory " ) ;
2007-08-28 04:16:58 +04:00
if ( ! ( cli = connect_to_server ( torture ) ) ) {
2007-03-06 01:26:38 +03:00
talloc_free ( mem_ctx ) ;
2007-10-07 02:28:14 +04:00
return false ;
2007-03-06 01:26:38 +03:00
}
smbcli_unlink ( cli - > tree , FILENAME ) ;
fnum = create_file ( cli , FILENAME ) ;
torture_assert ( torture , fnum ! = - 1 , smbcli_errstr ( cli - > tree ) ) ;
printf ( " checking SMB_QFILEINFO_UNIX_INFO2 for QueryFileInfo \n " ) ;
if ( ! query_file_info2 ( mem_ctx , torture , cli , fnum , & finfo ) ) {
goto fail ;
}
printf ( " checking SMB_QFILEINFO_UNIX_INFO2 for QueryPathInfo \n " ) ;
if ( ! query_path_info2 ( mem_ctx , torture , cli , FILENAME , & pinfo ) ) {
goto fail ;
}
if ( ! match_info2 ( torture , & pinfo , & finfo ) ) {
goto fail ;
}
printf ( " checking SMB_FIND_UNIX_INFO2 for FindFirst \n " ) ;
if ( ! find_single_info2 ( mem_ctx , torture , cli , FILENAME , & pinfo ) ) {
goto fail ;
}
if ( ! match_info2 ( torture , & pinfo , & finfo ) ) {
goto fail ;
}
/* XXX: should repeat this test with SetFileInfo. */
printf ( " checking SMB_SFILEINFO_UNIX_INFO2 for SetPathInfo \n " ) ;
if ( ! verify_setinfo_flags ( mem_ctx , torture , cli , FILENAME ) ) {
goto fail ;
}
smbcli_close ( cli - > tree , fnum ) ;
smbcli_unlink ( cli - > tree , FILENAME ) ;
torture_close_connection ( cli ) ;
talloc_free ( mem_ctx ) ;
2007-10-07 02:28:14 +04:00
return true ;
2007-03-06 01:26:38 +03:00
fail :
smbcli_close ( cli - > tree , fnum ) ;
smbcli_unlink ( cli - > tree , FILENAME ) ;
torture_close_connection ( cli ) ;
talloc_free ( mem_ctx ) ;
2007-10-07 02:28:14 +04:00
return false ;
2007-03-06 01:26:38 +03:00
}
/* vim: set sts=8 sw=8 : */