2005-11-15 04:38:59 +00:00
/*
Unix SMB / CIFS implementation .
SMB2 getinfo test suite
Copyright ( C ) Andrew Tridgell 2005
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 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2005-11-15 04:38:59 +00: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 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-11-15 04:38:59 +00:00
*/
# include "includes.h"
# include "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
2013-08-27 09:41:13 +00:00
# include "libcli/smb/smbXcli_base.h"
2005-11-15 04:38:59 +00:00
2006-03-25 16:01:28 +00:00
# include "torture/torture.h"
2006-02-04 14:08:24 +00:00
# include "torture/smb2/proto.h"
2013-08-27 09:41:13 +00:00
# include "torture/util.h"
2006-02-04 14:08:24 +00:00
2005-11-15 04:38:59 +00:00
static struct {
const char * name ;
uint16_t level ;
NTSTATUS fstatus ;
NTSTATUS dstatus ;
2005-11-17 11:06:13 +00:00
union smb_fileinfo finfo ;
union smb_fileinfo dinfo ;
} file_levels [ ] = {
2005-11-15 04:38:59 +00:00
# define LEVEL(x) #x, x
2005-11-17 11:06:13 +00:00
{ LEVEL ( RAW_FILEINFO_BASIC_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_STANDARD_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_INTERNAL_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_EA_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_ACCESS_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_POSITION_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_MODE_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_ALIGNMENT_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_ALL_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_ALT_NAME_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_STREAM_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_COMPRESSION_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_NETWORK_OPEN_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION ) } ,
2009-07-14 13:32:23 +02:00
2008-05-22 14:50:36 +10:00
{ LEVEL ( RAW_FILEINFO_SMB2_ALL_EAS ) } ,
2009-07-14 13:32:23 +02:00
2005-11-17 11:06:13 +00:00
{ LEVEL ( RAW_FILEINFO_SMB2_ALL_INFORMATION ) } ,
{ LEVEL ( RAW_FILEINFO_SEC_DESC ) }
} ;
static struct {
const char * name ;
uint16_t level ;
NTSTATUS status ;
union smb_fsinfo info ;
} fs_levels [ ] = {
{ LEVEL ( RAW_QFS_VOLUME_INFORMATION ) } ,
{ LEVEL ( RAW_QFS_SIZE_INFORMATION ) } ,
{ LEVEL ( RAW_QFS_DEVICE_INFORMATION ) } ,
{ LEVEL ( RAW_QFS_ATTRIBUTE_INFORMATION ) } ,
{ LEVEL ( RAW_QFS_QUOTA_INFORMATION ) } ,
{ LEVEL ( RAW_QFS_FULL_SIZE_INFORMATION ) } ,
2015-03-13 01:06:26 +01:00
{ LEVEL ( RAW_QFS_OBJECTID_INFORMATION ) } ,
{ LEVEL ( RAW_QFS_SECTOR_SIZE_INFORMATION ) } ,
2005-11-15 04:38:59 +00:00
} ;
# define FNAME "testsmb2_file.dat"
# define DNAME "testsmb2_dir"
2005-11-17 11:06:13 +00:00
/*
test fileinfo levels
2005-11-15 04:38:59 +00:00
*/
2007-12-03 15:53:17 +01:00
static bool torture_smb2_fileinfo ( struct torture_context * tctx , struct smb2_tree * tree )
2005-11-15 04:38:59 +00:00
{
struct smb2_handle hfile , hdir ;
NTSTATUS status ;
int i ;
status = torture_smb2_testfile ( tree , FNAME , & hfile ) ;
2012-02-28 14:19:49 +01:00
torture_assert_ntstatus_ok ( tctx , status , " Unable to create test file "
FNAME " \n " ) ;
2005-11-15 04:38:59 +00:00
status = torture_smb2_testdir ( tree , DNAME , & hdir ) ;
2012-02-28 14:19:49 +01:00
torture_assert_ntstatus_ok ( tctx , status , " Unable to create test dir "
DNAME " \n " ) ;
2005-11-15 04:38:59 +00:00
2016-02-22 15:51:06 +01:00
torture_comment ( tctx , " Testing file info levels \n " ) ;
2016-02-22 15:40:50 +01:00
torture_smb2_all_info ( tctx , tree , hfile ) ;
torture_smb2_all_info ( tctx , tree , hdir ) ;
2005-11-15 04:38:59 +00:00
2005-11-17 11:06:13 +00:00
for ( i = 0 ; i < ARRAY_SIZE ( file_levels ) ; i + + ) {
if ( file_levels [ i ] . level = = RAW_FILEINFO_SEC_DESC ) {
2006-03-10 20:49:20 +00:00
file_levels [ i ] . finfo . query_secdesc . in . secinfo_flags = 0x7 ;
file_levels [ i ] . dinfo . query_secdesc . in . secinfo_flags = 0x7 ;
2005-11-15 04:38:59 +00:00
}
2005-11-19 05:55:08 +00:00
if ( file_levels [ i ] . level = = RAW_FILEINFO_SMB2_ALL_EAS ) {
2012-02-28 14:19:49 +01:00
file_levels [ i ] . finfo . all_eas . in . continue_flags =
2005-11-19 06:39:12 +00:00
SMB2_CONTINUE_FLAG_RESTART ;
2012-02-28 14:19:49 +01:00
file_levels [ i ] . dinfo . all_eas . in . continue_flags =
2005-11-19 06:39:12 +00:00
SMB2_CONTINUE_FLAG_RESTART ;
2005-11-19 05:55:08 +00:00
}
2005-11-17 11:06:13 +00:00
file_levels [ i ] . finfo . generic . level = file_levels [ i ] . level ;
2006-03-12 22:48:25 +00:00
file_levels [ i ] . finfo . generic . in . file . handle = hfile ;
2005-11-17 11:06:13 +00:00
file_levels [ i ] . fstatus = smb2_getinfo_file ( tree , tree , & file_levels [ i ] . finfo ) ;
2012-02-28 14:19:49 +01:00
torture_assert_ntstatus_ok ( tctx , file_levels [ i ] . fstatus ,
talloc_asprintf ( tctx , " %s on file " ,
file_levels [ i ] . name ) ) ;
2005-11-17 11:06:13 +00:00
file_levels [ i ] . dinfo . generic . level = file_levels [ i ] . level ;
2006-03-12 22:48:25 +00:00
file_levels [ i ] . dinfo . generic . in . file . handle = hdir ;
2005-11-17 11:06:13 +00:00
file_levels [ i ] . dstatus = smb2_getinfo_file ( tree , tree , & file_levels [ i ] . dinfo ) ;
2012-02-28 14:19:49 +01:00
torture_assert_ntstatus_ok ( tctx , file_levels [ i ] . dstatus ,
talloc_asprintf ( tctx , " %s on dir " ,
file_levels [ i ] . name ) ) ;
2005-11-15 04:38:59 +00:00
}
2007-10-06 22:28:14 +00:00
return true ;
2005-11-15 04:38:59 +00:00
}
2005-11-17 11:06:13 +00:00
2016-08-13 21:23:34 +03:00
/*
test granted access when desired access includes
FILE_EXECUTE and does not include FILE_READ_DATA
*/
static bool torture_smb2_fileinfo_grant_read ( struct torture_context * tctx )
{
struct smb2_tree * tree ;
bool ret ;
struct smb2_handle hfile , hdir ;
NTSTATUS status ;
uint32_t file_granted_access , dir_granted_access ;
ret = torture_smb2_connection ( tctx , & tree ) ;
torture_assert ( tctx , ret , " connection failed " ) ;
status = torture_smb2_testfile_access (
tree , FNAME , & hfile , SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE ) ;
torture_assert_ntstatus_ok ( tctx , status ,
" Unable to create test file " FNAME " \n " ) ;
status =
torture_smb2_get_allinfo_access ( tree , hfile , & file_granted_access ) ;
torture_assert_ntstatus_ok ( tctx , status ,
" Unable to query test file access " ) ;
torture_assert_int_equal ( tctx , file_granted_access ,
SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE ,
" granted file access " ) ;
smb2_util_close ( tree , hfile ) ;
status = torture_smb2_testdir_access (
tree , DNAME , & hdir , SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE ) ;
torture_assert_ntstatus_ok ( tctx , status ,
" Unable to create test dir " DNAME " \n " ) ;
status =
torture_smb2_get_allinfo_access ( tree , hdir , & dir_granted_access ) ;
torture_assert_ntstatus_ok ( tctx , status ,
" Unable to query test dir access " ) ;
torture_assert_int_equal ( tctx , dir_granted_access ,
SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE ,
" granted dir access " ) ;
smb2_util_close ( tree , hdir ) ;
return true ;
}
2005-11-17 11:06:13 +00:00
/*
test fsinfo levels
*/
2013-08-22 11:47:21 +00:00
static bool torture_smb2_fsinfo ( struct torture_context * tctx )
2005-11-17 11:06:13 +00:00
{
2013-08-22 11:47:21 +00:00
bool ret ;
struct smb2_tree * tree ;
2005-11-17 11:06:13 +00:00
int i ;
NTSTATUS status ;
struct smb2_handle handle ;
2016-02-22 15:51:06 +01:00
torture_comment ( tctx , " Testing fsinfo levels \n " ) ;
2013-08-22 11:47:21 +00:00
ret = torture_smb2_connection ( tctx , & tree ) ;
torture_assert ( tctx , ret , " connection failed " ) ;
2005-11-19 05:55:08 +00:00
status = smb2_util_roothandle ( tree , & handle ) ;
2012-02-28 14:19:49 +01:00
torture_assert_ntstatus_ok ( tctx , status , " Unable to create root handle " ) ;
2005-11-17 11:06:13 +00:00
for ( i = 0 ; i < ARRAY_SIZE ( fs_levels ) ; i + + ) {
fs_levels [ i ] . info . generic . level = fs_levels [ i ] . level ;
fs_levels [ i ] . info . generic . handle = handle ;
fs_levels [ i ] . status = smb2_getinfo_fs ( tree , tree , & fs_levels [ i ] . info ) ;
2012-02-28 14:19:49 +01:00
torture_assert_ntstatus_ok ( tctx , fs_levels [ i ] . status ,
fs_levels [ i ] . name ) ;
2005-11-17 11:06:13 +00:00
}
2007-10-06 22:28:14 +00:00
return true ;
2005-11-17 11:06:13 +00:00
}
2013-08-27 09:41:13 +00:00
static bool torture_smb2_buffercheck_err ( struct torture_context * tctx ,
struct smb2_tree * tree ,
struct smb2_getinfo * b ,
size_t fixed ,
DATA_BLOB full )
{
size_t i ;
2005-11-17 11:06:13 +00:00
2013-08-27 09:41:13 +00:00
for ( i = 0 ; i < = full . length ; i + + ) {
NTSTATUS status ;
b - > in . output_buffer_length = i ;
status = smb2_getinfo ( tree , tree , b ) ;
if ( i < fixed ) {
torture_assert_ntstatus_equal (
tctx , status , NT_STATUS_INFO_LENGTH_MISMATCH ,
" Wrong error code small buffer " ) ;
continue ;
}
if ( i < full . length ) {
torture_assert_ntstatus_equal (
tctx , status , STATUS_BUFFER_OVERFLOW ,
" Wrong error code for large buffer " ) ;
/*
* TODO : compare the output buffer . That seems a bit
* difficult , because for level 5 for example the
* label length is adjusted to what is there . And some
* reserved fields seem to be not initialized to 0.
*/
TALLOC_FREE ( b - > out . blob . data ) ;
continue ;
}
torture_assert_ntstatus_equal (
tctx , status , NT_STATUS_OK ,
" Wrong error code for right sized buffer " ) ;
}
return true ;
}
struct level_buffersize {
int level ;
size_t fixed ;
} ;
static bool torture_smb2_qfs_buffercheck ( struct torture_context * tctx )
2008-05-31 13:39:51 +10:00
{
2013-08-22 11:23:22 +00:00
bool ret ;
struct smb2_tree * tree ;
2008-05-31 13:39:51 +10:00
NTSTATUS status ;
struct smb2_handle handle ;
2013-08-27 09:41:13 +00:00
int i ;
struct level_buffersize levels [ ] = {
{ 1 , 24 } , /* We don't have proper defines here */
{ 3 , 24 } ,
{ 4 , 8 } ,
{ 5 , 16 } ,
{ 6 , 48 } ,
{ 7 , 32 } ,
{ 11 , 28 } ,
} ;
2008-05-31 13:39:51 +10:00
2016-02-22 15:51:06 +01:00
torture_comment ( tctx , " Testing SMB2_GETINFO_FS buffer sizes \n " ) ;
2013-08-22 11:23:22 +00:00
ret = torture_smb2_connection ( tctx , & tree ) ;
torture_assert ( tctx , ret , " connection failed " ) ;
2008-05-31 13:39:51 +10:00
status = smb2_util_roothandle ( tree , & handle ) ;
2013-08-27 09:41:13 +00:00
torture_assert_ntstatus_ok (
tctx , status , " Unable to create root handle " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( levels ) ; i + + ) {
struct smb2_getinfo b ;
if ( TARGET_IS_SAMBA3 ( tctx ) & &
( ( levels [ i ] . level = = 6 ) | | ( levels [ i ] . level = = 11 ) ) ) {
continue ;
}
ZERO_STRUCT ( b ) ;
b . in . info_type = SMB2_GETINFO_FS ;
b . in . info_class = levels [ i ] . level ;
b . in . file . handle = handle ;
b . in . output_buffer_length = 65535 ;
status = smb2_getinfo ( tree , tree , & b ) ;
torture_assert_ntstatus_equal (
tctx , status , NT_STATUS_OK ,
" Wrong error code for large buffer " ) ;
ret = torture_smb2_buffercheck_err (
tctx , tree , & b , levels [ i ] . fixed , b . out . blob ) ;
if ( ! ret ) {
return ret ;
}
}
return true ;
}
static bool torture_smb2_qfile_buffercheck ( struct torture_context * tctx )
{
bool ret ;
struct smb2_tree * tree ;
struct smb2_create c ;
NTSTATUS status ;
struct smb2_handle handle ;
int i ;
struct level_buffersize levels [ ] = {
{ 4 , 40 } ,
{ 5 , 24 } ,
{ 6 , 8 } ,
{ 7 , 4 } ,
{ 8 , 4 } ,
{ 16 , 4 } ,
{ 17 , 4 } ,
{ 18 , 104 } ,
{ 21 , 8 } ,
{ 22 , 32 } ,
{ 28 , 16 } ,
{ 34 , 56 } ,
{ 35 , 8 } ,
} ;
2016-02-22 15:51:06 +01:00
torture_comment ( tctx , " Testing SMB2_GETINFO_FILE buffer sizes \n " ) ;
2013-08-27 09:41:13 +00:00
ret = torture_smb2_connection ( tctx , & tree ) ;
torture_assert ( tctx , ret , " connection failed " ) ;
ZERO_STRUCT ( c ) ;
c . in . desired_access = SEC_FLAG_MAXIMUM_ALLOWED ;
c . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
c . in . create_disposition = NTCREATEX_DISP_OVERWRITE_IF ;
c . in . share_access =
NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
c . in . create_options = 0 ;
c . in . fname = " bufsize.txt " ;
c . in . eas . num_eas = 2 ;
c . in . eas . eas = talloc_array ( tree , struct ea_struct , 2 ) ;
c . in . eas . eas [ 0 ] . flags = 0 ;
c . in . eas . eas [ 0 ] . name . s = " EAONE " ;
c . in . eas . eas [ 0 ] . value = data_blob_talloc ( c . in . eas . eas , " VALUE1 " , 6 ) ;
c . in . eas . eas [ 1 ] . flags = 0 ;
c . in . eas . eas [ 1 ] . name . s = " SECONDEA " ;
c . in . eas . eas [ 1 ] . value = data_blob_talloc ( c . in . eas . eas , " ValueTwo " , 8 ) ;
status = smb2_create ( tree , tree , & c ) ;
torture_assert_ntstatus_ok (
tctx , status , " Unable to create test file " ) ;
handle = c . out . file . handle ;
for ( i = 0 ; i < ARRAY_SIZE ( levels ) ; i + + ) {
struct smb2_getinfo b ;
ZERO_STRUCT ( b ) ;
b . in . info_type = SMB2_GETINFO_FILE ;
b . in . info_class = levels [ i ] . level ;
b . in . file . handle = handle ;
b . in . output_buffer_length = 65535 ;
status = smb2_getinfo ( tree , tree , & b ) ;
2013-09-26 21:21:21 -07:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_IMPLEMENTED ) ) {
continue ;
}
2013-08-27 09:41:13 +00:00
torture_assert_ntstatus_equal (
tctx , status , NT_STATUS_OK ,
" Wrong error code for large buffer " ) ;
ret = torture_smb2_buffercheck_err (
tctx , tree , & b , levels [ i ] . fixed , b . out . blob ) ;
if ( ! ret ) {
return ret ;
}
}
return true ;
}
static bool torture_smb2_qsec_buffercheck ( struct torture_context * tctx )
{
struct smb2_getinfo b ;
bool ret ;
struct smb2_tree * tree ;
struct smb2_create c ;
NTSTATUS status ;
struct smb2_handle handle ;
2016-02-22 15:51:06 +01:00
torture_comment ( tctx , " Testing SMB2_GETINFO_SECURITY buffer sizes \n " ) ;
2013-08-27 09:41:13 +00:00
ret = torture_smb2_connection ( tctx , & tree ) ;
torture_assert ( tctx , ret , " connection failed " ) ;
ZERO_STRUCT ( c ) ;
c . in . oplock_level = 0 ;
c . in . desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE |
SEC_DIR_LIST | SEC_STD_READ_CONTROL ;
c . in . file_attributes = 0 ;
c . in . create_disposition = NTCREATEX_DISP_OPEN ;
c . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_DELETE ;
c . in . create_options = NTCREATEX_OPTIONS_ASYNC_ALERT ;
c . in . fname = " " ;
status = smb2_create ( tree , tree , & c ) ;
torture_assert_ntstatus_ok (
tctx , status , " Unable to create root handle " ) ;
handle = c . out . file . handle ;
2008-05-31 13:39:51 +10:00
ZERO_STRUCT ( b ) ;
2013-08-27 09:41:13 +00:00
b . in . info_type = SMB2_GETINFO_SECURITY ;
b . in . info_class = 0 ;
b . in . file . handle = handle ;
b . in . output_buffer_length = 0 ;
2008-05-31 13:39:51 +10:00
status = smb2_getinfo ( tree , tree , & b ) ;
2013-08-27 09:41:13 +00:00
torture_assert_ntstatus_equal (
tctx , status , NT_STATUS_BUFFER_TOO_SMALL ,
" Wrong error code for large buffer " ) ;
b . in . output_buffer_length = 1 ;
status = smb2_getinfo ( tree , tree , & b ) ;
torture_assert_ntstatus_equal (
tctx , status , NT_STATUS_BUFFER_TOO_SMALL ,
" Wrong error code for large buffer " ) ;
2008-05-31 13:39:51 +10:00
return true ;
}
2005-11-17 11:06:13 +00:00
/* basic testing of all SMB2 getinfo levels
*/
2016-02-22 15:40:50 +01:00
static bool torture_smb2_getinfo ( struct torture_context * tctx )
2005-11-17 11:06:13 +00:00
{
struct smb2_tree * tree ;
2007-10-06 22:28:14 +00:00
bool ret = true ;
2005-11-18 09:51:13 +00:00
NTSTATUS status ;
2005-11-17 11:06:13 +00:00
2016-02-22 15:40:50 +01:00
ret = torture_smb2_connection ( tctx , & tree ) ;
torture_assert ( tctx , ret , " connection failed " ) ;
2005-11-17 11:06:13 +00:00
2008-05-22 14:50:36 +10:00
smb2_deltree ( tree , FNAME ) ;
smb2_deltree ( tree , DNAME ) ;
2016-02-22 15:40:50 +01:00
status = torture_setup_complex_file ( tctx , tree , FNAME ) ;
torture_assert_ntstatus_ok ( tctx , status ,
2012-02-28 14:19:49 +01:00
" setup complex file " FNAME ) ;
2016-02-22 15:40:50 +01:00
status = torture_setup_complex_file ( tctx , tree , FNAME " :streamtwo " ) ;
torture_assert_ntstatus_ok ( tctx , status ,
2012-03-06 11:48:52 +01:00
" setup complex file " FNAME " :streamtwo " ) ;
2012-02-28 14:19:49 +01:00
2016-02-22 15:40:50 +01:00
status = torture_setup_complex_dir ( tctx , tree , DNAME ) ;
torture_assert_ntstatus_ok ( tctx , status ,
2012-02-28 14:19:49 +01:00
" setup complex dir " DNAME ) ;
2016-02-22 15:40:50 +01:00
status = torture_setup_complex_file ( tctx , tree , DNAME " :streamtwo " ) ;
torture_assert_ntstatus_ok ( tctx , status ,
2012-03-06 11:48:52 +01:00
" setup complex dir " DNAME " :streamtwo " ) ;
2005-11-17 11:06:13 +00:00
2016-02-22 15:40:50 +01:00
ret & = torture_smb2_fileinfo ( tctx , tree ) ;
2005-11-17 11:06:13 +00:00
return ret ;
}
2013-08-22 11:06:59 +00:00
struct torture_suite * torture_smb2_getinfo_init ( void )
{
struct torture_suite * suite = torture_suite_create (
talloc_autofree_context ( ) , " getinfo " ) ;
torture_suite_add_simple_test ( suite , " complex " , torture_smb2_getinfo ) ;
2013-08-22 11:47:21 +00:00
torture_suite_add_simple_test ( suite , " fsinfo " , torture_smb2_fsinfo ) ;
2013-08-27 09:41:13 +00:00
torture_suite_add_simple_test ( suite , " qfs_buffercheck " ,
torture_smb2_qfs_buffercheck ) ;
torture_suite_add_simple_test ( suite , " qfile_buffercheck " ,
torture_smb2_qfile_buffercheck ) ;
torture_suite_add_simple_test ( suite , " qsec_buffercheck " ,
torture_smb2_qsec_buffercheck ) ;
2016-08-13 21:23:34 +03:00
torture_suite_add_simple_test ( suite , " granted " ,
torture_smb2_fileinfo_grant_read ) ;
2013-08-22 11:06:59 +00:00
return suite ;
}