2009-06-08 18:26:57 +04:00
/*
Unix SMB / CIFS implementation .
test suite for SMB2 compounded requests
Copyright ( C ) Stefan Metzmacher 2009
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2022-11-18 02:39:16 +03:00
# include "tevent.h"
2009-06-08 18:26:57 +04:00
# include "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
# include "torture/torture.h"
# include "torture/smb2/proto.h"
2020-05-15 21:32:18 +03:00
# include "libcli/security/security.h"
# include "librpc/gen_ndr/ndr_security.h"
2011-09-20 22:59:45 +04:00
# include "../libcli/smb/smbXcli_base.h"
2009-06-08 18:26:57 +04:00
# define CHECK_STATUS(status, correct) do { \
if ( ! NT_STATUS_EQUAL ( status , correct ) ) { \
torture_result ( tctx , TORTURE_FAIL , __location__ " : Incorrect status %s - should be %s " , \
nt_errstr ( status ) , nt_errstr ( correct ) ) ; \
ret = false ; \
goto done ; \
} } while ( 0 )
2015-05-14 05:27:54 +03:00
# define CHECK_VALUE(v, correct) do { \
if ( ( v ) ! = ( correct ) ) { \
torture_result ( tctx , TORTURE_FAIL , \
" (%s) Incorrect value %s=%d - should be %d \n " , \
__location__ , # v , ( int ) v , ( int ) correct ) ; \
ret = false ; \
} } while ( 0 )
2022-11-18 02:39:16 +03:00
# define WAIT_FOR_ASYNC_RESPONSE(req) \
while ( ! req - > cancel . can_cancel & & req - > state < = SMB2_REQUEST_RECV ) { \
if ( tevent_loop_once ( tctx - > ev ) ! = 0 ) { \
break ; \
} \
}
2013-05-03 01:36:05 +04:00
static struct {
struct smb2_handle handle ;
uint8_t level ;
struct smb2_break br ;
int count ;
int failures ;
NTSTATUS failure_status ;
} break_info ;
static void torture_oplock_break_callback ( struct smb2_request * req )
{
NTSTATUS status ;
struct smb2_break br ;
ZERO_STRUCT ( br ) ;
status = smb2_break_recv ( req , & break_info . br ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
break_info . failures + + ;
break_info . failure_status = status ;
}
return ;
}
/* A general oplock break notification handler. This should be used when a
* test expects to break from batch or exclusive to a lower level . */
static bool torture_oplock_handler ( struct smb2_transport * transport ,
const struct smb2_handle * handle ,
uint8_t level ,
void * private_data )
{
struct smb2_tree * tree = private_data ;
const char * name ;
struct smb2_request * req ;
ZERO_STRUCT ( break_info . br ) ;
break_info . handle = * handle ;
break_info . level = level ;
break_info . count + + ;
switch ( level ) {
case SMB2_OPLOCK_LEVEL_II :
name = " level II " ;
break ;
case SMB2_OPLOCK_LEVEL_NONE :
name = " none " ;
break ;
default :
name = " unknown " ;
break_info . failures + + ;
}
printf ( " Acking to %s [0x%02X] in oplock handler \n " , name , level ) ;
break_info . br . in . file . handle = * handle ;
break_info . br . in . oplock_level = level ;
break_info . br . in . reserved = 0 ;
break_info . br . in . reserved2 = 0 ;
req = smb2_break_send ( tree , & break_info . br ) ;
req - > async . fn = torture_oplock_break_callback ;
req - > async . private_data = NULL ;
return true ;
}
static bool test_compound_break ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
const char * fname1 = " some-file.pptx " ;
NTSTATUS status ;
bool ret = true ;
union smb_open io1 ;
struct smb2_create io2 ;
struct smb2_getinfo gf ;
struct smb2_request * req [ 2 ] ;
struct smb2_handle h1 ;
struct smb2_handle h ;
tree - > session - > transport - > oplock . handler = torture_oplock_handler ;
tree - > session - > transport - > oplock . private_data = tree ;
ZERO_STRUCT ( break_info ) ;
/*
base ntcreatex parms
*/
ZERO_STRUCT ( io1 . smb2 ) ;
io1 . generic . level = RAW_OPEN_SMB2 ;
io1 . smb2 . in . desired_access = ( SEC_STD_SYNCHRONIZE |
SEC_STD_READ_CONTROL |
SEC_FILE_READ_ATTRIBUTE |
SEC_FILE_READ_EA |
SEC_FILE_READ_DATA ) ;
io1 . smb2 . in . alloc_size = 0 ;
io1 . smb2 . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
io1 . smb2 . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
io1 . smb2 . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
io1 . smb2 . in . create_options = 0 ;
io1 . smb2 . in . impersonation_level = SMB2_IMPERSONATION_ANONYMOUS ;
io1 . smb2 . in . security_flags = 0 ;
io1 . smb2 . in . fname = fname1 ;
torture_comment ( tctx , " TEST2: open a file with an batch "
" oplock (share mode: all) \n " ) ;
io1 . smb2 . in . oplock_level = SMB2_OPLOCK_LEVEL_BATCH ;
status = smb2_create ( tree , tctx , & ( io1 . smb2 ) ) ;
torture_assert_ntstatus_ok ( tctx , status , " Error opening the file " ) ;
h1 = io1 . smb2 . out . file . handle ;
torture_comment ( tctx , " TEST2: Opening second time with compound \n " ) ;
ZERO_STRUCT ( io2 ) ;
io2 . in . desired_access = ( SEC_STD_SYNCHRONIZE |
SEC_FILE_READ_ATTRIBUTE |
SEC_FILE_READ_EA ) ;
io2 . in . alloc_size = 0 ;
io2 . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
io2 . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
io2 . in . create_disposition = NTCREATEX_DISP_OPEN ;
io2 . in . create_options = 0 ;
io2 . in . impersonation_level = SMB2_IMPERSONATION_ANONYMOUS ;
io2 . in . security_flags = 0 ;
io2 . in . fname = fname1 ;
io2 . in . oplock_level = 0 ;
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
req [ 0 ] = smb2_create_send ( tree , & io2 ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
h . data [ 0 ] = UINT64_MAX ;
h . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( gf ) ;
gf . in . file . handle = h ;
2019-03-29 13:08:12 +03:00
gf . in . info_type = SMB2_0_INFO_FILE ;
2013-05-03 01:36:05 +04:00
gf . in . info_class = 0x16 ;
gf . in . output_buffer_length = 0x1000 ;
2019-01-08 18:09:46 +03:00
gf . in . input_buffer = data_blob_null ;
2013-05-03 01:36:05 +04:00
req [ 1 ] = smb2_getinfo_send ( tree , & gf ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_getinfo_recv ( req [ 1 ] , tree , & gf ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
done :
smb2_util_close ( tree , h1 ) ;
smb2_util_unlink ( tree , fname1 ) ;
return ret ;
}
2009-06-08 18:26:57 +04:00
static bool test_compound_related1 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status ;
const char * fname = " compound_related1.dat " ;
struct smb2_close cl ;
bool ret = true ;
struct smb2_request * req [ 2 ] ;
2012-07-25 11:29:00 +04:00
struct smbXcli_tcon * saved_tcon = tree - > smbXcli ;
struct smbXcli_session * saved_session = tree - > session - > smbXcli ;
2009-06-08 18:26:57 +04:00
smb2_transport_credits_ask_num ( tree - > session - > transport , 2 ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
2010-04-07 21:33:02 +04:00
2012-07-25 11:29:00 +04:00
tree - > smbXcli = smbXcli_tcon_create ( tree ) ;
smb2cli_tcon_set_values ( tree - > smbXcli ,
2012-07-25 14:33:39 +04:00
NULL , /* session */
2012-07-25 11:29:00 +04:00
0xFFFFFFFF , /* tcon_id */
0 , /* type */
0 , /* flags */
0 , /* capabilities */
0 /* maximal_access */ ) ;
2019-06-11 18:42:38 +03:00
tree - > session - > smbXcli = smbXcli_session_shallow_copy ( tree - > session ,
2013-01-29 04:52:11 +04:00
tree - > session - > smbXcli ) ;
2011-09-20 22:59:45 +04:00
smb2cli_session_set_id_and_flags ( tree - > session - > smbXcli , UINT64_MAX , 0 ) ;
2010-04-07 21:33:02 +04:00
2009-06-08 18:26:57 +04:00
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2012-07-25 11:29:00 +04:00
TALLOC_FREE ( tree - > smbXcli ) ;
tree - > smbXcli = saved_tcon ;
TALLOC_FREE ( tree - > session - > smbXcli ) ;
tree - > session - > smbXcli = saved_session ;
2010-04-07 21:33:02 +04:00
2009-06-08 18:26:57 +04:00
smb2_util_unlink ( tree , fname ) ;
done :
return ret ;
}
static bool test_compound_related2 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status ;
const char * fname = " compound_related2.dat " ;
struct smb2_close cl ;
bool ret = true ;
struct smb2_request * req [ 5 ] ;
2012-07-25 11:29:00 +04:00
struct smbXcli_tcon * saved_tcon = tree - > smbXcli ;
struct smbXcli_session * saved_session = tree - > session - > smbXcli ;
2009-06-08 18:26:57 +04:00
smb2_transport_credits_ask_num ( tree - > session - > transport , 5 ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
smb2_transport_compound_start ( tree - > session - > transport , 5 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
2012-07-25 11:29:00 +04:00
tree - > smbXcli = smbXcli_tcon_create ( tree ) ;
smb2cli_tcon_set_values ( tree - > smbXcli ,
2012-07-25 14:33:39 +04:00
NULL , /* session */
2012-07-25 11:29:00 +04:00
0xFFFFFFFF , /* tcon_id */
0 , /* type */
0 , /* flags */
0 , /* capabilities */
0 /* maximal_access */ ) ;
2019-06-11 18:42:38 +03:00
tree - > session - > smbXcli = smbXcli_session_shallow_copy ( tree - > session ,
2013-01-29 04:52:11 +04:00
tree - > session - > smbXcli ) ;
2011-09-20 22:59:45 +04:00
smb2cli_session_set_id_and_flags ( tree - > session - > smbXcli , UINT64_MAX , 0 ) ;
2010-04-07 21:33:02 +04:00
2009-06-08 18:26:57 +04:00
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
req [ 3 ] = smb2_close_send ( tree , & cl ) ;
req [ 4 ] = smb2_close_send ( tree , & cl ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
status = smb2_close_recv ( req [ 3 ] , & cl ) ;
2012-09-20 02:35:52 +04:00
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
2009-06-08 18:26:57 +04:00
status = smb2_close_recv ( req [ 4 ] , & cl ) ;
2012-09-20 02:35:52 +04:00
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
2009-06-08 18:26:57 +04:00
2012-07-25 11:29:00 +04:00
TALLOC_FREE ( tree - > smbXcli ) ;
tree - > smbXcli = saved_tcon ;
TALLOC_FREE ( tree - > session - > smbXcli ) ;
tree - > session - > smbXcli = saved_session ;
2010-04-07 21:33:02 +04:00
2009-06-08 18:26:57 +04:00
smb2_util_unlink ( tree , fname ) ;
done :
return ret ;
}
2012-08-26 23:22:02 +04:00
static bool test_compound_related3 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_ioctl io ;
struct smb2_create cr ;
struct smb2_close cl ;
const char * fname = " compound_related3.dat " ;
struct smb2_request * req [ 3 ] ;
NTSTATUS status ;
bool ret = false ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
smb2_transport_compound_start ( tree - > session - > transport , 3 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( io ) ;
io . in . function = FSCTL_CREATE_OR_GET_OBJECT_ID ;
io . in . file . handle = hd ;
2019-01-08 17:52:35 +03:00
io . in . reserved2 = 0 ;
io . in . max_output_response = 64 ;
2012-08-26 23:22:02 +04:00
io . in . flags = 1 ;
req [ 1 ] = smb2_ioctl_send ( tree , & io ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_ioctl_recv ( req [ 1 ] , tree , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
ret = true ;
done :
return ret ;
}
2020-05-15 21:32:18 +03:00
static bool test_compound_related4 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
const char * fname = " compound_related4.dat " ;
struct security_descriptor * sd = NULL ;
struct smb2_handle hd ;
struct smb2_create cr ;
union smb_setfileinfo set ;
struct smb2_ioctl io ;
struct smb2_close cl ;
struct smb2_request * req [ 4 ] ;
NTSTATUS status ;
bool ret = true ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( cr ) ;
cr . level = RAW_OPEN_SMB2 ;
cr . in . create_flags = 0 ;
cr . in . desired_access = SEC_STD_READ_CONTROL |
SEC_STD_WRITE_DAC |
SEC_STD_WRITE_OWNER ;
cr . in . create_options = 0 ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
cr . in . alloc_size = 0 ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS ;
cr . in . security_flags = 0 ;
cr . in . fname = fname ;
status = smb2_create ( tree , tctx , & cr ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_create failed \n " ) ;
hd = cr . out . file . handle ;
torture_comment ( tctx , " set a sec desc allowing no write by CREATOR_OWNER \n " ) ;
sd = security_descriptor_dacl_create ( tctx ,
0 , NULL , NULL ,
SID_CREATOR_OWNER ,
SEC_ACE_TYPE_ACCESS_ALLOWED ,
SEC_RIGHTS_FILE_READ | SEC_STD_ALL ,
0 ,
NULL ) ;
torture_assert_not_null_goto ( tctx , sd , ret , done ,
" security_descriptor_dacl_create failed \n " ) ;
set . set_secdesc . level = RAW_SFILEINFO_SEC_DESC ;
set . set_secdesc . in . file . handle = hd ;
set . set_secdesc . in . secinfo_flags = SECINFO_DACL ;
set . set_secdesc . in . sd = sd ;
status = smb2_setinfo_file ( tree , & set ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_setinfo_file failed \n " ) ;
torture_comment ( tctx , " try open for write \n " ) ;
cr . in . desired_access = SEC_FILE_WRITE_DATA ;
smb2_transport_compound_start ( tree - > session - > transport , 4 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_create_send failed \n " ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( io ) ;
io . in . function = FSCTL_CREATE_OR_GET_OBJECT_ID ;
io . in . file . handle = hd ;
io . in . flags = 1 ;
req [ 1 ] = smb2_ioctl_send ( tree , & io ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_ioctl_send failed \n " ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
torture_assert_not_null_goto ( tctx , req [ 2 ] , ret , done ,
" smb2_create_send failed \n " ) ;
set . set_secdesc . in . file . handle = hd ;
req [ 3 ] = smb2_setinfo_file_send ( tree , & set ) ;
torture_assert_not_null_goto ( tctx , req [ 3 ] , ret , done ,
" smb2_create_send failed \n " ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_create_recv failed \n " ) ;
status = smb2_ioctl_recv ( req [ 1 ] , tree , & io ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_ioctl_recv failed \n " ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_close_recv failed \n " ) ;
status = smb2_setinfo_recv ( req [ 3 ] ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_setinfo_recv failed \n " ) ;
done :
smb2_util_unlink ( tree , fname ) ;
smb2_tdis ( tree ) ;
smb2_logoff ( tree - > session ) ;
return ret ;
}
static bool test_compound_related5 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_ioctl io ;
struct smb2_close cl ;
struct smb2_request * req [ 2 ] ;
NTSTATUS status ;
bool ret = false ;
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( io ) ;
io . in . function = FSCTL_CREATE_OR_GET_OBJECT_ID ;
io . in . file . handle = hd ;
io . in . flags = 1 ;
req [ 0 ] = smb2_ioctl_send ( tree , & io ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_ioctl_send failed \n " ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_create_send failed \n " ) ;
status = smb2_ioctl_recv ( req [ 0 ] , tree , & io ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_FILE_CLOSED ,
ret , done ,
" smb2_ioctl_recv failed \n " ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_FILE_CLOSED ,
ret , done ,
" smb2_close_recv failed \n " ) ;
ret = true ;
done :
smb2_tdis ( tree ) ;
smb2_logoff ( tree - > session ) ;
return ret ;
}
2020-05-18 17:50:05 +03:00
static bool test_compound_related6 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
struct smb2_read rd ;
struct smb2_write wr ;
struct smb2_close cl ;
NTSTATUS status ;
const char * fname = " compound_related6.dat " ;
struct smb2_request * req [ 5 ] ;
uint8_t buf [ 64 ] ;
bool ret = true ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( cr ) ;
cr . level = RAW_OPEN_SMB2 ;
cr . in . create_flags = 0 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . create_options = 0 ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
cr . in . alloc_size = 0 ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS ;
cr . in . security_flags = 0 ;
cr . in . fname = fname ;
status = smb2_create ( tree , tctx , & cr ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_create failed \n " ) ;
hd = cr . out . file . handle ;
ZERO_STRUCT ( buf ) ;
status = smb2_util_write ( tree , hd , buf , 0 , ARRAY_SIZE ( buf ) ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_util_write failed \n " ) ;
torture_comment ( tctx , " try open for read \n " ) ;
cr . in . desired_access = SEC_FILE_READ_DATA ;
smb2_transport_compound_start ( tree - > session - > transport , 5 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_create_send failed \n " ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( rd ) ;
rd . in . file . handle = hd ;
rd . in . length = 1 ;
rd . in . offset = 0 ;
req [ 1 ] = smb2_read_send ( tree , & rd ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_read_send failed \n " ) ;
ZERO_STRUCT ( wr ) ;
wr . in . file . handle = hd ;
wr . in . offset = 0 ;
wr . in . data = data_blob_talloc ( tctx , NULL , 64 ) ;
req [ 2 ] = smb2_write_send ( tree , & wr ) ;
torture_assert_not_null_goto ( tctx , req [ 2 ] , ret , done ,
" smb2_write_send failed \n " ) ;
ZERO_STRUCT ( rd ) ;
rd . in . file . handle = hd ;
rd . in . length = 1 ;
rd . in . offset = 0 ;
req [ 3 ] = smb2_read_send ( tree , & rd ) ;
torture_assert_not_null_goto ( tctx , req [ 3 ] , ret , done ,
" smb2_read_send failed \n " ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 4 ] = smb2_close_send ( tree , & cl ) ;
torture_assert_not_null_goto ( tctx , req [ 4 ] , ret , done ,
" smb2_close_send failed \n " ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_create_recv failed \n " ) ;
status = smb2_read_recv ( req [ 1 ] , tree , & rd ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_read_recv failed \n " ) ;
status = smb2_write_recv ( req [ 2 ] , & wr ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_write_recv failed \n " ) ;
status = smb2_read_recv ( req [ 3 ] , tree , & rd ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_read_recv failed \n " ) ;
status = smb2_close_recv ( req [ 4 ] , & cl ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_close_recv failed \n " ) ;
done :
smb2_util_unlink ( tree , fname ) ;
smb2_tdis ( tree ) ;
smb2_logoff ( tree - > session ) ;
return ret ;
}
2020-07-15 07:44:52 +03:00
static bool test_compound_related7 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
const char * fname = " compound_related4.dat " ;
struct security_descriptor * sd = NULL ;
struct smb2_handle hd ;
struct smb2_create cr ;
union smb_setfileinfo set ;
struct smb2_notify nt ;
struct smb2_close cl ;
NTSTATUS status ;
struct smb2_request * req [ 4 ] ;
bool ret = true ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( cr ) ;
cr . level = RAW_OPEN_SMB2 ;
cr . in . create_flags = 0 ;
cr . in . desired_access = SEC_STD_READ_CONTROL |
SEC_STD_WRITE_DAC |
SEC_STD_WRITE_OWNER ;
cr . in . create_options = 0 ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
cr . in . alloc_size = 0 ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS ;
cr . in . security_flags = 0 ;
cr . in . fname = fname ;
status = smb2_create ( tree , tctx , & cr ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_create failed \n " ) ;
hd = cr . out . file . handle ;
torture_comment ( tctx , " set a sec desc allowing no write by CREATOR_OWNER \n " ) ;
sd = security_descriptor_dacl_create ( tctx ,
0 , NULL , NULL ,
SID_CREATOR_OWNER ,
SEC_ACE_TYPE_ACCESS_ALLOWED ,
SEC_RIGHTS_FILE_READ | SEC_STD_ALL ,
0 ,
NULL ) ;
torture_assert_not_null_goto ( tctx , sd , ret , done ,
" security_descriptor_dacl_create failed \n " ) ;
set . set_secdesc . level = RAW_SFILEINFO_SEC_DESC ;
set . set_secdesc . in . file . handle = hd ;
set . set_secdesc . in . secinfo_flags = SECINFO_DACL ;
set . set_secdesc . in . sd = sd ;
status = smb2_setinfo_file ( tree , & set ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_setinfo_file failed \n " ) ;
torture_comment ( tctx , " try open for write \n " ) ;
cr . in . desired_access = SEC_FILE_WRITE_DATA ;
smb2_transport_compound_start ( tree - > session - > transport , 4 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_create_send failed \n " ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( nt ) ;
nt . in . recursive = true ;
nt . in . buffer_size = 0x1000 ;
nt . in . file . handle = hd ;
nt . in . completion_filter = FILE_NOTIFY_CHANGE_NAME ;
nt . in . unknown = 0x00000000 ;
req [ 1 ] = smb2_notify_send ( tree , & nt ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_notify_send failed \n " ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
torture_assert_not_null_goto ( tctx , req [ 2 ] , ret , done ,
" smb2_close_send failed \n " ) ;
set . set_secdesc . in . file . handle = hd ;
req [ 3 ] = smb2_setinfo_file_send ( tree , & set ) ;
torture_assert_not_null_goto ( tctx , req [ 3 ] , ret , done ,
" smb2_setinfo_file_send failed \n " ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_create_recv failed \n " ) ;
status = smb2_notify_recv ( req [ 1 ] , tree , & nt ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_notify_recv failed \n " ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_close_recv failed \n " ) ;
status = smb2_setinfo_recv ( req [ 3 ] ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_ACCESS_DENIED ,
ret , done ,
" smb2_setinfo_recv failed \n " ) ;
done :
smb2_util_unlink ( tree , fname ) ;
smb2_tdis ( tree ) ;
smb2_logoff ( tree - > session ) ;
return ret ;
}
2021-04-08 13:14:19 +03:00
static bool test_compound_related8 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
const char * fname = " compound_related8.dat " ;
const char * fname_nonexisting = " compound_related8.dat.void " ;
struct security_descriptor * sd = NULL ;
struct smb2_handle hd ;
struct smb2_create cr ;
union smb_setfileinfo set ;
struct smb2_notify nt ;
struct smb2_close cl ;
NTSTATUS status ;
struct smb2_request * req [ 4 ] ;
bool ret = true ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( cr ) ;
cr . level = RAW_OPEN_SMB2 ;
cr . in . create_flags = 0 ;
cr . in . desired_access = SEC_STD_READ_CONTROL |
SEC_STD_WRITE_DAC |
SEC_STD_WRITE_OWNER ;
cr . in . create_options = 0 ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
cr . in . alloc_size = 0 ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS ;
cr . in . security_flags = 0 ;
cr . in . fname = fname ;
status = smb2_create ( tree , tctx , & cr ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_create failed \n " ) ;
hd = cr . out . file . handle ;
smb2_transport_compound_start ( tree - > session - > transport , 4 ) ;
torture_comment ( tctx , " try open for write \n " ) ;
cr . in . fname = fname_nonexisting ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_create_send failed \n " ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( nt ) ;
nt . in . recursive = true ;
nt . in . buffer_size = 0x1000 ;
nt . in . file . handle = hd ;
nt . in . completion_filter = FILE_NOTIFY_CHANGE_NAME ;
nt . in . unknown = 0x00000000 ;
req [ 1 ] = smb2_notify_send ( tree , & nt ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_notify_send failed \n " ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
torture_assert_not_null_goto ( tctx , req [ 2 ] , ret , done ,
" smb2_close_send failed \n " ) ;
sd = security_descriptor_dacl_create ( tctx ,
0 , NULL , NULL ,
SID_CREATOR_OWNER ,
SEC_ACE_TYPE_ACCESS_ALLOWED ,
SEC_RIGHTS_FILE_READ | SEC_STD_ALL ,
0 ,
NULL ) ;
torture_assert_not_null_goto ( tctx , sd , ret , done ,
" security_descriptor_dacl_create failed \n " ) ;
set . set_secdesc . level = RAW_SFILEINFO_SEC_DESC ;
set . set_secdesc . in . file . handle = hd ;
set . set_secdesc . in . secinfo_flags = SECINFO_DACL ;
set . set_secdesc . in . sd = sd ;
req [ 3 ] = smb2_setinfo_file_send ( tree , & set ) ;
torture_assert_not_null_goto ( tctx , req [ 3 ] , ret , done ,
" smb2_setinfo_file_send failed \n " ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_OBJECT_NAME_NOT_FOUND ,
ret , done ,
" smb2_create_recv failed \n " ) ;
status = smb2_notify_recv ( req [ 1 ] , tree , & nt ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_OBJECT_NAME_NOT_FOUND ,
ret , done ,
" smb2_notify_recv failed \n " ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_OBJECT_NAME_NOT_FOUND ,
ret , done ,
" smb2_close_recv failed \n " ) ;
status = smb2_setinfo_recv ( req [ 3 ] ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_OBJECT_NAME_NOT_FOUND ,
ret , done ,
" smb2_setinfo_recv failed \n " ) ;
done :
smb2_util_unlink ( tree , fname ) ;
smb2_tdis ( tree ) ;
smb2_logoff ( tree - > session ) ;
return ret ;
}
2021-04-08 13:25:22 +03:00
static bool test_compound_related9 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
const char * fname = " compound_related9.dat " ;
struct security_descriptor * sd = NULL ;
struct smb2_handle hd ;
struct smb2_create cr ;
union smb_setfileinfo set ;
struct smb2_notify nt ;
struct smb2_close cl ;
NTSTATUS status ;
struct smb2_request * req [ 3 ] ;
bool ret = true ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( cr ) ;
cr . level = RAW_OPEN_SMB2 ;
cr . in . create_flags = 0 ;
cr . in . desired_access = SEC_STD_READ_CONTROL |
SEC_STD_WRITE_DAC |
SEC_STD_WRITE_OWNER ;
cr . in . create_options = 0 ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
cr . in . alloc_size = 0 ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS ;
cr . in . security_flags = 0 ;
cr . in . fname = fname ;
status = smb2_create ( tree , tctx , & cr ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_create failed \n " ) ;
hd = cr . out . file . handle ;
smb2_transport_compound_start ( tree - > session - > transport , 3 ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( nt ) ;
nt . in . recursive = true ;
nt . in . buffer_size = 0x1000 ;
nt . in . completion_filter = FILE_NOTIFY_CHANGE_NAME ;
req [ 0 ] = smb2_notify_send ( tree , & nt ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_notify_send failed \n " ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_close_send failed \n " ) ;
sd = security_descriptor_dacl_create ( tctx ,
0 , NULL , NULL ,
SID_CREATOR_OWNER ,
SEC_ACE_TYPE_ACCESS_ALLOWED ,
SEC_RIGHTS_FILE_READ | SEC_STD_ALL ,
0 ,
NULL ) ;
torture_assert_not_null_goto ( tctx , sd , ret , done ,
" security_descriptor_dacl_create failed \n " ) ;
set . set_secdesc . level = RAW_SFILEINFO_SEC_DESC ;
set . set_secdesc . in . file . handle = hd ;
set . set_secdesc . in . secinfo_flags = SECINFO_DACL ;
set . set_secdesc . in . sd = sd ;
req [ 2 ] = smb2_setinfo_file_send ( tree , & set ) ;
torture_assert_not_null_goto ( tctx , req [ 2 ] , ret , done ,
" smb2_setinfo_file_send failed \n " ) ;
status = smb2_notify_recv ( req [ 0 ] , tree , & nt ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_INVALID_PARAMETER ,
ret , done ,
" smb2_notify_recv failed \n " ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_INVALID_PARAMETER ,
ret , done ,
" smb2_close_recv failed \n " ) ;
status = smb2_setinfo_recv ( req [ 2 ] ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , NT_STATUS_INVALID_PARAMETER ,
ret , done ,
" smb2_setinfo_recv failed \n " ) ;
done :
smb2_util_unlink ( tree , fname ) ;
smb2_tdis ( tree ) ;
smb2_logoff ( tree - > session ) ;
return ret ;
}
2015-05-14 05:27:54 +03:00
static bool test_compound_padding ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle h ;
struct smb2_create cr ;
struct smb2_read r ;
2022-11-19 00:23:48 +03:00
struct smb2_read r2 ;
2015-05-14 05:27:54 +03:00
const char * fname = " compound_read.dat " ;
const char * sname = " compound_read.dat:foo " ;
struct smb2_request * req [ 3 ] ;
NTSTATUS status ;
bool ret = false ;
smb2_util_unlink ( tree , fname ) ;
/* Write file */
ZERO_STRUCT ( cr ) ;
cr . in . desired_access = SEC_FILE_WRITE_DATA ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . create_disposition = NTCREATEX_DISP_CREATE ;
cr . in . impersonation_level = SMB2_IMPERSONATION_ANONYMOUS ;
cr . in . fname = fname ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
status = smb2_create ( tree , tctx , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h = cr . out . file . handle ;
status = smb2_util_write ( tree , h , " 123 " , 0 , 3 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
smb2_util_close ( tree , h ) ;
/* Write stream */
ZERO_STRUCT ( cr ) ;
cr . in . desired_access = SEC_FILE_WRITE_DATA ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . create_disposition = NTCREATEX_DISP_CREATE ;
cr . in . impersonation_level = SMB2_IMPERSONATION_ANONYMOUS ;
cr . in . fname = sname ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
status = smb2_create ( tree , tctx , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h = cr . out . file . handle ;
status = smb2_util_write ( tree , h , " 456 " , 0 , 3 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
smb2_util_close ( tree , h ) ;
/* Check compound read from basefile */
2022-11-19 00:23:48 +03:00
smb2_transport_compound_start ( tree - > session - > transport , 3 ) ;
2015-05-14 05:27:54 +03:00
ZERO_STRUCT ( cr ) ;
cr . in . impersonation_level = SMB2_IMPERSONATION_ANONYMOUS ;
cr . in . desired_access = SEC_FILE_READ_DATA ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN ;
cr . in . fname = fname ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
2022-11-19 00:23:48 +03:00
/*
* We send 2 reads in the compound here as the protocol
* allows the last read to be split off and possibly
* go async . Check the padding on the first read returned ,
* not the second as the second may not be part of the
* returned compound .
*/
2015-05-14 05:27:54 +03:00
ZERO_STRUCT ( r ) ;
h . data [ 0 ] = UINT64_MAX ;
h . data [ 1 ] = UINT64_MAX ;
r . in . file . handle = h ;
r . in . length = 3 ;
r . in . offset = 0 ;
r . in . min_count = 1 ;
req [ 1 ] = smb2_read_send ( tree , & r ) ;
2022-11-19 00:23:48 +03:00
ZERO_STRUCT ( r2 ) ;
h . data [ 0 ] = UINT64_MAX ;
h . data [ 1 ] = UINT64_MAX ;
r2 . in . file . handle = h ;
r2 . in . length = 3 ;
r2 . in . offset = 0 ;
r2 . in . min_count = 1 ;
req [ 2 ] = smb2_read_send ( tree , & r2 ) ;
2015-05-14 05:27:54 +03:00
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/*
* We must do a manual smb2_request_receive ( ) in order to be
* able to check the transport layer info , as smb2_read_recv ( )
* will destroy the req . smb2_read_recv ( ) will call
* smb2_request_receive ( ) again , but that ' s ok .
*/
if ( ! smb2_request_receive ( req [ 1 ] ) | |
! smb2_request_is_ok ( req [ 1 ] ) ) {
torture_fail ( tctx , " failed to receive read request " ) ;
}
/*
* size must be 24 : 16 byte read response header plus 3
* requested bytes padded to an 8 byte boundary .
*/
CHECK_VALUE ( req [ 1 ] - > in . body_size , 24 ) ;
status = smb2_read_recv ( req [ 1 ] , tree , & r ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2022-11-19 00:23:48 +03:00
/* Pick up the second, possibly async, read. */
status = smb2_read_recv ( req [ 2 ] , tree , & r2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2015-05-14 05:27:54 +03:00
smb2_util_close ( tree , cr . out . file . handle ) ;
/* Check compound read from stream */
2022-11-19 00:30:05 +03:00
smb2_transport_compound_start ( tree - > session - > transport , 3 ) ;
2015-05-14 05:27:54 +03:00
ZERO_STRUCT ( cr ) ;
cr . in . impersonation_level = SMB2_IMPERSONATION_ANONYMOUS ;
cr . in . desired_access = SEC_FILE_READ_DATA ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN ;
cr . in . fname = sname ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
2022-11-19 00:30:05 +03:00
/*
* We send 2 reads in the compound here as the protocol
* allows the last read to be split off and possibly
* go async . Check the padding on the first read returned ,
* not the second as the second may not be part of the
* returned compound .
*/
2015-05-14 05:27:54 +03:00
ZERO_STRUCT ( r ) ;
h . data [ 0 ] = UINT64_MAX ;
h . data [ 1 ] = UINT64_MAX ;
r . in . file . handle = h ;
r . in . length = 3 ;
r . in . offset = 0 ;
r . in . min_count = 1 ;
req [ 1 ] = smb2_read_send ( tree , & r ) ;
2022-11-19 00:30:05 +03:00
ZERO_STRUCT ( r2 ) ;
h . data [ 0 ] = UINT64_MAX ;
h . data [ 1 ] = UINT64_MAX ;
r2 . in . file . handle = h ;
r2 . in . length = 3 ;
r2 . in . offset = 0 ;
r2 . in . min_count = 1 ;
req [ 2 ] = smb2_read_send ( tree , & r2 ) ;
2015-05-14 05:27:54 +03:00
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/*
* We must do a manual smb2_request_receive ( ) in order to be
* able to check the transport layer info , as smb2_read_recv ( )
* will destroy the req . smb2_read_recv ( ) will call
* smb2_request_receive ( ) again , but that ' s ok .
*/
if ( ! smb2_request_receive ( req [ 1 ] ) | |
! smb2_request_is_ok ( req [ 1 ] ) ) {
torture_fail ( tctx , " failed to receive read request " ) ;
}
/*
* size must be 24 : 16 byte read response header plus 3
* requested bytes padded to an 8 byte boundary .
*/
CHECK_VALUE ( req [ 1 ] - > in . body_size , 24 ) ;
status = smb2_read_recv ( req [ 1 ] , tree , & r ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2022-11-19 00:30:05 +03:00
/* Pick up the second, possibly async, read. */
status = smb2_read_recv ( req [ 2 ] , tree , & r2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2015-05-14 05:27:54 +03:00
h = cr . out . file . handle ;
/* Check 2 compound (unrelateated) reads from existing stream handle */
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( r ) ;
r . in . file . handle = h ;
r . in . length = 3 ;
r . in . offset = 0 ;
r . in . min_count = 1 ;
req [ 0 ] = smb2_read_send ( tree , & r ) ;
req [ 1 ] = smb2_read_send ( tree , & r ) ;
/*
* We must do a manual smb2_request_receive ( ) in order to be
* able to check the transport layer info , as smb2_read_recv ( )
* will destroy the req . smb2_read_recv ( ) will call
* smb2_request_receive ( ) again , but that ' s ok .
*/
if ( ! smb2_request_receive ( req [ 0 ] ) | |
! smb2_request_is_ok ( req [ 0 ] ) ) {
torture_fail ( tctx , " failed to receive read request " ) ;
}
if ( ! smb2_request_receive ( req [ 1 ] ) | |
! smb2_request_is_ok ( req [ 1 ] ) ) {
torture_fail ( tctx , " failed to receive read request " ) ;
}
/*
* size must be 24 : 16 byte read response header plus 3
* requested bytes padded to an 8 byte boundary .
*/
CHECK_VALUE ( req [ 0 ] - > in . body_size , 24 ) ;
CHECK_VALUE ( req [ 1 ] - > in . body_size , 24 ) ;
status = smb2_read_recv ( req [ 0 ] , tree , & r ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_read_recv ( req [ 1 ] , tree , & r ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/*
* now try a single read from the stream and verify there ' s no padding
*/
ZERO_STRUCT ( r ) ;
r . in . file . handle = h ;
r . in . length = 3 ;
r . in . offset = 0 ;
r . in . min_count = 1 ;
req [ 0 ] = smb2_read_send ( tree , & r ) ;
/*
* We must do a manual smb2_request_receive ( ) in order to be
* able to check the transport layer info , as smb2_read_recv ( )
* will destroy the req . smb2_read_recv ( ) will call
* smb2_request_receive ( ) again , but that ' s ok .
*/
if ( ! smb2_request_receive ( req [ 0 ] ) | |
! smb2_request_is_ok ( req [ 0 ] ) ) {
torture_fail ( tctx , " failed to receive read request " ) ;
}
/*
* size must be 19 : 16 byte read response header plus 3
* requested bytes without padding .
*/
CHECK_VALUE ( req [ 0 ] - > in . body_size , 19 ) ;
status = smb2_read_recv ( req [ 0 ] , tree , & r ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
smb2_util_close ( tree , h ) ;
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
ret = true ;
done :
return ret ;
}
2017-09-21 02:07:50 +03:00
static bool test_compound_create_write_close ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle handle = { . data = { UINT64_MAX , UINT64_MAX } } ;
struct smb2_create create ;
struct smb2_write write ;
struct smb2_close close ;
const char * fname = " compound_create_write_close.dat " ;
struct smb2_request * req [ 3 ] ;
NTSTATUS status ;
bool ret = false ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( create ) ;
create . in . security_flags = 0x00 ;
create . in . oplock_level = 0 ;
create . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
create . in . create_flags = 0x00000000 ;
create . in . reserved = 0x00000000 ;
create . in . desired_access = SEC_RIGHTS_FILE_ALL ;
create . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
create . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
create . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
create . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
create . in . fname = fname ;
smb2_transport_compound_start ( tree - > session - > transport , 3 ) ;
req [ 0 ] = smb2_create_send ( tree , & create ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( write ) ;
write . in . file . handle = handle ;
write . in . offset = 0 ;
write . in . data = data_blob_talloc ( tctx , NULL , 1024 ) ;
req [ 1 ] = smb2_write_send ( tree , & write ) ;
ZERO_STRUCT ( close ) ;
close . in . file . handle = handle ;
req [ 2 ] = smb2_close_send ( tree , & close ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & create ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" CREATE failed. " ) ;
status = smb2_write_recv ( req [ 1 ] , & write ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" WRITE failed. " ) ;
status = smb2_close_recv ( req [ 2 ] , & close ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" CLOSE failed. " ) ;
status = smb2_util_unlink ( tree , fname ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" File deletion failed. " ) ;
ret = true ;
done :
return ret ;
}
2009-06-08 18:26:57 +04:00
static bool test_compound_unrelated1 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status ;
const char * fname = " compound_unrelated1.dat " ;
struct smb2_close cl ;
bool ret = true ;
struct smb2_request * req [ 5 ] ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 5 ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
smb2_transport_compound_start ( tree - > session - > transport , 5 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
req [ 3 ] = smb2_close_send ( tree , & cl ) ;
req [ 4 ] = smb2_close_send ( tree , & cl ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
status = smb2_close_recv ( req [ 3 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
status = smb2_close_recv ( req [ 4 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
smb2_util_unlink ( tree , fname ) ;
done :
return ret ;
}
2009-06-09 20:13:53 +04:00
static bool test_compound_invalid1 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status ;
const char * fname = " compound_invalid1.dat " ;
struct smb2_close cl ;
bool ret = true ;
2012-09-22 00:20:20 +04:00
struct smb2_request * req [ 3 ] ;
2009-06-09 20:13:53 +04:00
2012-09-22 00:20:20 +04:00
smb2_transport_credits_ask_num ( tree - > session - > transport , 3 ) ;
2009-06-09 20:13:53 +04:00
smb2_util_unlink ( tree , fname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
2012-09-22 00:20:20 +04:00
smb2_transport_compound_start ( tree - > session - > transport , 3 ) ;
2009-06-09 20:13:53 +04:00
/* passing the first request with the related flag is invalid */
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
2012-09-22 00:20:20 +04:00
smb2_transport_compound_set_related ( tree - > session - > transport , false ) ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
2009-06-09 20:13:53 +04:00
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
/* TODO: check why this fails with --signing=required */
CHECK_STATUS ( status , NT_STATUS_INVALID_PARAMETER ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_INVALID_PARAMETER ) ;
2012-09-22 00:20:20 +04:00
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
2009-06-09 20:13:53 +04:00
smb2_util_unlink ( tree , fname ) ;
done :
return ret ;
}
static bool test_compound_invalid2 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status ;
const char * fname = " compound_invalid2.dat " ;
struct smb2_close cl ;
bool ret = true ;
struct smb2_request * req [ 5 ] ;
2012-07-25 11:29:00 +04:00
struct smbXcli_tcon * saved_tcon = tree - > smbXcli ;
struct smbXcli_session * saved_session = tree - > session - > smbXcli ;
2009-06-09 20:13:53 +04:00
smb2_transport_credits_ask_num ( tree - > session - > transport , 5 ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
smb2_transport_compound_start ( tree - > session - > transport , 5 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
2012-07-25 11:29:00 +04:00
tree - > smbXcli = smbXcli_tcon_create ( tree ) ;
smb2cli_tcon_set_values ( tree - > smbXcli ,
2012-07-25 14:33:39 +04:00
NULL , /* session */
2012-07-25 11:29:00 +04:00
0xFFFFFFFF , /* tcon_id */
0 , /* type */
0 , /* flags */
0 , /* capabilities */
0 /* maximal_access */ ) ;
2019-06-11 18:42:38 +03:00
tree - > session - > smbXcli = smbXcli_session_shallow_copy ( tree - > session ,
2013-01-29 04:52:11 +04:00
tree - > session - > smbXcli ) ;
2011-09-20 22:59:45 +04:00
smb2cli_session_set_id_and_flags ( tree - > session - > smbXcli , UINT64_MAX , 0 ) ;
2010-04-07 21:33:02 +04:00
2009-06-09 20:13:53 +04:00
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
/* strange that this is not generating invalid parameter */
smb2_transport_compound_set_related ( tree - > session - > transport , false ) ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
req [ 3 ] = smb2_close_send ( tree , & cl ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
req [ 4 ] = smb2_close_send ( tree , & cl ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
2011-10-27 23:41:11 +04:00
CHECK_STATUS ( status , NT_STATUS_USER_SESSION_DELETED ) ;
2009-06-09 20:13:53 +04:00
status = smb2_close_recv ( req [ 3 ] , & cl ) ;
2011-10-27 23:41:11 +04:00
CHECK_STATUS ( status , NT_STATUS_USER_SESSION_DELETED ) ;
2009-06-09 20:13:53 +04:00
status = smb2_close_recv ( req [ 4 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_INVALID_PARAMETER ) ;
2012-07-25 11:29:00 +04:00
TALLOC_FREE ( tree - > smbXcli ) ;
tree - > smbXcli = saved_tcon ;
TALLOC_FREE ( tree - > session - > smbXcli ) ;
tree - > session - > smbXcli = saved_session ;
2010-04-07 21:33:02 +04:00
2009-06-09 20:13:53 +04:00
smb2_util_unlink ( tree , fname ) ;
done :
return ret ;
}
static bool test_compound_invalid3 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status ;
const char * fname = " compound_invalid3.dat " ;
struct smb2_close cl ;
bool ret = true ;
struct smb2_request * req [ 5 ] ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 5 ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
smb2_transport_compound_start ( tree - > session - > transport , 5 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = hd ;
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
req [ 2 ] = smb2_close_send ( tree , & cl ) ;
/* flipping the related flag is invalid */
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
req [ 3 ] = smb2_close_send ( tree , & cl ) ;
req [ 4 ] = smb2_close_send ( tree , & cl ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
status = smb2_close_recv ( req [ 2 ] , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
status = smb2_close_recv ( req [ 3 ] , & cl ) ;
2012-09-20 02:36:29 +04:00
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
2009-06-09 20:13:53 +04:00
status = smb2_close_recv ( req [ 4 ] , & cl ) ;
2012-09-20 02:36:29 +04:00
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
2009-06-09 20:13:53 +04:00
smb2_util_unlink ( tree , fname ) ;
done :
return ret ;
}
2018-04-11 16:11:10 +03:00
static bool test_compound_invalid4 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_create cr ;
struct smb2_read rd ;
NTSTATUS status ;
const char * fname = " compound_invalid4.dat " ;
struct smb2_close cl ;
bool ret = true ;
bool ok ;
struct smb2_request * req [ 2 ] ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 2 ) ;
smb2_util_unlink ( tree , fname ) ;
ZERO_STRUCT ( cr ) ;
cr . in . security_flags = 0x00 ;
cr . in . oplock_level = 0 ;
cr . in . impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION ;
cr . in . create_flags = 0x00000000 ;
cr . in . reserved = 0x00000000 ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_OPEN_IF ;
cr . in . create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
NTCREATEX_OPTIONS_ASYNC_ALERT |
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
0x00200000 ;
cr . in . fname = fname ;
status = smb2_create ( tree , tctx , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( rd ) ;
rd . in . file . handle = cr . out . file . handle ;
rd . in . length = 1 ;
rd . in . offset = 0 ;
req [ 0 ] = smb2_read_send ( tree , & rd ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
/*
* Send a completely bogus request as second compound
* element . This triggers smbd_smb2_request_error ( ) in in
* smbd_smb2_request_dispatch ( ) before calling
* smbd_smb2_request_dispatch_update_counts ( ) .
*/
req [ 1 ] = smb2_request_init_tree ( tree , 0xff , 0x04 , false , 0 ) ;
smb2_transport_send ( req [ 1 ] ) ;
status = smb2_read_recv ( req [ 0 ] , tctx , & rd ) ;
CHECK_STATUS ( status , NT_STATUS_END_OF_FILE ) ;
ok = smb2_request_receive ( req [ 1 ] ) ;
torture_assert ( tctx , ok , " Invalid request failed \n " ) ;
CHECK_STATUS ( req [ 1 ] - > status , NT_STATUS_INVALID_PARAMETER ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = cr . out . file . handle ;
status = smb2_close ( tree , & cl ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
smb2_util_unlink ( tree , fname ) ;
done :
return ret ;
}
2010-02-22 23:38:26 +03:00
/* Send a compound request where we expect the last request (Create, Notify)
* to go asynchronous . This works against a Win7 server and the reply is
* sent in two different packets . */
static bool test_compound_interim1 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status = NT_STATUS_OK ;
const char * dname = " compound_interim_dir " ;
struct smb2_notify nt ;
bool ret = true ;
struct smb2_request * req [ 2 ] ;
/* Win7 compound request implementation deviates substantially from the
* SMB2 spec as noted in MS - SMB2 < 159 > , < 162 > . This , test currently
* verifies the Windows behavior , not the general spec behavior . */
smb2_transport_credits_ask_num ( tree - > session - > transport , 5 ) ;
smb2_deltree ( tree , dname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
cr . in . file_attributes = FILE_ATTRIBUTE_DIRECTORY ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_CREATE ;
cr . in . fname = dname ;
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( nt ) ;
nt . in . recursive = true ;
nt . in . buffer_size = 0x1000 ;
nt . in . file . handle = hd ;
nt . in . completion_filter = FILE_NOTIFY_CHANGE_NAME ;
nt . in . unknown = 0x00000000 ;
req [ 1 ] = smb2_notify_send ( tree , & nt ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
smb2_cancel ( req [ 1 ] ) ;
status = smb2_notify_recv ( req [ 1 ] , tree , & nt ) ;
CHECK_STATUS ( status , NT_STATUS_CANCELLED ) ;
smb2_util_close ( tree , cr . out . file . handle ) ;
smb2_deltree ( tree , dname ) ;
done :
return ret ;
}
/* Send a compound request where we expect the middle request (Create, Notify,
* GetInfo ) to go asynchronous . Against Win7 the sync request succeed while
* the async fails . All are returned in the same compound response . */
static bool test_compound_interim2 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle hd ;
struct smb2_create cr ;
NTSTATUS status = NT_STATUS_OK ;
const char * dname = " compound_interim_dir " ;
struct smb2_getinfo gf ;
struct smb2_notify nt ;
bool ret = true ;
struct smb2_request * req [ 3 ] ;
/* Win7 compound request implementation deviates substantially from the
* SMB2 spec as noted in MS - SMB2 < 159 > , < 162 > . This , test currently
* verifies the Windows behavior , not the general spec behavior . */
smb2_transport_credits_ask_num ( tree - > session - > transport , 5 ) ;
smb2_deltree ( tree , dname ) ;
smb2_transport_credits_ask_num ( tree - > session - > transport , 1 ) ;
ZERO_STRUCT ( cr ) ;
cr . in . desired_access = SEC_RIGHTS_FILE_ALL ;
cr . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
cr . in . file_attributes = FILE_ATTRIBUTE_DIRECTORY ;
cr . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
cr . in . create_disposition = NTCREATEX_DISP_CREATE ;
cr . in . fname = dname ;
smb2_transport_compound_start ( tree - > session - > transport , 3 ) ;
req [ 0 ] = smb2_create_send ( tree , & cr ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
hd . data [ 0 ] = UINT64_MAX ;
hd . data [ 1 ] = UINT64_MAX ;
ZERO_STRUCT ( nt ) ;
nt . in . recursive = true ;
nt . in . buffer_size = 0x1000 ;
nt . in . file . handle = hd ;
nt . in . completion_filter = FILE_NOTIFY_CHANGE_NAME ;
nt . in . unknown = 0x00000000 ;
req [ 1 ] = smb2_notify_send ( tree , & nt ) ;
ZERO_STRUCT ( gf ) ;
gf . in . file . handle = hd ;
2019-03-29 13:08:12 +03:00
gf . in . info_type = SMB2_0_INFO_FILE ;
2011-10-08 09:23:00 +04:00
gf . in . info_class = 0x04 ; /* FILE_BASIC_INFORMATION */
2010-02-22 23:38:26 +03:00
gf . in . output_buffer_length = 0x1000 ;
2019-01-08 18:09:46 +03:00
gf . in . input_buffer = data_blob_null ;
2010-02-22 23:38:26 +03:00
req [ 2 ] = smb2_getinfo_send ( tree , & gf ) ;
status = smb2_create_recv ( req [ 0 ] , tree , & cr ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
status = smb2_notify_recv ( req [ 1 ] , tree , & nt ) ;
CHECK_STATUS ( status , NT_STATUS_INTERNAL_ERROR ) ;
status = smb2_getinfo_recv ( req [ 2 ] , tree , & gf ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
smb2_util_close ( tree , cr . out . file . handle ) ;
smb2_deltree ( tree , dname ) ;
done :
return ret ;
}
2017-01-11 19:09:54 +03:00
/* Test compound related finds */
static bool test_compound_find_related ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
const char * dname = " compound_find_dir " ;
struct smb2_create create ;
struct smb2_find f ;
struct smb2_handle h ;
struct smb2_request * req [ 2 ] ;
NTSTATUS status ;
bool ret = true ;
smb2_deltree ( tree , dname ) ;
ZERO_STRUCT ( create ) ;
create . in . desired_access = SEC_RIGHTS_DIR_ALL ;
create . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
create . in . file_attributes = FILE_ATTRIBUTE_DIRECTORY ;
create . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
create . in . create_disposition = NTCREATEX_DISP_CREATE ;
create . in . fname = dname ;
status = smb2_create ( tree , mem_ctx , & create ) ;
h = create . out . file . handle ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_create failed \n " ) ;
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( f ) ;
f . in . file . handle = h ;
f . in . pattern = " * " ;
f . in . max_response_size = 0x100 ;
f . in . level = SMB2_FIND_BOTH_DIRECTORY_INFO ;
req [ 0 ] = smb2_find_send ( tree , & f ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
req [ 1 ] = smb2_find_send ( tree , & f ) ;
status = smb2_find_recv ( req [ 0 ] , mem_ctx , & f ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_find_recv failed \n " ) ;
status = smb2_find_recv ( req [ 1 ] , mem_ctx , & f ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , STATUS_NO_MORE_FILES , ret , done , " smb2_find_recv failed \n " ) ;
done :
smb2_util_close ( tree , h ) ;
smb2_deltree ( tree , dname ) ;
TALLOC_FREE ( mem_ctx ) ;
return ret ;
}
2018-03-22 11:22:08 +03:00
/* Test compound related finds */
static bool test_compound_find_close ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
const char * dname = " compound_find_dir " ;
struct smb2_create create ;
struct smb2_find f ;
struct smb2_handle h ;
struct smb2_request * req = NULL ;
const int num_files = 5000 ;
int i ;
NTSTATUS status ;
bool ret = true ;
smb2_deltree ( tree , dname ) ;
ZERO_STRUCT ( create ) ;
create . in . desired_access = SEC_RIGHTS_DIR_ALL ;
create . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
create . in . file_attributes = FILE_ATTRIBUTE_DIRECTORY ;
create . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
create . in . create_disposition = NTCREATEX_DISP_CREATE ;
create . in . fname = dname ;
smb2cli_conn_set_max_credits ( tree - > session - > transport - > conn , 256 ) ;
status = smb2_create ( tree , mem_ctx , & create ) ;
h = create . out . file . handle ;
ZERO_STRUCT ( create ) ;
create . in . desired_access = SEC_RIGHTS_FILE_ALL ;
create . in . file_attributes = FILE_ATTRIBUTE_NORMAL ;
create . in . create_disposition = NTCREATEX_DISP_CREATE ;
for ( i = 0 ; i < num_files ; i + + ) {
create . in . fname = talloc_asprintf ( mem_ctx , " %s \\ file%d " ,
dname , i ) ;
status = smb2_create ( tree , mem_ctx , & create ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " " ) ;
smb2_util_close ( tree , create . out . file . handle ) ;
}
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_create failed \n " ) ;
ZERO_STRUCT ( f ) ;
f . in . file . handle = h ;
f . in . pattern = " * " ;
f . in . max_response_size = 8 * 1024 * 1024 ;
f . in . level = SMB2_FIND_BOTH_DIRECTORY_INFO ;
req = smb2_find_send ( tree , & f ) ;
status = smb2_util_close ( tree , h ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_util_close failed \n " ) ;
status = smb2_find_recv ( req , mem_ctx , & f ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_find_recv failed \n " ) ;
done :
smb2_util_close ( tree , h ) ;
smb2_deltree ( tree , dname ) ;
TALLOC_FREE ( mem_ctx ) ;
return ret ;
}
2017-01-11 19:09:54 +03:00
/* Test compound unrelated finds */
static bool test_compound_find_unrelated ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
const char * dname = " compound_find_dir " ;
struct smb2_create create ;
struct smb2_find f ;
struct smb2_handle h ;
struct smb2_request * req [ 2 ] ;
NTSTATUS status ;
bool ret = true ;
smb2_deltree ( tree , dname ) ;
ZERO_STRUCT ( create ) ;
create . in . desired_access = SEC_RIGHTS_DIR_ALL ;
create . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
create . in . file_attributes = FILE_ATTRIBUTE_DIRECTORY ;
create . in . share_access = NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_DELETE ;
create . in . create_disposition = NTCREATEX_DISP_CREATE ;
create . in . fname = dname ;
status = smb2_create ( tree , mem_ctx , & create ) ;
h = create . out . file . handle ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_create failed \n " ) ;
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( f ) ;
f . in . file . handle = h ;
f . in . pattern = " * " ;
f . in . max_response_size = 0x100 ;
f . in . level = SMB2_FIND_BOTH_DIRECTORY_INFO ;
req [ 0 ] = smb2_find_send ( tree , & f ) ;
req [ 1 ] = smb2_find_send ( tree , & f ) ;
status = smb2_find_recv ( req [ 0 ] , mem_ctx , & f ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done , " smb2_find_recv failed \n " ) ;
status = smb2_find_recv ( req [ 1 ] , mem_ctx , & f ) ;
torture_assert_ntstatus_equal_goto ( tctx , status , STATUS_NO_MORE_FILES , ret , done , " smb2_find_recv failed \n " ) ;
done :
smb2_util_close ( tree , h ) ;
smb2_deltree ( tree , dname ) ;
TALLOC_FREE ( mem_ctx ) ;
return ret ;
}
2022-10-19 02:22:33 +03:00
static bool test_compound_async_flush_close ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle fhandle = { . data = { 0 , 0 } } ;
struct smb2_handle relhandle = { . data = { UINT64_MAX , UINT64_MAX } } ;
struct smb2_close cl ;
struct smb2_flush fl ;
const char * fname = " compound_async_flush_close " ;
struct smb2_request * req [ 2 ] ;
NTSTATUS status ;
bool ret = false ;
/* Start clean. */
smb2_util_unlink ( tree , fname ) ;
/* Create a file. */
status = torture_smb2_testfile_access ( tree ,
fname ,
& fhandle ,
SEC_RIGHTS_FILE_ALL ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* Now do a compound flush + close handle. */
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( fl ) ;
fl . in . file . handle = fhandle ;
req [ 0 ] = smb2_flush_send ( tree , & fl ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_flush_send failed \n " ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( cl ) ;
cl . in . file . handle = relhandle ;
req [ 1 ] = smb2_close_send ( tree , & cl ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_close_send failed \n " ) ;
status = smb2_flush_recv ( req [ 0 ] , & fl ) ;
/*
* On Windows , this flush will usually
* succeed as we have nothing to flush ,
* so allow NT_STATUS_OK . Once bug # 15172
* is fixed Samba will do the flush synchronously
* so allow NT_STATUS_OK .
*/
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* If we didn ' t get NT_STATUS_OK , we * must *
* get NT_STATUS_INTERNAL_ERROR if the flush
* goes async .
*
* For pre - bugfix # 15172 Samba , the flush goes async and
* we should get NT_STATUS_INTERNAL_ERROR .
*/
torture_assert_ntstatus_equal_goto ( tctx ,
status ,
NT_STATUS_INTERNAL_ERROR ,
ret ,
done ,
" smb2_flush_recv didn't return "
" NT_STATUS_INTERNAL_ERROR. \n " ) ;
}
status = smb2_close_recv ( req [ 1 ] , & cl ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_close_recv failed. " ) ;
ZERO_STRUCT ( fhandle ) ;
/*
* Do several more operations on the tree , spaced
* out by 1 sec sleeps to make sure the server didn ' t
* crash on the close . The sleeps are required to
* make test test for a crash reliable , as we ensure
* the pthread fsync internally finishes and accesses
2023-08-03 16:45:39 +03:00
* freed memory . Without them the test occasionally
2022-10-19 02:22:33 +03:00
* passes as we disconnect before the pthread fsync
* finishes .
*/
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
sleep ( 1 ) ;
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
sleep ( 1 ) ;
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
ret = true ;
done :
if ( fhandle . data [ 0 ] ! = 0 ) {
smb2_util_close ( tree , fhandle ) ;
}
smb2_util_unlink ( tree , fname ) ;
return ret ;
}
2022-10-21 00:22:25 +03:00
static bool test_compound_async_flush_flush ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle fhandle = { . data = { 0 , 0 } } ;
struct smb2_handle relhandle = { . data = { UINT64_MAX , UINT64_MAX } } ;
struct smb2_flush fl1 ;
struct smb2_flush fl2 ;
const char * fname = " compound_async_flush_flush " ;
struct smb2_request * req [ 2 ] ;
NTSTATUS status ;
bool ret = false ;
/* Start clean. */
smb2_util_unlink ( tree , fname ) ;
/* Create a file. */
status = torture_smb2_testfile_access ( tree ,
fname ,
& fhandle ,
SEC_RIGHTS_FILE_ALL ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* Now do a compound flush + flush handle. */
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( fl1 ) ;
fl1 . in . file . handle = fhandle ;
req [ 0 ] = smb2_flush_send ( tree , & fl1 ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_flush_send (1) failed \n " ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( fl2 ) ;
fl2 . in . file . handle = relhandle ;
req [ 1 ] = smb2_flush_send ( tree , & fl2 ) ;
torture_assert_not_null_goto ( tctx , req [ 1 ] , ret , done ,
" smb2_flush_send (2) failed \n " ) ;
status = smb2_flush_recv ( req [ 0 ] , & fl1 ) ;
/*
* On Windows , this flush will usually
* succeed as we have nothing to flush ,
* so allow NT_STATUS_OK . Once bug # 15172
* is fixed Samba will do the flush synchronously
* so allow NT_STATUS_OK .
*/
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* If we didn ' t get NT_STATUS_OK , we * must *
* get NT_STATUS_INTERNAL_ERROR if the flush
* goes async .
*
* For pre - bugfix # 15172 Samba , the flush goes async and
* we should get NT_STATUS_INTERNAL_ERROR .
*/
torture_assert_ntstatus_equal_goto ( tctx ,
status ,
NT_STATUS_INTERNAL_ERROR ,
ret ,
done ,
" smb2_flush_recv (1) didn't return "
" NT_STATUS_INTERNAL_ERROR. \n " ) ;
}
/*
* If the flush is the last entry in a compound ,
* it should always succeed even if it goes async .
*/
status = smb2_flush_recv ( req [ 1 ] , & fl2 ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_flush_recv (2) failed. " ) ;
status = smb2_util_close ( tree , fhandle ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_util_close failed. " ) ;
ZERO_STRUCT ( fhandle ) ;
/*
* Do several more operations on the tree , spaced
* out by 1 sec sleeps to make sure the server didn ' t
* crash on the close . The sleeps are required to
* make test test for a crash reliable , as we ensure
* the pthread fsync internally finishes and accesses
2023-08-03 16:45:39 +03:00
* freed memory . Without them the test occasionally
2022-10-21 00:22:25 +03:00
* passes as we disconnect before the pthread fsync
* finishes .
*/
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
sleep ( 1 ) ;
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
sleep ( 1 ) ;
status = smb2_util_unlink ( tree , fname ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
ret = true ;
done :
if ( fhandle . data [ 0 ] ! = 0 ) {
smb2_util_close ( tree , fhandle ) ;
}
smb2_util_unlink ( tree , fname ) ;
return ret ;
}
2022-11-18 02:39:16 +03:00
/*
* For Samba / smbd this test must be run against the aio_delay_inject share
* as we need to ensure the last write in the compound takes longer than
* 500 us , which is the threshold for going async in smbd SMB2 writes .
*/
static bool test_compound_async_write_write ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle fhandle = { . data = { 0 , 0 } } ;
struct smb2_handle relhandle = { . data = { UINT64_MAX , UINT64_MAX } } ;
struct smb2_write w1 ;
struct smb2_write w2 ;
const char * fname = " compound_async_write_write " ;
struct smb2_request * req [ 2 ] ;
NTSTATUS status ;
bool is_smbd = torture_setting_bool ( tctx , " smbd " , true ) ;
bool ret = false ;
/* Start clean. */
smb2_util_unlink ( tree , fname ) ;
/* Create a file. */
status = torture_smb2_testfile_access ( tree ,
fname ,
& fhandle ,
SEC_RIGHTS_FILE_ALL ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* Now do a compound write + write handle. */
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( w1 ) ;
w1 . in . file . handle = fhandle ;
w1 . in . offset = 0 ;
w1 . in . data = data_blob_talloc_zero ( tctx , 64 ) ;
req [ 0 ] = smb2_write_send ( tree , & w1 ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_write_send (1) failed \n " ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( w2 ) ;
w2 . in . file . handle = relhandle ;
w2 . in . offset = 64 ;
w2 . in . data = data_blob_talloc_zero ( tctx , 64 ) ;
req [ 1 ] = smb2_write_send ( tree , & w2 ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_write_send (2) failed \n " ) ;
status = smb2_write_recv ( req [ 0 ] , & w1 ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_write_recv (1) failed. " ) ;
if ( ! is_smbd ) {
/*
* Windows and other servers don ' t go async .
*/
status = smb2_write_recv ( req [ 1 ] , & w2 ) ;
} else {
/*
* For smbd , the second write should go async
* as it ' s the last element of a compound .
*/
WAIT_FOR_ASYNC_RESPONSE ( req [ 1 ] ) ;
CHECK_VALUE ( req [ 1 ] - > cancel . can_cancel , true ) ;
/*
* Now pick up the real return .
*/
status = smb2_write_recv ( req [ 1 ] , & w2 ) ;
}
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_write_recv (2) failed. " ) ;
status = smb2_util_close ( tree , fhandle ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_util_close failed. " ) ;
ZERO_STRUCT ( fhandle ) ;
ret = true ;
done :
if ( fhandle . data [ 0 ] ! = 0 ) {
smb2_util_close ( tree , fhandle ) ;
}
smb2_util_unlink ( tree , fname ) ;
return ret ;
}
2022-11-18 02:50:30 +03:00
/*
* For Samba / smbd this test must be run against the aio_delay_inject share
* as we need to ensure the last read in the compound takes longer than
* 500 us , which is the threshold for going async in smbd SMB2 reads .
*/
static bool test_compound_async_read_read ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
struct smb2_handle fhandle = { . data = { 0 , 0 } } ;
struct smb2_handle relhandle = { . data = { UINT64_MAX , UINT64_MAX } } ;
struct smb2_write w ;
struct smb2_read r1 ;
struct smb2_read r2 ;
const char * fname = " compound_async_read_read " ;
struct smb2_request * req [ 2 ] ;
NTSTATUS status ;
bool is_smbd = torture_setting_bool ( tctx , " smbd " , true ) ;
bool ret = false ;
/* Start clean. */
smb2_util_unlink ( tree , fname ) ;
/* Create a file. */
status = torture_smb2_testfile_access ( tree ,
fname ,
& fhandle ,
SEC_RIGHTS_FILE_ALL ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* Write 128 bytes. */
ZERO_STRUCT ( w ) ;
w . in . file . handle = fhandle ;
w . in . offset = 0 ;
w . in . data = data_blob_talloc_zero ( tctx , 128 ) ;
status = smb2_write ( tree , & w ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_write_recv (1) failed. " ) ;
/* Now do a compound read + read handle. */
smb2_transport_compound_start ( tree - > session - > transport , 2 ) ;
ZERO_STRUCT ( r1 ) ;
r1 . in . file . handle = fhandle ;
r1 . in . length = 64 ;
r1 . in . offset = 0 ;
req [ 0 ] = smb2_read_send ( tree , & r1 ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_read_send (1) failed \n " ) ;
smb2_transport_compound_set_related ( tree - > session - > transport , true ) ;
ZERO_STRUCT ( r2 ) ;
r2 . in . file . handle = relhandle ;
r2 . in . length = 64 ;
r2 . in . offset = 64 ;
req [ 1 ] = smb2_read_send ( tree , & r2 ) ;
torture_assert_not_null_goto ( tctx , req [ 0 ] , ret , done ,
" smb2_read_send (2) failed \n " ) ;
status = smb2_read_recv ( req [ 0 ] , tree , & r1 ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_read_recv (1) failed. " ) ;
if ( ! is_smbd ) {
/*
* Windows and other servers don ' t go async .
*/
status = smb2_read_recv ( req [ 1 ] , tree , & r2 ) ;
} else {
/*
* For smbd , the second write should go async
* as it ' s the last element of a compound .
*/
WAIT_FOR_ASYNC_RESPONSE ( req [ 1 ] ) ;
CHECK_VALUE ( req [ 1 ] - > cancel . can_cancel , true ) ;
/*
* Now pick up the real return .
*/
status = smb2_read_recv ( req [ 1 ] , tree , & r2 ) ;
}
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_read_recv (2) failed. " ) ;
status = smb2_util_close ( tree , fhandle ) ;
torture_assert_ntstatus_ok_goto ( tctx , status , ret , done ,
" smb2_util_close failed. " ) ;
ZERO_STRUCT ( fhandle ) ;
ret = true ;
done :
if ( fhandle . data [ 0 ] ! = 0 ) {
smb2_util_close ( tree , fhandle ) ;
}
smb2_util_unlink ( tree , fname ) ;
return ret ;
}
2017-04-25 01:13:10 +03:00
struct torture_suite * torture_smb2_compound_init ( TALLOC_CTX * ctx )
2009-06-08 18:26:57 +04:00
{
2017-04-25 01:13:10 +03:00
struct torture_suite * suite = torture_suite_create ( ctx , " compound " ) ;
2010-12-11 05:26:31 +03:00
torture_suite_add_1smb2_test ( suite , " related1 " , test_compound_related1 ) ;
torture_suite_add_1smb2_test ( suite , " related2 " , test_compound_related2 ) ;
2012-08-26 23:22:02 +04:00
torture_suite_add_1smb2_test ( suite , " related3 " ,
test_compound_related3 ) ;
2020-05-15 21:32:18 +03:00
torture_suite_add_1smb2_test ( suite , " related4 " ,
test_compound_related4 ) ;
torture_suite_add_1smb2_test ( suite , " related5 " ,
test_compound_related5 ) ;
2020-05-18 17:50:05 +03:00
torture_suite_add_1smb2_test ( suite , " related6 " ,
test_compound_related6 ) ;
2020-07-15 07:44:52 +03:00
torture_suite_add_1smb2_test ( suite , " related7 " ,
test_compound_related7 ) ;
2021-04-08 13:14:19 +03:00
torture_suite_add_1smb2_test ( suite , " related8 " ,
test_compound_related8 ) ;
2021-04-08 13:25:22 +03:00
torture_suite_add_1smb2_test ( suite , " related9 " ,
test_compound_related9 ) ;
2010-12-11 05:26:31 +03:00
torture_suite_add_1smb2_test ( suite , " unrelated1 " , test_compound_unrelated1 ) ;
torture_suite_add_1smb2_test ( suite , " invalid1 " , test_compound_invalid1 ) ;
torture_suite_add_1smb2_test ( suite , " invalid2 " , test_compound_invalid2 ) ;
torture_suite_add_1smb2_test ( suite , " invalid3 " , test_compound_invalid3 ) ;
2018-04-11 16:11:10 +03:00
torture_suite_add_1smb2_test (
suite , " invalid4 " , test_compound_invalid4 ) ;
2010-12-11 05:26:31 +03:00
torture_suite_add_1smb2_test ( suite , " interim1 " , test_compound_interim1 ) ;
torture_suite_add_1smb2_test ( suite , " interim2 " , test_compound_interim2 ) ;
2013-05-03 01:36:05 +04:00
torture_suite_add_1smb2_test ( suite , " compound-break " , test_compound_break ) ;
2015-05-14 05:27:54 +03:00
torture_suite_add_1smb2_test ( suite , " compound-padding " , test_compound_padding ) ;
2017-09-21 02:07:50 +03:00
torture_suite_add_1smb2_test ( suite , " create-write-close " ,
test_compound_create_write_close ) ;
2009-06-08 18:26:57 +04:00
suite - > description = talloc_strdup ( suite , " SMB2-COMPOUND tests " ) ;
return suite ;
}
2017-01-11 19:09:54 +03:00
2017-04-25 01:13:10 +03:00
struct torture_suite * torture_smb2_compound_find_init ( TALLOC_CTX * ctx )
2017-01-11 19:09:54 +03:00
{
2017-04-25 01:13:10 +03:00
struct torture_suite * suite = torture_suite_create ( ctx , " compound_find " ) ;
2017-01-11 19:09:54 +03:00
torture_suite_add_1smb2_test ( suite , " compound_find_related " , test_compound_find_related ) ;
torture_suite_add_1smb2_test ( suite , " compound_find_unrelated " , test_compound_find_unrelated ) ;
2018-03-22 11:22:08 +03:00
torture_suite_add_1smb2_test ( suite , " compound_find_close " , test_compound_find_close ) ;
2017-01-11 19:09:54 +03:00
suite - > description = talloc_strdup ( suite , " SMB2-COMPOUND-FIND tests " ) ;
return suite ;
}
2022-10-19 02:22:33 +03:00
struct torture_suite * torture_smb2_compound_async_init ( TALLOC_CTX * ctx )
{
struct torture_suite * suite = torture_suite_create ( ctx ,
" compound_async " ) ;
torture_suite_add_1smb2_test ( suite , " flush_close " ,
test_compound_async_flush_close ) ;
2022-10-21 00:22:25 +03:00
torture_suite_add_1smb2_test ( suite , " flush_flush " ,
test_compound_async_flush_flush ) ;
2022-11-18 02:39:16 +03:00
torture_suite_add_1smb2_test ( suite , " write_write " ,
test_compound_async_write_write ) ;
2022-11-18 02:50:30 +03:00
torture_suite_add_1smb2_test ( suite , " read_read " ,
test_compound_async_read_read ) ;
2022-10-19 02:22:33 +03:00
suite - > description = talloc_strdup ( suite , " SMB2-COMPOUND-ASYNC tests " ) ;
return suite ;
}