2011-09-23 00:23:08 +04:00
/*
Unix SMB / CIFS implementation .
test suite for SMB2 ioctl operations
Copyright ( C ) David Disseldorp 2011
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"
# include "librpc/gen_ndr/security.h"
# include "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
# include "torture/torture.h"
# include "torture/smb2/proto.h"
2011-09-27 18:40:20 +04:00
# include "librpc/gen_ndr/ndr_ioctl.h"
2011-09-23 00:23:08 +04:00
2011-09-27 18:40:20 +04:00
# define FNAME "testfsctl.dat"
# define FNAME2 "testfsctl2.dat"
2011-09-23 00:23:08 +04:00
/*
basic testing of SMB2 shadow copy calls
*/
static bool test_ioctl_get_shadow_copy ( struct torture_context * torture ,
struct smb2_tree * tree )
{
struct smb2_handle h ;
uint8_t buf [ 100 ] ;
NTSTATUS status ;
union smb_ioctl ioctl ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
smb2_util_unlink ( tree , FNAME ) ;
status = torture_smb2_testfile ( tree , FNAME , & h ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " create write " ) ;
2011-09-23 00:23:08 +04:00
ZERO_ARRAY ( buf ) ;
status = smb2_util_write ( tree , h , buf , 0 , ARRAY_SIZE ( buf ) ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " write " ) ;
2011-09-23 00:23:08 +04:00
ZERO_STRUCT ( ioctl ) ;
ioctl . smb2 . level = RAW_IOCTL_SMB2 ;
ioctl . smb2 . in . file . handle = h ;
2011-10-18 15:55:22 +04:00
ioctl . smb2 . in . function = FSCTL_SRV_ENUM_SNAPS ;
2011-09-23 00:23:08 +04:00
ioctl . smb2 . in . max_response_size = 16 ;
2011-09-26 15:38:16 +04:00
ioctl . smb2 . in . flags = SMB2_IOCTL_FLAG_IS_FSCTL ;
2011-09-23 00:23:08 +04:00
status = smb2_ioctl ( tree , tmp_ctx , & ioctl . smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " FSCTL_SRV_ENUM_SNAPS " ) ;
2011-09-23 00:23:08 +04:00
return true ;
}
2011-09-27 18:40:20 +04:00
/*
basic testing of the SMB2 server side copy ioctls
*/
static bool test_ioctl_req_resume_key ( struct torture_context * torture ,
struct smb2_tree * tree )
{
struct smb2_handle h ;
uint8_t buf [ 100 ] ;
NTSTATUS status ;
union smb_ioctl ioctl ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
struct req_resume_key_rsp res_key ;
enum ndr_err_code ndr_ret ;
smb2_util_unlink ( tree , FNAME ) ;
status = torture_smb2_testfile ( tree , FNAME , & h ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " create write " ) ;
2011-09-27 18:40:20 +04:00
ZERO_ARRAY ( buf ) ;
status = smb2_util_write ( tree , h , buf , 0 , ARRAY_SIZE ( buf ) ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " write " ) ;
2011-09-27 18:40:20 +04:00
ZERO_STRUCT ( ioctl ) ;
ioctl . smb2 . level = RAW_IOCTL_SMB2 ;
ioctl . smb2 . in . file . handle = h ;
ioctl . smb2 . in . function = FSCTL_SRV_REQUEST_RESUME_KEY ;
ioctl . smb2 . in . max_response_size = 32 ;
ioctl . smb2 . in . flags = SMB2_IOCTL_FLAG_IS_FSCTL ;
status = smb2_ioctl ( tree , tmp_ctx , & ioctl . smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " FSCTL_SRV_REQUEST_RESUME_KEY " ) ;
2011-09-27 18:40:20 +04:00
ndr_ret = ndr_pull_struct_blob ( & ioctl . smb2 . out . out , tmp_ctx , & res_key ,
( ndr_pull_flags_fn_t ) ndr_pull_req_resume_key_rsp ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_pull_req_resume_key_rsp " ) ;
2011-09-27 18:40:20 +04:00
ndr_print_debug ( ( ndr_print_fn_t ) ndr_print_req_resume_key_rsp , " yo " , & res_key ) ;
talloc_free ( tmp_ctx ) ;
return true ;
}
2011-10-11 13:44:03 +04:00
static uint64_t patt_hash ( uint64_t off )
{
return off ;
}
2012-02-29 14:02:20 +04:00
static bool check_pattern ( struct torture_context * torture ,
struct smb2_tree * tree , TALLOC_CTX * mem_ctx ,
2011-10-11 13:44:03 +04:00
struct smb2_handle h , uint64_t off , uint64_t len ,
uint64_t patt_off )
{
uint64_t i ;
struct smb2_read r ;
NTSTATUS status ;
ZERO_STRUCT ( r ) ;
r . in . file . handle = h ;
r . in . length = len ;
r . in . offset = off ;
status = smb2_read ( tree , mem_ctx , & r ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " read " ) ;
torture_assert_u64_equal ( torture , r . out . data . length , len ,
" read data len mismatch " ) ;
2011-10-11 13:44:03 +04:00
for ( i = 0 ; i < = len - 8 ; i + = 8 , patt_off + = 8 ) {
2012-02-29 14:02:20 +04:00
uint64_t data = BVAL ( r . out . data . data , i ) ;
torture_assert_u64_equal ( torture , data , patt_hash ( patt_off ) ,
talloc_asprintf ( torture , " read data "
" pattern bad at %llu \n " ,
( unsigned long long ) i ) ) ;
2011-10-11 13:44:03 +04:00
}
talloc_free ( r . out . data . data ) ;
return true ;
}
2012-02-29 14:02:20 +04:00
static bool test_setup_copy_chunk ( struct torture_context * torture ,
struct smb2_tree * tree , TALLOC_CTX * mem_ctx ,
2011-09-30 14:50:36 +04:00
uint32_t nchunks ,
struct smb2_handle * src_h ,
uint64_t src_size ,
struct smb2_handle * dest_h ,
uint64_t dest_size ,
struct srv_copychunk_copy * cc_copy ,
union smb_ioctl * ioctl )
2011-09-27 18:40:20 +04:00
{
struct req_resume_key_rsp res_key ;
2011-09-30 14:50:36 +04:00
NTSTATUS status ;
2011-09-27 18:40:20 +04:00
enum ndr_err_code ndr_ret ;
2011-10-11 13:44:03 +04:00
uint64_t i ;
2011-09-30 14:50:36 +04:00
uint8_t * buf = talloc_zero_size ( mem_ctx , MAX ( src_size , dest_size ) ) ;
if ( buf = = NULL ) {
printf ( " no mem for file data buffer \n " ) ;
return false ;
}
2011-09-27 18:40:20 +04:00
smb2_util_unlink ( tree , FNAME ) ;
smb2_util_unlink ( tree , FNAME2 ) ;
2011-09-30 14:50:36 +04:00
status = torture_smb2_testfile ( tree , FNAME , src_h ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " create write " ) ;
2011-09-27 18:40:20 +04:00
2011-09-30 14:50:36 +04:00
if ( src_size > 0 ) {
2011-10-11 13:44:03 +04:00
for ( i = 0 ; i < = src_size - 8 ; i + = 8 ) {
SBVAL ( buf , i , patt_hash ( i ) ) ;
}
2011-09-30 14:50:36 +04:00
status = smb2_util_write ( tree , * src_h , buf , 0 , src_size ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " src write " ) ;
2011-09-30 14:50:36 +04:00
}
status = torture_smb2_testfile ( tree , FNAME2 , dest_h ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " create write " ) ;
2011-09-27 18:40:20 +04:00
2011-09-30 14:50:36 +04:00
if ( dest_size > 0 ) {
2011-10-11 13:44:03 +04:00
for ( i = 0 ; i < = src_size - 8 ; i + = 8 ) {
SBVAL ( buf , i , patt_hash ( i ) ) ;
}
2011-09-30 14:50:36 +04:00
status = smb2_util_write ( tree , * dest_h , buf , 0 , dest_size ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " dest write " ) ;
2011-09-30 14:50:36 +04:00
}
ZERO_STRUCTPN ( ioctl ) ;
ioctl - > smb2 . level = RAW_IOCTL_SMB2 ;
ioctl - > smb2 . in . file . handle = * src_h ;
ioctl - > smb2 . in . function = FSCTL_SRV_REQUEST_RESUME_KEY ;
2011-09-27 18:40:20 +04:00
/* Allow for Key + ContextLength + Context */
2011-09-30 14:50:36 +04:00
ioctl - > smb2 . in . max_response_size = 32 ;
ioctl - > smb2 . in . flags = SMB2_IOCTL_FLAG_IS_FSCTL ;
2011-09-27 18:40:20 +04:00
2011-09-30 14:50:36 +04:00
status = smb2_ioctl ( tree , mem_ctx , & ioctl - > smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status ,
" FSCTL_SRV_REQUEST_RESUME_KEY " ) ;
2011-09-27 18:40:20 +04:00
2011-09-30 14:50:36 +04:00
ndr_ret = ndr_pull_struct_blob ( & ioctl - > smb2 . out . out , mem_ctx , & res_key ,
2011-09-27 18:40:20 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_req_resume_key_rsp ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_pull_req_resume_key_rsp " ) ;
2011-09-27 18:40:20 +04:00
2011-09-30 14:50:36 +04:00
ZERO_STRUCTPN ( ioctl ) ;
ioctl - > smb2 . level = RAW_IOCTL_SMB2 ;
ioctl - > smb2 . in . file . handle = * dest_h ;
ioctl - > smb2 . in . function = FSCTL_SRV_COPYCHUNK ;
ioctl - > smb2 . in . max_response_size = sizeof ( struct srv_copychunk_rsp ) ;
ioctl - > smb2 . in . flags = SMB2_IOCTL_FLAG_IS_FSCTL ;
ZERO_STRUCTPN ( cc_copy ) ;
memcpy ( cc_copy - > source_key , res_key . resume_key , ARRAY_SIZE ( cc_copy - > source_key ) ) ;
cc_copy - > chunk_count = nchunks ;
cc_copy - > chunks = talloc_zero_array ( mem_ctx , struct srv_copychunk , nchunks ) ;
if ( cc_copy - > chunks = = NULL ) {
printf ( " not enough memory to allocate %u chunks \n " , nchunks ) ;
2011-09-27 18:40:20 +04:00
return false ;
}
2011-09-30 14:50:36 +04:00
return true ;
}
2011-09-27 18:40:20 +04:00
2012-02-29 14:02:20 +04:00
static bool check_copy_chunk_rsp ( struct torture_context * torture ,
struct srv_copychunk_rsp * cc_rsp ,
2011-09-30 14:50:36 +04:00
uint32_t ex_chunks_written ,
uint32_t ex_chunk_bytes_written ,
uint32_t ex_total_bytes_written )
{
2012-02-29 14:02:20 +04:00
torture_assert_int_equal ( torture , cc_rsp - > chunks_written ,
ex_chunks_written , " num chunks " ) ;
torture_assert_int_equal ( torture , cc_rsp - > chunk_bytes_written ,
ex_chunk_bytes_written , " chunk bytes written " ) ;
torture_assert_int_equal ( torture , cc_rsp - > total_bytes_written ,
ex_total_bytes_written , " chunk total bytes " ) ;
2011-09-30 14:50:36 +04:00
return true ;
}
2011-09-30 16:33:36 +04:00
static bool test_ioctl_copy_chunk_simple ( struct torture_context * torture ,
struct smb2_tree * tree )
2011-09-30 14:50:36 +04:00
{
struct smb2_handle src_h ;
struct smb2_handle dest_h ;
NTSTATUS status ;
union smb_ioctl ioctl ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
struct srv_copychunk_copy cc_copy ;
struct srv_copychunk_rsp cc_rsp ;
enum ndr_err_code ndr_ret ;
bool ok ;
2012-02-29 14:02:20 +04:00
ok = test_setup_copy_chunk ( torture , tree , tmp_ctx ,
2011-09-30 14:50:36 +04:00
1 , /* 1 chunk */
2011-09-30 16:33:36 +04:00
& src_h , 4096 , /* fill 4096 byte src file */
2011-09-30 14:50:36 +04:00
& dest_h , 0 , /* 0 byte dest file */
& cc_copy ,
& ioctl ) ;
if ( ! ok ) {
return false ;
}
/* copy all src file data (via a single chunk desc) */
cc_copy . chunks [ 0 ] . source_off = 0 ;
cc_copy . chunks [ 0 ] . target_off = 0 ;
2011-09-30 16:33:36 +04:00
cc_copy . chunks [ 0 ] . length = 4096 ;
2011-09-27 18:40:20 +04:00
ndr_ret = ndr_push_struct_blob ( & ioctl . smb2 . in . out , tmp_ctx ,
& cc_copy ,
( ndr_push_flags_fn_t ) ndr_push_srv_copychunk_copy ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_push_srv_copychunk_copy " ) ;
2011-09-27 18:40:20 +04:00
status = smb2_ioctl ( tree , tmp_ctx , & ioctl . smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " FSCTL_SRV_COPYCHUNK " ) ;
2011-09-27 18:40:20 +04:00
ndr_ret = ndr_pull_struct_blob ( & ioctl . smb2 . out . out , tmp_ctx ,
& cc_rsp ,
( ndr_pull_flags_fn_t ) ndr_pull_srv_copychunk_rsp ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_pull_srv_copychunk_rsp " ) ;
2011-09-30 14:50:36 +04:00
2012-02-29 14:02:20 +04:00
ok = check_copy_chunk_rsp ( torture , & cc_rsp ,
2011-09-30 14:50:36 +04:00
1 , /* chunks written */
0 , /* chunk bytes unsuccessfully written */
2011-09-30 16:33:36 +04:00
4096 ) ; /* total bytes written */
if ( ! ok ) {
return false ;
}
2012-02-29 14:02:20 +04:00
ok = check_pattern ( torture , tree , tmp_ctx , dest_h , 0 , 4096 , 0 ) ;
2011-10-11 13:44:03 +04:00
if ( ! ok ) {
return false ;
}
2011-09-30 16:33:36 +04:00
smb2_util_close ( tree , src_h ) ;
smb2_util_close ( tree , dest_h ) ;
talloc_free ( tmp_ctx ) ;
return true ;
}
static bool test_ioctl_copy_chunk_multi ( struct torture_context * torture ,
struct smb2_tree * tree )
{
struct smb2_handle src_h ;
struct smb2_handle dest_h ;
NTSTATUS status ;
union smb_ioctl ioctl ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
struct srv_copychunk_copy cc_copy ;
struct srv_copychunk_rsp cc_rsp ;
enum ndr_err_code ndr_ret ;
bool ok ;
2012-02-29 14:02:20 +04:00
ok = test_setup_copy_chunk ( torture , tree , tmp_ctx ,
2011-09-30 16:33:36 +04:00
2 , /* chunks */
& src_h , 8192 , /* src file */
& dest_h , 0 , /* dest file */
& cc_copy ,
& ioctl ) ;
if ( ! ok ) {
return false ;
}
/* copy all src file data via two chunks */
cc_copy . chunks [ 0 ] . source_off = 0 ;
cc_copy . chunks [ 0 ] . target_off = 0 ;
cc_copy . chunks [ 0 ] . length = 4096 ;
cc_copy . chunks [ 1 ] . source_off = 4096 ;
cc_copy . chunks [ 1 ] . target_off = 4096 ;
cc_copy . chunks [ 1 ] . length = 4096 ;
ndr_ret = ndr_push_struct_blob ( & ioctl . smb2 . in . out , tmp_ctx ,
& cc_copy ,
( ndr_push_flags_fn_t ) ndr_push_srv_copychunk_copy ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_push_srv_copychunk_copy " ) ;
2011-09-30 16:33:36 +04:00
status = smb2_ioctl ( tree , tmp_ctx , & ioctl . smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " FSCTL_SRV_COPYCHUNK " ) ;
2011-09-30 16:33:36 +04:00
ndr_ret = ndr_pull_struct_blob ( & ioctl . smb2 . out . out , tmp_ctx ,
& cc_rsp ,
( ndr_pull_flags_fn_t ) ndr_pull_srv_copychunk_rsp ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_pull_srv_copychunk_rsp " ) ;
2011-09-30 16:33:36 +04:00
2012-02-29 14:02:20 +04:00
ok = check_copy_chunk_rsp ( torture , & cc_rsp ,
2011-09-30 16:33:36 +04:00
2 , /* chunks written */
0 , /* chunk bytes unsuccessfully written */
8192 ) ; /* total bytes written */
if ( ! ok ) {
return false ;
}
smb2_util_close ( tree , src_h ) ;
smb2_util_close ( tree , dest_h ) ;
talloc_free ( tmp_ctx ) ;
return true ;
}
static bool test_ioctl_copy_chunk_tiny ( struct torture_context * torture ,
struct smb2_tree * tree )
{
struct smb2_handle src_h ;
struct smb2_handle dest_h ;
NTSTATUS status ;
union smb_ioctl ioctl ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
struct srv_copychunk_copy cc_copy ;
struct srv_copychunk_rsp cc_rsp ;
enum ndr_err_code ndr_ret ;
bool ok ;
2012-02-29 14:02:20 +04:00
ok = test_setup_copy_chunk ( torture , tree , tmp_ctx ,
2011-09-30 16:33:36 +04:00
2 , /* chunks */
& src_h , 100 , /* src file */
& dest_h , 0 , /* dest file */
& cc_copy ,
& ioctl ) ;
if ( ! ok ) {
return false ;
}
/* copy all src file data via two chunks, sub block size chunks */
cc_copy . chunks [ 0 ] . source_off = 0 ;
cc_copy . chunks [ 0 ] . target_off = 0 ;
cc_copy . chunks [ 0 ] . length = 50 ;
cc_copy . chunks [ 1 ] . source_off = 50 ;
cc_copy . chunks [ 1 ] . target_off = 50 ;
cc_copy . chunks [ 1 ] . length = 50 ;
ndr_ret = ndr_push_struct_blob ( & ioctl . smb2 . in . out , tmp_ctx ,
& cc_copy ,
( ndr_push_flags_fn_t ) ndr_push_srv_copychunk_copy ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_push_srv_copychunk_copy " ) ;
2011-09-30 16:33:36 +04:00
status = smb2_ioctl ( tree , tmp_ctx , & ioctl . smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " FSCTL_SRV_COPYCHUNK " ) ;
2011-09-30 16:33:36 +04:00
ndr_ret = ndr_pull_struct_blob ( & ioctl . smb2 . out . out , tmp_ctx ,
& cc_rsp ,
( ndr_pull_flags_fn_t ) ndr_pull_srv_copychunk_rsp ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_pull_srv_copychunk_rsp " ) ;
2011-09-30 16:33:36 +04:00
2012-02-29 14:02:20 +04:00
ok = check_copy_chunk_rsp ( torture , & cc_rsp ,
2011-09-30 16:33:36 +04:00
2 , /* chunks written */
0 , /* chunk bytes unsuccessfully written */
2011-09-30 14:50:36 +04:00
100 ) ; /* total bytes written */
if ( ! ok ) {
2011-09-27 18:40:20 +04:00
return false ;
}
2012-02-29 14:02:20 +04:00
ok = check_pattern ( torture , tree , tmp_ctx , dest_h , 0 , 100 , 0 ) ;
2011-10-11 13:44:03 +04:00
if ( ! ok ) {
return false ;
}
2011-09-30 16:33:36 +04:00
smb2_util_close ( tree , src_h ) ;
smb2_util_close ( tree , dest_h ) ;
talloc_free ( tmp_ctx ) ;
return true ;
}
static bool test_ioctl_copy_chunk_over ( struct torture_context * torture ,
struct smb2_tree * tree )
{
struct smb2_handle src_h ;
struct smb2_handle dest_h ;
NTSTATUS status ;
union smb_ioctl ioctl ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
struct srv_copychunk_copy cc_copy ;
struct srv_copychunk_rsp cc_rsp ;
enum ndr_err_code ndr_ret ;
bool ok ;
2012-02-29 14:02:20 +04:00
ok = test_setup_copy_chunk ( torture , tree , tmp_ctx ,
2011-09-30 16:33:36 +04:00
2 , /* chunks */
& src_h , 8192 , /* src file */
& dest_h , 4096 , /* dest file */
& cc_copy ,
& ioctl ) ;
if ( ! ok ) {
return false ;
}
/* first chunk overwrites existing dest data */
cc_copy . chunks [ 0 ] . source_off = 0 ;
cc_copy . chunks [ 0 ] . target_off = 0 ;
cc_copy . chunks [ 0 ] . length = 4096 ;
/* second chunk overwrites the first */
cc_copy . chunks [ 1 ] . source_off = 4096 ;
cc_copy . chunks [ 1 ] . target_off = 0 ;
cc_copy . chunks [ 1 ] . length = 4096 ;
ndr_ret = ndr_push_struct_blob ( & ioctl . smb2 . in . out , tmp_ctx ,
& cc_copy ,
( ndr_push_flags_fn_t ) ndr_push_srv_copychunk_copy ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_push_srv_copychunk_copy " ) ;
2011-09-30 16:33:36 +04:00
status = smb2_ioctl ( tree , tmp_ctx , & ioctl . smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " FSCTL_SRV_COPYCHUNK " ) ;
2011-09-30 16:33:36 +04:00
ndr_ret = ndr_pull_struct_blob ( & ioctl . smb2 . out . out , tmp_ctx ,
& cc_rsp ,
( ndr_pull_flags_fn_t ) ndr_pull_srv_copychunk_rsp ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_pull_srv_copychunk_rsp " ) ;
2011-09-30 16:33:36 +04:00
2012-02-29 14:02:20 +04:00
ok = check_copy_chunk_rsp ( torture , & cc_rsp ,
2011-09-30 16:33:36 +04:00
2 , /* chunks written */
0 , /* chunk bytes unsuccessfully written */
8192 ) ; /* total bytes written */
if ( ! ok ) {
return false ;
}
2012-02-29 14:02:20 +04:00
ok = check_pattern ( torture , tree , tmp_ctx , dest_h , 0 , 4096 , 4096 ) ;
2011-10-11 13:44:03 +04:00
if ( ! ok ) {
return false ;
}
2011-09-30 16:33:36 +04:00
smb2_util_close ( tree , src_h ) ;
smb2_util_close ( tree , dest_h ) ;
talloc_free ( tmp_ctx ) ;
return true ;
}
static bool test_ioctl_copy_chunk_append ( struct torture_context * torture ,
struct smb2_tree * tree )
{
struct smb2_handle src_h ;
struct smb2_handle dest_h ;
NTSTATUS status ;
union smb_ioctl ioctl ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
struct srv_copychunk_copy cc_copy ;
struct srv_copychunk_rsp cc_rsp ;
enum ndr_err_code ndr_ret ;
bool ok ;
2012-02-29 14:02:20 +04:00
ok = test_setup_copy_chunk ( torture , tree , tmp_ctx ,
2011-09-30 16:33:36 +04:00
2 , /* chunks */
& src_h , 4096 , /* src file */
& dest_h , 0 , /* dest file */
& cc_copy ,
& ioctl ) ;
if ( ! ok ) {
return false ;
}
cc_copy . chunks [ 0 ] . source_off = 0 ;
cc_copy . chunks [ 0 ] . target_off = 0 ;
cc_copy . chunks [ 0 ] . length = 4096 ;
/* second chunk appends the same data to the first */
cc_copy . chunks [ 1 ] . source_off = 0 ;
cc_copy . chunks [ 1 ] . target_off = 4096 ;
cc_copy . chunks [ 1 ] . length = 4096 ;
ndr_ret = ndr_push_struct_blob ( & ioctl . smb2 . in . out , tmp_ctx ,
& cc_copy ,
( ndr_push_flags_fn_t ) ndr_push_srv_copychunk_copy ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_push_srv_copychunk_copy " ) ;
2011-09-30 16:33:36 +04:00
status = smb2_ioctl ( tree , tmp_ctx , & ioctl . smb2 ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ntstatus_ok ( torture , status , " FSCTL_SRV_COPYCHUNK " ) ;
2011-09-30 16:33:36 +04:00
ndr_ret = ndr_pull_struct_blob ( & ioctl . smb2 . out . out , tmp_ctx ,
& cc_rsp ,
( ndr_pull_flags_fn_t ) ndr_pull_srv_copychunk_rsp ) ;
2012-02-29 14:02:20 +04:00
torture_assert_ndr_success ( torture , ndr_ret ,
" ndr_pull_srv_copychunk_rsp " ) ;
2011-09-30 16:33:36 +04:00
2012-02-29 14:02:20 +04:00
ok = check_copy_chunk_rsp ( torture , & cc_rsp ,
2011-09-30 16:33:36 +04:00
2 , /* chunks written */
0 , /* chunk bytes unsuccessfully written */
8192 ) ; /* total bytes written */
if ( ! ok ) {
return false ;
}
2012-02-29 14:02:20 +04:00
ok = check_pattern ( torture , tree , tmp_ctx , dest_h , 0 , 4096 , 0 ) ;
2011-10-11 13:44:03 +04:00
if ( ! ok ) {
return false ;
}
2012-02-29 14:02:20 +04:00
ok = check_pattern ( torture , tree , tmp_ctx , dest_h , 4096 , 4096 , 0 ) ;
2011-10-11 13:44:03 +04:00
if ( ! ok ) {
return false ;
}
2011-09-30 16:33:36 +04:00
smb2_util_close ( tree , src_h ) ;
smb2_util_close ( tree , dest_h ) ;
2011-09-27 18:40:20 +04:00
talloc_free ( tmp_ctx ) ;
return true ;
}
2011-09-23 00:23:08 +04:00
/*
basic testing of SMB2 ioctls
*/
struct torture_suite * torture_smb2_ioctl_init ( void )
{
struct torture_suite * suite = torture_suite_create ( talloc_autofree_context ( ) , " ioctl " ) ;
2011-09-30 16:33:36 +04:00
torture_suite_add_1smb2_test ( suite , " shadow_copy " ,
test_ioctl_get_shadow_copy ) ;
torture_suite_add_1smb2_test ( suite , " req_resume_key " ,
test_ioctl_req_resume_key ) ;
torture_suite_add_1smb2_test ( suite , " copy_chunk_simple " ,
test_ioctl_copy_chunk_simple ) ;
torture_suite_add_1smb2_test ( suite , " copy_chunk_multi " ,
test_ioctl_copy_chunk_multi ) ;
torture_suite_add_1smb2_test ( suite , " copy_chunk_tiny " ,
test_ioctl_copy_chunk_tiny ) ;
torture_suite_add_1smb2_test ( suite , " copy_chunk_overwrite " ,
test_ioctl_copy_chunk_over ) ;
torture_suite_add_1smb2_test ( suite , " copy_chunk_append " ,
test_ioctl_copy_chunk_append ) ;
2011-09-23 00:23:08 +04:00
suite - > description = talloc_strdup ( suite , " SMB2-IOCTL tests " ) ;
return suite ;
}