2008-04-16 12:11:44 +04:00
/*
Unix SMB / CIFS implementation .
2009-03-26 19:32:50 +03:00
test suite for SMB2 durable opens
2008-04-16 12:11:44 +04:00
Copyright ( C ) Stefan Metzmacher 2008
2012-03-01 01:59:35 +04:00
Copyright ( C ) Michael Adam 2011 - 2012
2008-04-16 12:11:44 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 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 "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
2012-02-23 12:16:55 +04:00
# include "../libcli/smb/smbXcli_base.h"
2008-04-16 12:11:44 +04:00
# include "torture/torture.h"
# include "torture/smb2/proto.h"
2012-02-26 05:36:13 +04:00
# include "../libcli/smb/smbXcli_base.h"
2008-04-16 12:11:44 +04:00
# define CHECK_VAL(v, correct) do { \
if ( ( v ) ! = ( correct ) ) { \
2012-06-21 00:28:54 +04:00
torture_result ( tctx , TORTURE_FAIL , " (%s): wrong value for %s got 0x%llx - should be 0x%llx \n " , \
__location__ , # v , ( unsigned long long ) v , ( unsigned long long ) correct ) ; \
ret = false ; \
} } while ( 0 )
2015-06-17 04:21:28 +03:00
# define CHECK_NOT_VAL(v, incorrect) do { \
if ( ( v ) = = ( incorrect ) ) { \
2012-06-21 00:28:54 +04:00
torture_result ( tctx , TORTURE_FAIL , " (%s): wrong value for %s got 0x%llx - should not be 0x%llx \n " , \
2015-06-17 04:21:28 +03:00
__location__ , # v , ( unsigned long long ) v , ( unsigned long long ) incorrect ) ; \
2008-04-16 12:11:44 +04:00
ret = false ; \
} } while ( 0 )
2015-06-17 04:20:29 +03:00
# define CHECK_NOT_NULL(p) do { \
if ( ( p ) = = NULL ) { \
torture_result ( tctx , TORTURE_FAIL , " (%s): %s is NULL but it should not be. \n " , \
__location__ , # p ) ; \
ret = false ; \
} } while ( 0 )
2008-04-16 12:11:44 +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 )
2009-03-31 02:59:06 +04:00
# define CHECK_CREATED(__io, __created, __attribute) \
do { \
CHECK_VAL ( ( __io ) - > out . create_action , NTCREATEX_ACTION_ # # __created ) ; \
CHECK_VAL ( ( __io ) - > out . size , 0 ) ; \
CHECK_VAL ( ( __io ) - > out . file_attr , ( __attribute ) ) ; \
CHECK_VAL ( ( __io ) - > out . reserved2 , 0 ) ; \
} while ( 0 )
2012-09-07 02:53:38 +04:00
# define CHECK_CREATED_SIZE(__io, __created, __attribute, __alloc_size, __size) \
do { \
CHECK_VAL ( ( __io ) - > out . create_action , NTCREATEX_ACTION_ # # __created ) ; \
CHECK_VAL ( ( __io ) - > out . alloc_size , ( __alloc_size ) ) ; \
CHECK_VAL ( ( __io ) - > out . size , ( __size ) ) ; \
CHECK_VAL ( ( __io ) - > out . file_attr , ( __attribute ) ) ; \
CHECK_VAL ( ( __io ) - > out . reserved2 , 0 ) ; \
} while ( 0 )
2011-10-29 19:26:53 +04:00
/**
* basic durable_open test .
* durable state should only be granted when requested
* along with a batch oplock or a handle lease .
*
* This test tests durable open with all possible oplock types .
*/
struct durable_open_vs_oplock {
2011-11-08 19:34:51 +04:00
const char * level ;
2011-11-01 03:55:48 +04:00
const char * share_mode ;
2011-10-29 19:26:53 +04:00
bool expected ;
} ;
2011-11-01 03:55:48 +04:00
# define NUM_OPLOCK_TYPES 4
# define NUM_SHARE_MODES 8
# define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
2012-02-28 06:07:51 +04:00
static struct durable_open_vs_oplock durable_open_vs_oplock_table [ NUM_OPLOCK_OPEN_TESTS ] =
2011-10-29 19:26:53 +04:00
{
2011-11-08 19:34:51 +04:00
{ " " , " " , false } ,
{ " " , " R " , false } ,
{ " " , " W " , false } ,
{ " " , " D " , false } ,
{ " " , " RD " , false } ,
{ " " , " RW " , false } ,
{ " " , " WD " , false } ,
{ " " , " RWD " , false } ,
{ " s " , " " , false } ,
{ " s " , " R " , false } ,
{ " s " , " W " , false } ,
{ " s " , " D " , false } ,
{ " s " , " RD " , false } ,
{ " s " , " RW " , false } ,
{ " s " , " WD " , false } ,
{ " s " , " RWD " , false } ,
{ " x " , " " , false } ,
{ " x " , " R " , false } ,
{ " x " , " W " , false } ,
{ " x " , " D " , false } ,
{ " x " , " RD " , false } ,
{ " x " , " RW " , false } ,
{ " x " , " WD " , false } ,
{ " x " , " RWD " , false } ,
{ " b " , " " , true } ,
{ " b " , " R " , true } ,
{ " b " , " W " , true } ,
{ " b " , " D " , true } ,
{ " b " , " RD " , true } ,
{ " b " , " RW " , true } ,
{ " b " , " WD " , true } ,
{ " b " , " RWD " , true } ,
2011-10-29 19:26:53 +04:00
} ;
2012-03-01 02:19:59 +04:00
static bool test_one_durable_open_open_oplock ( struct torture_context * tctx ,
struct smb2_tree * tree ,
const char * fname ,
struct durable_open_vs_oplock test )
2011-10-29 19:26:53 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
bool ret = true ;
2011-11-08 21:31:17 +04:00
struct smb2_create io ;
2011-10-29 19:26:53 +04:00
smb2_util_unlink ( tree , fname ) ;
2011-11-08 21:31:17 +04:00
smb2_oplock_create_share ( & io , fname ,
smb2_util_share_access ( test . share_mode ) ,
smb2_util_oplock_level ( test . level ) ) ;
io . in . durable_open = true ;
2011-10-29 19:26:53 +04:00
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , test . expected ) ;
2011-11-08 19:34:51 +04:00
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( test . level ) ) ;
2011-10-29 19:26:53 +04:00
done :
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2013-02-13 00:51:06 +04:00
static bool test_durable_open_open_oplock ( struct torture_context * tctx ,
struct smb2_tree * tree )
2011-10-29 19:26:53 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
bool ret = true ;
int i ;
/* Choose a random name in case the state is left a little funky. */
2012-03-01 02:19:59 +04:00
snprintf ( fname , 256 , " durable_open_open_oplock_%s.dat " , generate_random_str ( tctx , 8 ) ) ;
2011-10-29 19:26:53 +04:00
smb2_util_unlink ( tree , fname ) ;
/* test various oplock levels with durable open */
for ( i = 0 ; i < NUM_OPLOCK_OPEN_TESTS ; i + + ) {
2012-03-01 02:19:59 +04:00
ret = test_one_durable_open_open_oplock ( tctx ,
tree ,
fname ,
durable_open_vs_oplock_table [ i ] ) ;
2011-10-29 19:26:53 +04:00
if ( ret = = false ) {
goto done ;
}
}
done :
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2011-10-29 19:28:38 +04:00
/**
* basic durable_open test .
* durable state should only be granted when requested
* along with a batch oplock or a handle lease .
*
* This test tests durable open with all valid lease types .
*/
struct durable_open_vs_lease {
const char * type ;
2011-11-01 03:56:29 +04:00
const char * share_mode ;
2011-10-29 19:28:38 +04:00
bool expected ;
} ;
2011-11-01 03:56:29 +04:00
# define NUM_LEASE_TYPES 5
# define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
2012-02-28 06:07:51 +04:00
static struct durable_open_vs_lease durable_open_vs_lease_table [ NUM_LEASE_OPEN_TESTS ] =
2011-10-29 19:28:38 +04:00
{
2011-11-01 03:56:29 +04:00
{ " " , " " , false } ,
{ " " , " R " , false } ,
{ " " , " W " , false } ,
{ " " , " D " , false } ,
{ " " , " RW " , false } ,
{ " " , " RD " , false } ,
{ " " , " WD " , false } ,
{ " " , " RWD " , false } ,
{ " R " , " " , false } ,
{ " R " , " R " , false } ,
{ " R " , " W " , false } ,
{ " R " , " D " , false } ,
{ " R " , " RW " , false } ,
{ " R " , " RD " , false } ,
{ " R " , " DW " , false } ,
{ " R " , " RWD " , false } ,
{ " RW " , " " , false } ,
{ " RW " , " R " , false } ,
{ " RW " , " W " , false } ,
{ " RW " , " D " , false } ,
{ " RW " , " RW " , false } ,
{ " RW " , " RD " , false } ,
{ " RW " , " WD " , false } ,
{ " RW " , " RWD " , false } ,
{ " RH " , " " , true } ,
{ " RH " , " R " , true } ,
{ " RH " , " W " , true } ,
{ " RH " , " D " , true } ,
{ " RH " , " RW " , true } ,
{ " RH " , " RD " , true } ,
{ " RH " , " WD " , true } ,
{ " RH " , " RWD " , true } ,
{ " RHW " , " " , true } ,
{ " RHW " , " R " , true } ,
{ " RHW " , " W " , true } ,
{ " RHW " , " D " , true } ,
{ " RHW " , " RW " , true } ,
{ " RHW " , " RD " , true } ,
{ " RHW " , " WD " , true } ,
{ " RHW " , " RWD " , true } ,
2011-10-29 19:28:38 +04:00
} ;
2012-03-01 02:19:59 +04:00
static bool test_one_durable_open_open_lease ( struct torture_context * tctx ,
struct smb2_tree * tree ,
const char * fname ,
struct durable_open_vs_lease test )
2011-10-29 19:28:38 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
bool ret = true ;
2011-11-08 21:39:45 +04:00
struct smb2_create io ;
2011-10-29 19:28:38 +04:00
struct smb2_lease ls ;
uint64_t lease ;
2012-02-23 12:16:55 +04:00
uint32_t caps ;
caps = smb2cli_conn_server_capabilities ( tree - > session - > transport - > conn ) ;
if ( ! ( caps & SMB2_CAP_LEASING ) ) {
torture_skip ( tctx , " leases are not supported " ) ;
}
2011-10-29 19:28:38 +04:00
smb2_util_unlink ( tree , fname ) ;
lease = random ( ) ;
2011-11-08 21:39:45 +04:00
smb2_lease_create_share ( & io , & ls , false /* dir */ , fname ,
smb2_util_share_access ( test . share_mode ) ,
lease ,
smb2_util_lease_state ( test . type ) ) ;
io . in . durable_open = true ;
2011-10-29 19:28:38 +04:00
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , test . expected ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 0 ] , lease ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 1 ] , ~ lease ) ;
2011-11-08 11:04:28 +04:00
CHECK_VAL ( io . out . lease_response . lease_state ,
smb2_util_lease_state ( test . type ) ) ;
2011-10-29 19:28:38 +04:00
done :
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2013-02-13 00:51:06 +04:00
static bool test_durable_open_open_lease ( struct torture_context * tctx ,
struct smb2_tree * tree )
2011-10-29 19:28:38 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
bool ret = true ;
int i ;
2012-02-23 12:16:55 +04:00
uint32_t caps ;
caps = smb2cli_conn_server_capabilities ( tree - > session - > transport - > conn ) ;
if ( ! ( caps & SMB2_CAP_LEASING ) ) {
torture_skip ( tctx , " leases are not supported " ) ;
}
2011-10-29 19:28:38 +04:00
/* Choose a random name in case the state is left a little funky. */
2012-03-01 02:19:59 +04:00
snprintf ( fname , 256 , " durable_open_open_lease_%s.dat " , generate_random_str ( tctx , 8 ) ) ;
2011-10-29 19:28:38 +04:00
smb2_util_unlink ( tree , fname ) ;
/* test various oplock levels with durable open */
for ( i = 0 ; i < NUM_LEASE_OPEN_TESTS ; i + + ) {
2012-03-01 02:19:59 +04:00
ret = test_one_durable_open_open_lease ( tctx ,
tree ,
fname ,
durable_open_vs_lease_table [ i ] ) ;
2011-10-29 19:28:38 +04:00
if ( ret = = false ) {
goto done ;
}
}
done :
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-01-27 16:03:08 +04:00
/**
* basic test for doing a durable open
* and do a durable reopen on the same connection
2012-02-19 03:10:37 +04:00
* while the first open is still active ( fails )
2012-01-27 16:03:08 +04:00
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_reopen1 ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-01-27 16:03:08 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io1 , io2 ;
bool ret = true ;
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen1_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io1 , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io1 . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io1 . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . durable_open , true ) ;
CHECK_VAL ( io1 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
/* try a durable reconnect while the file is still open */
ZERO_STRUCT ( io2 ) ;
io2 . in . fname = fname ;
io2 . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
done :
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2013-11-29 21:20:01 +04:00
/**
* Basic test for doing a durable open
* and do a session reconnect while the first
* session is still active and the handle is
* still open in the client .
* This closes the original session and a
* durable reconnect on the new session succeeds .
*/
static bool test_durable_open_reopen1a ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
2016-03-17 04:45:16 +03:00
struct smb2_create io ;
2013-11-29 21:20:01 +04:00
bool ret = true ;
struct smb2_tree * tree2 = NULL ;
2016-03-15 10:59:53 +03:00
struct smb2_tree * tree3 = NULL ;
2013-11-29 21:20:01 +04:00
uint64_t previous_session_id ;
struct smbcli_options options ;
2016-03-15 10:59:53 +03:00
struct GUID orig_client_guid ;
2013-11-29 21:20:01 +04:00
options = tree - > session - > transport - > options ;
2016-03-15 10:59:53 +03:00
orig_client_guid = options . client_guid ;
2013-11-29 21:20:01 +04:00
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen1a_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
2016-03-17 04:45:16 +03:00
smb2_oplock_create_share ( & io , fname ,
2013-11-29 21:20:01 +04:00
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
2016-03-17 04:45:16 +03:00
io . in . durable_open = true ;
2013-11-29 21:20:01 +04:00
2016-03-17 04:45:16 +03:00
status = smb2_create ( tree , mem_ctx , & io ) ;
2013-11-29 21:20:01 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2016-03-17 04:45:16 +03:00
_h = io . out . file . handle ;
2013-11-29 21:20:01 +04:00
h = & _h ;
2016-03-17 04:45:16 +03:00
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
2013-11-29 21:20:01 +04:00
/*
* a session reconnect on a second tcp connection
*/
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
2016-03-15 10:59:53 +03:00
/* for oplocks, the client guid can be different: */
options . client_guid = GUID_random ( ) ;
2016-03-15 11:35:03 +03:00
ret = torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree2 ) ;
torture_assert_goto ( tctx , ret , ret , done , " could not reconnect " ) ;
2013-11-29 21:20:01 +04:00
/*
* check that this has deleted the old session
*/
2016-03-17 04:45:16 +03:00
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
2013-11-29 21:20:01 +04:00
2016-03-17 04:45:16 +03:00
status = smb2_create ( tree , mem_ctx , & io ) ;
2013-11-29 21:20:01 +04:00
CHECK_STATUS ( status , NT_STATUS_USER_SESSION_DELETED ) ;
2016-03-05 00:55:40 +03:00
TALLOC_FREE ( tree ) ;
2013-11-29 21:20:01 +04:00
/*
* but a durable reconnect on the new session succeeds :
*/
2016-03-17 04:45:16 +03:00
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
2013-11-29 21:20:01 +04:00
2016-03-17 04:45:16 +03:00
status = smb2_create ( tree2 , mem_ctx , & io ) ;
2013-11-29 21:20:01 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2016-03-17 04:45:16 +03:00
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
2013-11-29 21:20:01 +04:00
h = & _h ;
2016-03-15 10:59:53 +03:00
/*
* a session reconnect on a second tcp connection
*/
previous_session_id = smb2cli_session_current_id ( tree2 - > session - > smbXcli ) ;
/* the original client_guid works just the same */
options . client_guid = orig_client_guid ;
ret = torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree3 ) ;
torture_assert_goto ( tctx , ret , ret , done , " could not reconnect " ) ;
/*
* check that this has deleted the old session
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
status = smb2_create ( tree2 , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_USER_SESSION_DELETED ) ;
TALLOC_FREE ( tree2 ) ;
/*
* but a durable reconnect on the new session succeeds :
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
status = smb2_create ( tree3 , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
h = & _h ;
2013-11-29 21:20:01 +04:00
done :
2016-03-05 00:55:40 +03:00
if ( tree = = NULL ) {
tree = tree2 ;
2013-11-29 21:20:01 +04:00
}
2016-03-15 10:59:53 +03:00
if ( tree = = NULL ) {
tree = tree3 ;
}
2016-03-05 00:55:40 +03:00
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
h = NULL ;
}
smb2_util_unlink ( tree , fname ) ;
2013-11-29 21:20:01 +04:00
2016-03-05 00:55:40 +03:00
talloc_free ( tree ) ;
}
2013-11-29 21:20:01 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2016-03-15 12:02:14 +03:00
/**
* lease variant of reopen1a
*
* Basic test for doing a durable open and doing a session
* reconnect while the first session is still active and the
* handle is still open in the client .
* This closes the original session and a durable reconnect on
* the new session succeeds depending on the client guid :
*
* Durable reconnect on a session with a different client guid fails .
* Durable reconnect on a session with the original client guid succeeds .
*/
bool test_durable_open_reopen1a_lease ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io ;
struct smb2_lease ls ;
uint64_t lease_key ;
bool ret = true ;
struct smb2_tree * tree2 = NULL ;
struct smb2_tree * tree3 = NULL ;
uint64_t previous_session_id ;
struct smbcli_options options ;
struct GUID orig_client_guid ;
options = tree - > session - > transport - > options ;
orig_client_guid = options . client_guid ;
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_v2_open_reopen1a_lease_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
lease_key = random ( ) ;
smb2_lease_create ( & io , & ls , false /* dir */ , fname ,
lease_key , smb2_util_lease_state ( " RWH " ) ) ;
io . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response . lease_duration , 0 ) ;
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
/*
* a session reconnect on a second tcp connection
* with a different client_guid does not allow
* the durable reconnect .
*/
options . client_guid = GUID_random ( ) ;
ret = torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree2 ) ;
torture_assert_goto ( tctx , ret , ret , done , " couldn't reconnect " ) ;
/*
* check that this has deleted the old session
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
io . in . lease_request = & ls ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_USER_SESSION_DELETED ) ;
TALLOC_FREE ( tree ) ;
/*
* but a durable reconnect on the new session with the wrong
* client guid fails
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
io . in . lease_request = & ls ;
status = smb2_create ( tree2 , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
/*
* now a session reconnect on a second tcp connection
* with original client_guid allows the durable reconnect .
*/
options . client_guid = orig_client_guid ;
ret = torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree3 ) ;
torture_assert_goto ( tctx , ret , ret , done , " couldn't reconnect " ) ;
/*
* check that this has deleted the old session
* In this case , a durable reconnect attempt with the
* correct client_guid yields a different error code .
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
io . in . lease_request = & ls ;
status = smb2_create ( tree2 , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
TALLOC_FREE ( tree2 ) ;
/*
* but a durable reconnect on the new session succeeds :
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
io . in . lease_request = & ls ;
status = smb2_create ( tree3 , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , false ) ; /* no dh response context... */
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response . lease_duration , 0 ) ;
_h = io . out . file . handle ;
h = & _h ;
done :
if ( tree = = NULL ) {
tree = tree2 ;
}
if ( tree = = NULL ) {
tree = tree3 ;
}
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
}
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-01-27 16:06:09 +04:00
/**
* basic test for doing a durable open
* tcp disconnect , reconnect , do a durable reopen ( succeeds )
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_reopen2 ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-01-27 16:06:09 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
2013-09-26 07:35:19 +04:00
struct smb2_create io ;
2012-01-27 16:06:09 +04:00
bool ret = true ;
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen2_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
2013-09-26 07:35:19 +04:00
smb2_oplock_create_share ( & io , fname ,
2012-01-27 16:06:09 +04:00
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
2013-09-26 07:35:19 +04:00
io . in . durable_open = true ;
2012-01-27 16:06:09 +04:00
2013-09-26 07:35:19 +04:00
status = smb2_create ( tree , mem_ctx , & io ) ;
2012-01-27 16:06:09 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2013-09-26 07:35:19 +04:00
_h = io . out . file . handle ;
2012-01-27 16:06:09 +04:00
h = & _h ;
2013-09-26 07:35:19 +04:00
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
2012-01-27 16:06:09 +04:00
2013-09-26 07:35:19 +04:00
/* disconnect, leaving the durable in place */
TALLOC_FREE ( tree ) ;
2012-01-27 16:06:09 +04:00
if ( ! torture_smb2_connection ( tctx , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
2013-09-26 07:35:19 +04:00
ZERO_STRUCT ( io ) ;
2012-09-06 14:38:54 +04:00
/* the path name is ignored by the server */
2013-09-26 07:35:19 +04:00
io . in . fname = fname ;
io . in . durable_handle = h ; /* durable v1 reconnect request */
2012-02-20 19:25:42 +04:00
h = NULL ;
2012-01-27 16:06:09 +04:00
2013-09-26 07:35:19 +04:00
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
h = & _h ;
/* disconnect again, leaving the durable in place */
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_connection ( tctx , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
/*
* show that the filename and many other fields
* are ignored . only the reconnect request blob
* is important .
*/
ZERO_STRUCT ( io ) ;
/* the path name is ignored by the server */
io . in . security_flags = 0x78 ;
io . in . oplock_level = 0x78 ;
io . in . impersonation_level = 0x12345678 ;
io . in . create_flags = 0x12345678 ;
io . in . reserved = 0x12345678 ;
io . in . desired_access = 0x12345678 ;
io . in . file_attributes = 0x12345678 ;
io . in . share_access = 0x12345678 ;
io . in . create_disposition = 0x12345678 ;
io . in . create_options = 0x12345678 ;
io . in . fname = " __non_existing_fname__ " ;
io . in . durable_handle = h ; /* durable v1 reconnect request */
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
2012-01-27 16:06:09 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2013-09-26 07:35:19 +04:00
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
h = & _h ;
/* disconnect, leaving the durable in place */
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_connection ( tctx , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
/*
* show that an additionally specified durable v1 request
* is ignored by the server .
* See MS - SMB2 , 3.3 .5 .9 .7
* Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context
*/
ZERO_STRUCT ( io ) ;
/* the path name is ignored by the server */
io . in . fname = fname ;
io . in . durable_handle = h ; /* durable v1 reconnect request */
io . in . durable_open = true ; /* durable v1 handle request */
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
2012-01-27 16:06:09 +04:00
h = & _h ;
done :
2013-02-13 17:58:29 +04:00
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
2012-01-27 16:06:09 +04:00
2013-02-13 17:58:29 +04:00
smb2_util_unlink ( tree , fname ) ;
2012-01-27 16:06:09 +04:00
2013-02-13 17:58:29 +04:00
talloc_free ( tree ) ;
}
2012-01-27 16:06:09 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2013-09-25 01:08:24 +04:00
/**
* lease variant of reopen2
* basic test for doing a durable open
* tcp disconnect , reconnect , do a durable reopen ( succeeds )
*/
static bool test_durable_open_reopen2_lease ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io ;
struct smb2_lease ls ;
uint64_t lease_key ;
bool ret = true ;
struct smbcli_options options ;
uint32_t caps ;
caps = smb2cli_conn_server_capabilities ( tree - > session - > transport - > conn ) ;
if ( ! ( caps & SMB2_CAP_LEASING ) ) {
torture_skip ( tctx , " leases are not supported " ) ;
}
options = tree - > session - > transport - > options ;
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen2_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
lease_key = random ( ) ;
smb2_lease_create ( & io , & ls , false /* dir */ , fname , lease_key ,
smb2_util_lease_state ( " RWH " ) ) ;
io . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response . lease_duration , 0 ) ;
/* disconnect, reconnect and then do durable reopen */
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_connection_ext ( tctx , 0 , & options , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
/* a few failure tests: */
/*
* several attempts without lease attached :
* all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
* irrespective of file name provided
*/
ZERO_STRUCT ( io ) ;
io . in . fname = " " ;
io . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
ZERO_STRUCT ( io ) ;
io . in . fname = " __non_existing_fname__ " ;
io . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
/*
* attempt with lease provided , but
* with a changed lease key . = > fails
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_open = false ;
io . in . durable_handle = h ;
io . in . lease_request = & ls ;
io . in . oplock_level = SMB2_OPLOCK_LEVEL_LEASE ;
/* a wrong lease key lets the request fail */
ls . lease_key . data [ 0 ] + + ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
/* restore the correct lease key */
ls . lease_key . data [ 0 ] - - ;
/*
* this last failing attempt is almost correct :
* only problem is : we use the wrong filename . . .
* Note that this gives INVALID_PARAMETER .
* This is different from oplocks !
*/
ZERO_STRUCT ( io ) ;
io . in . fname = " __non_existing_fname__ " ;
io . in . durable_open = false ;
io . in . durable_handle = h ;
io . in . lease_request = & ls ;
io . in . oplock_level = SMB2_OPLOCK_LEVEL_LEASE ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_INVALID_PARAMETER ) ;
/*
* Now for a succeeding reconnect :
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_open = false ;
io . in . durable_handle = h ;
io . in . lease_request = & ls ;
io . in . oplock_level = SMB2_OPLOCK_LEVEL_LEASE ;
/* the requested lease state is irrelevant */
ls . lease_state = smb2_util_lease_state ( " " ) ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , false ) ;
CHECK_VAL ( io . out . durable_open_v2 , false ) ; /* no dh2q response blob */
CHECK_VAL ( io . out . persistent_open , false ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response . lease_duration , 0 ) ;
_h = io . out . file . handle ;
h = & _h ;
/* disconnect one more time */
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_connection_ext ( tctx , 0 , & options , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
/*
* demonstrate that various parameters are ignored
* in the reconnect
*/
ZERO_STRUCT ( io ) ;
/*
* These are completely ignored by the server
*/
io . in . security_flags = 0x78 ;
io . in . oplock_level = 0x78 ;
io . in . impersonation_level = 0x12345678 ;
io . in . create_flags = 0x12345678 ;
io . in . reserved = 0x12345678 ;
io . in . desired_access = 0x12345678 ;
io . in . file_attributes = 0x12345678 ;
io . in . share_access = 0x12345678 ;
io . in . create_disposition = 0x12345678 ;
io . in . create_options = 0x12345678 ;
/*
* only these are checked :
* - io . in . fname
* - io . in . durable_handle ,
* - io . in . lease_request - > lease_key
*/
io . in . fname = fname ;
io . in . durable_open_v2 = false ;
io . in . durable_handle_v2 = h ;
io . in . lease_request = & ls ;
/* the requested lease state is irrelevant */
ls . lease_state = smb2_util_lease_state ( " " ) ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , false ) ;
CHECK_VAL ( io . out . durable_open_v2 , false ) ; /* no dh2q response blob */
CHECK_VAL ( io . out . persistent_open , false ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response . lease_duration , 0 ) ;
_h = io . out . file . handle ;
h = & _h ;
done :
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
}
talloc_free ( mem_ctx ) ;
return ret ;
}
2013-09-25 20:31:10 +04:00
/**
* lease v2 variant of reopen2
* basic test for doing a durable open
* tcp disconnect , reconnect , do a durable reopen ( succeeds )
*/
static bool test_durable_open_reopen2_lease_v2 ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io ;
struct smb2_lease ls ;
uint64_t lease_key ;
bool ret = true ;
struct smbcli_options options ;
uint32_t caps ;
caps = smb2cli_conn_server_capabilities ( tree - > session - > transport - > conn ) ;
if ( ! ( caps & SMB2_CAP_LEASING ) ) {
torture_skip ( tctx , " leases are not supported " ) ;
}
options = tree - > session - > transport - > options ;
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen2_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
lease_key = random ( ) ;
smb2_lease_v2_create ( & io , & ls , false /* dir */ , fname ,
lease_key , 0 , /* parent lease key */
smb2_util_lease_state ( " RWH " ) , 0 /* lease epoch */ ) ;
io . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_duration , 0 ) ;
/* disconnect, reconnect and then do durable reopen */
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_connection_ext ( tctx , 0 , & options , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
/* a few failure tests: */
/*
* several attempts without lease attached :
* all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
* irrespective of file name provided
*/
ZERO_STRUCT ( io ) ;
io . in . fname = " " ;
io . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
ZERO_STRUCT ( io ) ;
io . in . fname = " __non_existing_fname__ " ;
io . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
/*
* attempt with lease provided , but
* with a changed lease key . = > fails
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_open = false ;
io . in . durable_handle = h ;
io . in . lease_request_v2 = & ls ;
io . in . oplock_level = SMB2_OPLOCK_LEVEL_LEASE ;
/* a wrong lease key lets the request fail */
ls . lease_key . data [ 0 ] + + ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
/* restore the correct lease key */
ls . lease_key . data [ 0 ] - - ;
/*
* this last failing attempt is almost correct :
* only problem is : we use the wrong filename . . .
* Note that this gives INVALID_PARAMETER .
* This is different from oplocks !
*/
ZERO_STRUCT ( io ) ;
io . in . fname = " __non_existing_fname__ " ;
io . in . durable_open = false ;
io . in . durable_handle = h ;
io . in . lease_request_v2 = & ls ;
io . in . oplock_level = SMB2_OPLOCK_LEVEL_LEASE ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_INVALID_PARAMETER ) ;
/*
* Now for a succeeding reconnect :
*/
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_open = false ;
io . in . durable_handle = h ;
io . in . lease_request_v2 = & ls ;
io . in . oplock_level = SMB2_OPLOCK_LEVEL_LEASE ;
/* the requested lease state is irrelevant */
ls . lease_state = smb2_util_lease_state ( " " ) ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , false ) ;
CHECK_VAL ( io . out . durable_open_v2 , false ) ; /* no dh2q response blob */
CHECK_VAL ( io . out . persistent_open , false ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_duration , 0 ) ;
_h = io . out . file . handle ;
h = & _h ;
/* disconnect one more time */
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_connection_ext ( tctx , 0 , & options , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
/*
* demonstrate that various parameters are ignored
* in the reconnect
*/
ZERO_STRUCT ( io ) ;
/*
* These are completely ignored by the server
*/
io . in . security_flags = 0x78 ;
io . in . oplock_level = 0x78 ;
io . in . impersonation_level = 0x12345678 ;
io . in . create_flags = 0x12345678 ;
io . in . reserved = 0x12345678 ;
io . in . desired_access = 0x12345678 ;
io . in . file_attributes = 0x12345678 ;
io . in . share_access = 0x12345678 ;
io . in . create_disposition = 0x12345678 ;
io . in . create_options = 0x12345678 ;
/*
* only these are checked :
* - io . in . fname
* - io . in . durable_handle ,
* - io . in . lease_request - > lease_key
*/
io . in . fname = fname ;
io . in . durable_open_v2 = false ;
io . in . durable_handle_v2 = h ;
io . in . lease_request_v2 = & ls ;
/* the requested lease state is irrelevant */
ls . lease_state = smb2_util_lease_state ( " " ) ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , false ) ;
CHECK_VAL ( io . out . durable_open_v2 , false ) ; /* no dh2q response blob */
CHECK_VAL ( io . out . persistent_open , false ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_key . data [ 0 ] , lease_key ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_key . data [ 1 ] , ~ lease_key ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_state ,
smb2_util_lease_state ( " RWH " ) ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_flags , 0 ) ;
CHECK_VAL ( io . out . lease_response_v2 . lease_duration , 0 ) ;
_h = io . out . file . handle ;
h = & _h ;
done :
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
}
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-02-26 05:36:13 +04:00
/**
* basic test for doing a durable open
* tcp disconnect , reconnect with a session reconnect and
* do a durable reopen ( succeeds )
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_reopen2a ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-02-26 05:36:13 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io1 , io2 ;
uint64_t previous_session_id ;
bool ret = true ;
2013-09-25 09:20:30 +04:00
struct smbcli_options options ;
options = tree - > session - > transport - > options ;
2012-02-26 05:36:13 +04:00
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen2_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io1 , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io1 . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io1 . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . durable_open , true ) ;
CHECK_VAL ( io1 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
/* disconnect, reconnect and then do durable reopen */
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
talloc_free ( tree ) ;
tree = NULL ;
2013-09-25 09:20:30 +04:00
if ( ! torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree ) )
{
2012-02-26 05:36:13 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io2 ) ;
io2 . in . fname = fname ;
io2 . in . durable_handle = h ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED ( & io2 , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io2 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io2 . out . file . handle ;
h = & _h ;
done :
2013-02-13 18:00:26 +04:00
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
2012-02-26 05:36:13 +04:00
2013-02-13 18:00:26 +04:00
smb2_util_unlink ( tree , fname ) ;
2012-02-26 05:36:13 +04:00
2013-02-13 18:00:26 +04:00
talloc_free ( tree ) ;
}
2012-02-26 05:36:13 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-01-27 20:21:25 +04:00
/**
* basic test for doing a durable open :
* tdis , new tcon , try durable reopen ( fails )
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_reopen3 ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-01-27 20:21:25 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io1 , io2 ;
bool ret = true ;
struct smb2_tree * tree2 ;
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen3_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io1 , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io1 . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io1 . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . durable_open , true ) ;
CHECK_VAL ( io1 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
/* disconnect, reconnect and then do durable reopen */
status = smb2_tdis ( tree ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
if ( ! torture_smb2_tree_connect ( tctx , tree - > session , mem_ctx , & tree2 ) ) {
torture_warning ( tctx , " couldn't reconnect to share, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io2 ) ;
io2 . in . fname = fname ;
io2 . in . durable_handle = h ;
status = smb2_create ( tree2 , mem_ctx , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
done :
2013-02-13 18:01:47 +04:00
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
2012-01-27 20:21:25 +04:00
2013-02-13 18:01:47 +04:00
smb2_util_unlink ( tree2 , fname ) ;
2012-01-27 20:21:25 +04:00
2013-02-13 18:01:47 +04:00
talloc_free ( tree ) ;
}
2012-01-27 20:21:25 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-01-30 15:08:38 +04:00
/**
* basic test for doing a durable open :
* logoff , create a new session , do a durable reopen ( succeeds )
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_reopen4 ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-01-30 15:08:38 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io1 , io2 ;
bool ret = true ;
struct smb2_transport * transport ;
2012-02-24 02:43:18 +04:00
struct smb2_session * session2 ;
2012-01-30 15:08:38 +04:00
struct smb2_tree * tree2 ;
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_reopen4_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io1 , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io1 . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io1 . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . durable_open , true ) ;
CHECK_VAL ( io1 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
2012-02-24 02:25:18 +04:00
/*
* do a session logoff , establish a new session and tree
* connect on the same transport , and try a durable reopen
*/
2012-01-30 15:08:38 +04:00
transport = tree - > session - > transport ;
status = smb2_logoff ( tree - > session ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2012-02-26 04:36:51 +04:00
if ( ! torture_smb2_session_setup ( tctx , transport ,
0 , /* previous_session_id */
mem_ctx , & session2 ) )
{
2012-01-30 15:08:38 +04:00
torture_warning ( tctx , " session setup failed. \n " ) ;
ret = false ;
goto done ;
}
2012-02-24 02:43:18 +04:00
/*
* the session setup has talloc - stolen the transport ,
* so we can safely free the old tree + session for clarity
*/
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_tree_connect ( tctx , session2 , mem_ctx , & tree2 ) ) {
2012-01-30 15:08:38 +04:00
torture_warning ( tctx , " tree connect failed. \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io2 ) ;
io2 . in . fname = fname ;
io2 . in . durable_handle = h ;
2012-02-23 18:49:51 +04:00
h = NULL ;
2012-01-30 15:08:38 +04:00
status = smb2_create ( tree2 , mem_ctx , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io2 . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io2 , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io2 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
done :
2013-02-13 18:03:00 +04:00
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree2 , * h ) ;
}
2012-01-30 15:08:38 +04:00
2013-02-13 18:03:00 +04:00
smb2_util_unlink ( tree2 , fname ) ;
2012-01-30 15:08:38 +04:00
2013-02-13 18:03:00 +04:00
talloc_free ( tree ) ;
}
2012-01-30 15:08:38 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2013-02-13 00:51:06 +04:00
static bool test_durable_open_delete_on_close1 ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-06-21 00:28:54 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
2012-09-11 15:43:17 +04:00
struct smb2_create io1 , io2 ;
2012-06-21 00:28:54 +04:00
bool ret = true ;
2012-09-11 15:43:17 +04:00
uint8_t b = 0 ;
2012-06-21 00:28:54 +04:00
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_delete_on_close1_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io1 , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io1 . in . durable_open = true ;
io1 . in . create_options | = NTCREATEX_OPTIONS_DELETE_ON_CLOSE ;
status = smb2_create ( tree , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io1 . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . durable_open , true ) ;
CHECK_VAL ( io1 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
2012-09-11 15:43:17 +04:00
status = smb2_util_write ( tree , * h , & b , 0 , 1 ) ;
2012-06-21 00:28:54 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2012-09-11 15:43:17 +04:00
/* disconnect, leaving the durable handle in place */
TALLOC_FREE ( tree ) ;
2012-06-21 00:28:54 +04:00
2012-09-11 15:43:17 +04:00
if ( ! torture_smb2_connection ( tctx , & tree ) ) {
torture_warning ( tctx , " could not reconnect, bailing \n " ) ;
2012-06-21 00:28:54 +04:00
ret = false ;
goto done ;
}
/*
2012-09-11 15:43:17 +04:00
* Open the file on the new connection again
* and check that it has been newly created ,
* i . e . delete on close was effective on the disconnected handle .
* Also check that the file is really empty ,
* the previously written byte gone .
2012-06-21 00:28:54 +04:00
*/
smb2_oplock_create_share ( & io2 , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io2 . in . create_options | = NTCREATEX_OPTIONS_DELETE_ON_CLOSE ;
2012-09-11 15:43:17 +04:00
status = smb2_create ( tree , mem_ctx , & io2 ) ;
2012-06-21 00:28:54 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io2 . out . file . handle ;
h = & _h ;
2012-09-11 15:43:17 +04:00
CHECK_CREATED_SIZE ( & io2 , CREATED , FILE_ATTRIBUTE_ARCHIVE , 0 , 0 ) ;
2012-06-21 00:28:54 +04:00
CHECK_VAL ( io2 . out . durable_open , false ) ;
CHECK_VAL ( io2 . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
done :
2013-02-13 18:04:10 +04:00
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
2012-06-21 00:28:54 +04:00
2013-02-13 18:04:10 +04:00
smb2_util_unlink ( tree , fname ) ;
2012-06-21 00:28:54 +04:00
2013-02-13 18:04:10 +04:00
talloc_free ( tree ) ;
}
2012-06-21 00:28:54 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-09-11 16:08:28 +04:00
2013-02-13 00:51:06 +04:00
static bool test_durable_open_delete_on_close2 ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-09-11 16:08:28 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io ;
bool ret = true ;
uint8_t b = 0 ;
uint64_t previous_session_id ;
uint64_t alloc_size_step ;
2013-09-25 09:20:30 +04:00
struct smbcli_options options ;
options = tree - > session - > transport - > options ;
2012-09-11 16:08:28 +04:00
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_delete_on_close2_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io . in . durable_open = true ;
io . in . create_options | = NTCREATEX_OPTIONS_DELETE_ON_CLOSE ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
status = smb2_util_write ( tree , * h , & b , 0 , 1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
/* disconnect, leaving the durable handle in place */
TALLOC_FREE ( tree ) ;
2013-09-25 09:20:30 +04:00
if ( ! torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree ) )
{
2012-09-11 16:08:28 +04:00
torture_warning ( tctx , " could not reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
alloc_size_step = io . out . alloc_size ;
CHECK_CREATED_SIZE ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE , alloc_size_step , 1 ) ;
CHECK_VAL ( io . out . durable_open , false ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
/* close the file, thereby deleting it */
smb2_util_close ( tree , * h ) ;
status = smb2_logoff ( tree - > session ) ;
TALLOC_FREE ( tree ) ;
if ( ! torture_smb2_connection ( tctx , & tree ) ) {
torture_warning ( tctx , " could not reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
/*
* Open the file on the new connection again
* and check that it has been newly created ,
* i . e . delete on close was effective on the reconnected handle .
* Also check that the file is really empty ,
* the previously written byte gone .
*/
smb2_oplock_create_share ( & io , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io . in . durable_open = true ;
io . in . create_options | = NTCREATEX_OPTIONS_DELETE_ON_CLOSE ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED_SIZE ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE , 0 , 0 ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
done :
2013-02-13 18:05:40 +04:00
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
2012-09-11 16:08:28 +04:00
2013-02-13 18:05:40 +04:00
smb2_util_unlink ( tree , fname ) ;
2012-09-11 16:08:28 +04:00
2013-02-13 18:05:40 +04:00
talloc_free ( tree ) ;
}
2012-09-11 16:08:28 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2009-03-26 19:32:50 +03:00
/*
basic testing of SMB2 durable opens
2008-04-16 12:11:44 +04:00
regarding the position information on the handle
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_file_position ( struct torture_context * tctx ,
struct smb2_tree * tree )
2008-04-16 12:11:44 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
2012-09-07 19:36:56 +04:00
struct smb2_handle h ;
struct smb2_create io ;
2008-04-16 12:11:44 +04:00
NTSTATUS status ;
2009-03-26 23:35:39 +03:00
const char * fname = " durable_open_position.dat " ;
2008-04-16 12:11:44 +04:00
union smb_fileinfo qfinfo ;
union smb_setfileinfo sfinfo ;
bool ret = true ;
2008-04-17 05:52:45 +04:00
uint64_t pos ;
2012-09-07 19:23:46 +04:00
uint64_t previous_session_id ;
2013-09-25 09:20:30 +04:00
struct smbcli_options options ;
options = tree - > session - > transport - > options ;
2008-04-17 05:52:45 +04:00
2012-09-07 19:23:46 +04:00
smb2_util_unlink ( tree , fname ) ;
2008-04-17 05:52:45 +04:00
2012-09-07 19:36:56 +04:00
smb2_oplock_create ( & io , fname , SMB2_OPLOCK_LEVEL_BATCH ) ;
io . in . durable_open = true ;
2008-04-16 12:11:44 +04:00
2012-09-07 19:36:56 +04:00
status = smb2_create ( tree , mem_ctx , & io ) ;
2008-04-16 12:11:44 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2012-09-07 19:36:56 +04:00
h = io . out . file . handle ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_BATCH ) ;
2008-04-17 05:52:45 +04:00
/* TODO: check extra blob content */
2008-04-16 12:11:44 +04:00
ZERO_STRUCT ( qfinfo ) ;
qfinfo . generic . level = RAW_FILEINFO_POSITION_INFORMATION ;
2012-09-07 19:36:56 +04:00
qfinfo . generic . in . file . handle = h ;
2012-09-07 19:23:46 +04:00
status = smb2_getinfo_file ( tree , mem_ctx , & qfinfo ) ;
2008-04-16 12:11:44 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_VAL ( qfinfo . position_information . out . position , 0 ) ;
2008-04-17 05:52:45 +04:00
pos = qfinfo . position_information . out . position ;
torture_comment ( tctx , " position: %llu \n " ,
( unsigned long long ) pos ) ;
2008-04-16 12:11:44 +04:00
ZERO_STRUCT ( sfinfo ) ;
sfinfo . generic . level = RAW_SFILEINFO_POSITION_INFORMATION ;
2012-09-07 19:36:56 +04:00
sfinfo . generic . in . file . handle = h ;
2008-04-16 12:11:44 +04:00
sfinfo . position_information . in . position = 0x1000 ;
2012-09-07 19:23:46 +04:00
status = smb2_setinfo_file ( tree , & sfinfo ) ;
2008-04-16 12:11:44 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
ZERO_STRUCT ( qfinfo ) ;
qfinfo . generic . level = RAW_FILEINFO_POSITION_INFORMATION ;
2012-09-07 19:36:56 +04:00
qfinfo . generic . in . file . handle = h ;
2012-09-07 19:23:46 +04:00
status = smb2_getinfo_file ( tree , mem_ctx , & qfinfo ) ;
2008-04-16 12:11:44 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_VAL ( qfinfo . position_information . out . position , 0x1000 ) ;
2008-04-17 05:52:45 +04:00
pos = qfinfo . position_information . out . position ;
torture_comment ( tctx , " position: %llu \n " ,
( unsigned long long ) pos ) ;
2008-04-16 12:11:44 +04:00
2012-09-07 19:23:46 +04:00
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
/* tcp disconnect */
talloc_free ( tree ) ;
tree = NULL ;
/* do a session reconnect */
2013-09-25 09:20:30 +04:00
if ( ! torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree ) )
{
2012-09-07 19:23:46 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
2008-04-16 12:11:44 +04:00
ZERO_STRUCT ( qfinfo ) ;
qfinfo . generic . level = RAW_FILEINFO_POSITION_INFORMATION ;
2012-09-07 19:36:56 +04:00
qfinfo . generic . in . file . handle = h ;
2012-09-07 19:23:46 +04:00
status = smb2_getinfo_file ( tree , mem_ctx , & qfinfo ) ;
2008-04-16 12:11:44 +04:00
CHECK_STATUS ( status , NT_STATUS_FILE_CLOSED ) ;
2012-09-07 19:36:56 +04:00
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = & h ;
2008-04-16 12:11:44 +04:00
2012-09-07 19:36:56 +04:00
status = smb2_create ( tree , mem_ctx , & io ) ;
2008-04-16 12:11:44 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2012-09-07 19:36:56 +04:00
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_BATCH ) ;
CHECK_VAL ( io . out . reserved , 0x00 ) ;
CHECK_VAL ( io . out . create_action , NTCREATEX_ACTION_EXISTED ) ;
CHECK_VAL ( io . out . alloc_size , 0 ) ;
CHECK_VAL ( io . out . size , 0 ) ;
CHECK_VAL ( io . out . file_attr , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . reserved2 , 0 ) ;
2008-04-16 12:11:44 +04:00
2012-09-07 19:36:56 +04:00
h = io . out . file . handle ;
2008-04-16 12:11:44 +04:00
ZERO_STRUCT ( qfinfo ) ;
qfinfo . generic . level = RAW_FILEINFO_POSITION_INFORMATION ;
2012-09-07 19:36:56 +04:00
qfinfo . generic . in . file . handle = h ;
2012-09-07 19:23:46 +04:00
status = smb2_getinfo_file ( tree , mem_ctx , & qfinfo ) ;
2008-04-16 12:11:44 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_VAL ( qfinfo . position_information . out . position , 0x1000 ) ;
2008-04-17 05:52:45 +04:00
pos = qfinfo . position_information . out . position ;
torture_comment ( tctx , " position: %llu \n " ,
( unsigned long long ) pos ) ;
2008-04-16 12:11:44 +04:00
2012-09-07 19:36:56 +04:00
smb2_util_close ( tree , h ) ;
2008-04-19 04:06:44 +04:00
2008-04-16 12:11:44 +04:00
talloc_free ( mem_ctx ) ;
2012-09-07 19:23:46 +04:00
smb2_util_unlink ( tree , fname ) ;
2008-04-16 12:11:44 +04:00
done :
2012-09-07 19:23:46 +04:00
talloc_free ( tree ) ;
2011-10-28 02:11:08 +04:00
2008-04-16 12:11:44 +04:00
return ret ;
}
2009-03-26 19:32:50 +03:00
2009-03-26 23:35:39 +03:00
/*
Open , disconnect , oplock break , reconnect .
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_oplock ( struct torture_context * tctx ,
struct smb2_tree * tree1 ,
struct smb2_tree * tree2 )
2009-03-26 23:35:39 +03:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
2009-03-27 15:25:26 +03:00
struct smb2_create io1 , io2 ;
2016-10-19 11:27:14 +03:00
struct smb2_handle h1 = { { 0 } } ;
struct smb2_handle h2 = { { 0 } } ;
2009-03-26 23:35:39 +03:00
NTSTATUS status ;
2009-03-31 02:59:06 +04:00
char fname [ 256 ] ;
2009-03-26 23:35:39 +03:00
bool ret = true ;
2009-03-31 02:59:06 +04:00
/* Choose a random name in case the state is left a little funky. */
2011-11-01 17:55:37 +04:00
snprintf ( fname , 256 , " durable_open_oplock_%s.dat " , generate_random_str ( tctx , 8 ) ) ;
2009-03-31 02:59:06 +04:00
2009-03-26 23:35:39 +03:00
/* Clean slate */
smb2_util_unlink ( tree1 , fname ) ;
/* Create with batch oplock */
2011-11-08 21:48:25 +04:00
smb2_oplock_create ( & io1 , fname , SMB2_OPLOCK_LEVEL_BATCH ) ;
io1 . in . durable_open = true ;
2009-03-26 23:35:39 +03:00
io2 = io1 ;
2011-11-08 21:48:25 +04:00
io2 . in . create_disposition = NTCREATEX_DISP_OPEN ;
2009-03-26 23:35:39 +03:00
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h1 = io1 . out . file . handle ;
2009-03-31 02:59:06 +04:00
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
2011-10-29 19:25:00 +04:00
CHECK_VAL ( io1 . out . durable_open , true ) ;
2009-03-31 02:59:06 +04:00
CHECK_VAL ( io1 . out . oplock_level , SMB2_OPLOCK_LEVEL_BATCH ) ;
2009-03-26 23:35:39 +03:00
/* Disconnect after getting the batch */
talloc_free ( tree1 ) ;
tree1 = NULL ;
/*
* Windows7 ( build 7000 ) will break a batch oplock immediately if the
* original client is gone . ( ZML : This seems like a bug . It should give
* some time for the client to reconnect ! )
*/
status = smb2_create ( tree2 , mem_ctx , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2009-03-31 02:59:06 +04:00
h2 = io2 . out . file . handle ;
CHECK_CREATED ( & io2 , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
2011-10-29 19:25:00 +04:00
CHECK_VAL ( io2 . out . durable_open , true ) ;
2009-03-26 23:35:39 +03:00
CHECK_VAL ( io2 . out . oplock_level , SMB2_OPLOCK_LEVEL_BATCH ) ;
/* What if tree1 tries to come back and reclaim? */
if ( ! torture_smb2_connection ( tctx , & tree1 ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
2009-03-31 02:59:06 +04:00
ZERO_STRUCT ( io1 ) ;
io1 . in . fname = fname ;
io1 . in . durable_handle = & h1 ;
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
done :
smb2_util_close ( tree2 , h2 ) ;
smb2_util_unlink ( tree2 , fname ) ;
2011-10-28 02:11:08 +04:00
talloc_free ( tree1 ) ;
talloc_free ( tree2 ) ;
2009-03-31 02:59:06 +04:00
return ret ;
}
/*
Open , disconnect , lease break , reconnect .
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_lease ( struct torture_context * tctx ,
struct smb2_tree * tree1 ,
struct smb2_tree * tree2 )
2009-03-31 02:59:06 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_create io1 , io2 ;
struct smb2_lease ls1 , ls2 ;
2016-10-19 11:27:14 +03:00
struct smb2_handle h1 = { { 0 } } ;
struct smb2_handle h2 = { { 0 } } ;
2009-03-31 02:59:06 +04:00
NTSTATUS status ;
char fname [ 256 ] ;
bool ret = true ;
uint64_t lease1 , lease2 ;
2012-02-23 12:16:55 +04:00
uint32_t caps ;
caps = smb2cli_conn_server_capabilities ( tree1 - > session - > transport - > conn ) ;
if ( ! ( caps & SMB2_CAP_LEASING ) ) {
torture_skip ( tctx , " leases are not supported " ) ;
}
2009-03-31 02:59:06 +04:00
/*
* Choose a random name and random lease in case the state is left a
* little funky .
*/
lease1 = random ( ) ;
lease2 = random ( ) ;
snprintf ( fname , 256 , " durable_open_lease_%s.dat " , generate_random_str ( tctx , 8 ) ) ;
/* Clean slate */
smb2_util_unlink ( tree1 , fname ) ;
2009-03-26 23:35:39 +03:00
2009-03-31 02:59:06 +04:00
/* Create with lease */
2011-11-09 00:59:18 +04:00
smb2_lease_create ( & io1 , & ls1 , false /* dir */ , fname ,
lease1 , smb2_util_lease_state ( " RHW " ) ) ;
io1 . in . durable_open = true ;
2009-03-31 02:59:06 +04:00
2011-11-09 00:59:18 +04:00
smb2_lease_create ( & io2 , & ls2 , false /* dir */ , fname ,
lease2 , smb2_util_lease_state ( " RHW " ) ) ;
io2 . in . durable_open = true ;
2009-03-31 02:59:06 +04:00
io2 . in . create_disposition = NTCREATEX_DISP_OPEN ;
2009-03-26 23:35:39 +03:00
2009-03-31 02:59:06 +04:00
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
2009-03-26 23:35:39 +03:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
2009-03-31 02:59:06 +04:00
h1 = io1 . out . file . handle ;
2011-10-29 19:25:00 +04:00
CHECK_VAL ( io1 . out . durable_open , true ) ;
2009-03-31 02:59:06 +04:00
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io1 . out . lease_response . lease_key . data [ 0 ] , lease1 ) ;
CHECK_VAL ( io1 . out . lease_response . lease_key . data [ 1 ] , ~ lease1 ) ;
CHECK_VAL ( io1 . out . lease_response . lease_state ,
SMB2_LEASE_READ | SMB2_LEASE_HANDLE | SMB2_LEASE_WRITE ) ;
/* Disconnect after getting the lease */
talloc_free ( tree1 ) ;
tree1 = NULL ;
2009-03-26 23:35:39 +03:00
2009-03-31 02:59:06 +04:00
/*
* Windows7 ( build 7000 ) will grant an RH lease immediate ( not an RHW ? )
* even if the original client is gone . ( ZML : This seems like a bug . It
* should give some time for the client to reconnect ! And why RH ? )
2011-10-30 21:40:00 +04:00
*
* obnox : Current windows 7 and w2k8r2 grant RHW instead of RH .
* Test is adapted accordingly .
2009-03-31 02:59:06 +04:00
*/
2009-03-26 23:35:39 +03:00
status = smb2_create ( tree2 , mem_ctx , & io2 ) ;
2009-03-31 02:59:06 +04:00
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h2 = io2 . out . file . handle ;
2011-10-29 19:25:00 +04:00
CHECK_VAL ( io2 . out . durable_open , true ) ;
2009-03-31 02:59:06 +04:00
CHECK_CREATED ( & io2 , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io2 . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io2 . out . lease_response . lease_key . data [ 0 ] , lease2 ) ;
CHECK_VAL ( io2 . out . lease_response . lease_key . data [ 1 ] , ~ lease2 ) ;
CHECK_VAL ( io2 . out . lease_response . lease_state ,
2011-10-29 13:56:48 +04:00
SMB2_LEASE_READ | SMB2_LEASE_HANDLE | SMB2_LEASE_WRITE ) ;
2009-03-31 02:59:06 +04:00
/* What if tree1 tries to come back and reclaim? */
if ( ! torture_smb2_connection ( tctx , & tree1 ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io1 ) ;
io1 . in . fname = fname ;
io1 . in . durable_handle = & h1 ;
io1 . in . lease_request = & ls1 ;
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
2009-03-26 23:35:39 +03:00
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
2009-03-31 02:59:06 +04:00
done :
smb2_util_close ( tree2 , h2 ) ;
smb2_util_unlink ( tree2 , fname ) ;
2011-10-28 02:11:08 +04:00
talloc_free ( tree1 ) ;
talloc_free ( tree2 ) ;
2009-03-26 23:35:39 +03:00
return ret ;
2009-03-31 02:59:06 +04:00
}
2009-03-26 23:35:39 +03:00
2013-02-13 00:51:06 +04:00
static bool test_durable_open_lock_oplock ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-06-22 02:28:26 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_create io ;
2016-10-19 11:27:14 +03:00
struct smb2_handle h = { { 0 } } ;
2012-06-22 02:28:26 +04:00
struct smb2_lock lck ;
struct smb2_lock_element el [ 2 ] ;
NTSTATUS status ;
char fname [ 256 ] ;
bool ret = true ;
/*
*/
snprintf ( fname , 256 , " durable_open_oplock_lock_%s.dat " , generate_random_str ( tctx , 8 ) ) ;
/* Clean slate */
smb2_util_unlink ( tree , fname ) ;
2013-09-24 00:55:55 +04:00
/* Create with oplock */
2012-06-22 02:28:26 +04:00
smb2_oplock_create_share ( & io , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h = io . out . file . handle ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
ZERO_STRUCT ( lck ) ;
ZERO_STRUCT ( el ) ;
lck . in . locks = el ;
lck . in . lock_count = 0x0001 ;
lck . in . lock_sequence = 0x00000000 ;
lck . in . file . handle = h ;
el [ 0 ] . offset = 0 ;
el [ 0 ] . length = 1 ;
el [ 0 ] . reserved = 0x00000000 ;
el [ 0 ] . flags = SMB2_LOCK_FLAG_EXCLUSIVE ;
status = smb2_lock ( tree , & lck ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* Disconnect/Reconnect. */
talloc_free ( tree ) ;
tree = NULL ;
if ( ! torture_smb2_connection ( tctx , & tree ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = & h ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h = io . out . file . handle ;
lck . in . file . handle = h ;
el [ 0 ] . flags = SMB2_LOCK_FLAG_UNLOCK ;
status = smb2_lock ( tree , & lck ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
done :
smb2_util_close ( tree , h ) ;
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
return ret ;
}
2009-03-31 02:59:06 +04:00
/*
Open , take BRL , disconnect , reconnect .
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_lock_lease ( struct torture_context * tctx ,
struct smb2_tree * tree )
2009-03-31 02:59:06 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_create io ;
struct smb2_lease ls ;
2016-10-19 11:27:14 +03:00
struct smb2_handle h = { { 0 } } ;
2009-03-31 02:59:06 +04:00
struct smb2_lock lck ;
struct smb2_lock_element el [ 2 ] ;
NTSTATUS status ;
char fname [ 256 ] ;
bool ret = true ;
uint64_t lease ;
2012-02-23 12:16:55 +04:00
uint32_t caps ;
2013-09-25 03:25:49 +04:00
struct smbcli_options options ;
options = tree - > session - > transport - > options ;
2012-02-23 12:16:55 +04:00
caps = smb2cli_conn_server_capabilities ( tree - > session - > transport - > conn ) ;
if ( ! ( caps & SMB2_CAP_LEASING ) ) {
torture_skip ( tctx , " leases are not supported " ) ;
}
2009-03-31 02:59:06 +04:00
/*
* Choose a random name and random lease in case the state is left a
* little funky .
*/
lease = random ( ) ;
2012-06-21 14:10:09 +04:00
snprintf ( fname , 256 , " durable_open_lease_lock_%s.dat " , generate_random_str ( tctx , 8 ) ) ;
2009-03-31 02:59:06 +04:00
/* Clean slate */
smb2_util_unlink ( tree , fname ) ;
/* Create with lease */
2011-11-09 01:03:04 +04:00
smb2_lease_create ( & io , & ls , false /* dir */ , fname , lease ,
smb2_util_lease_state ( " RWH " ) ) ;
io . in . durable_open = true ;
2009-03-31 02:59:06 +04:00
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h = io . out . file . handle ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
2011-10-29 19:25:00 +04:00
CHECK_VAL ( io . out . durable_open , true ) ;
2009-03-31 02:59:06 +04:00
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 0 ] , lease ) ;
CHECK_VAL ( io . out . lease_response . lease_key . data [ 1 ] , ~ lease ) ;
CHECK_VAL ( io . out . lease_response . lease_state ,
SMB2_LEASE_READ | SMB2_LEASE_HANDLE | SMB2_LEASE_WRITE ) ;
ZERO_STRUCT ( lck ) ;
ZERO_STRUCT ( el ) ;
lck . in . locks = el ;
lck . in . lock_count = 0x0001 ;
2009-11-19 04:51:35 +03:00
lck . in . lock_sequence = 0x00000000 ;
2009-03-31 02:59:06 +04:00
lck . in . file . handle = h ;
el [ 0 ] . offset = 0 ;
el [ 0 ] . length = 1 ;
el [ 0 ] . reserved = 0x00000000 ;
el [ 0 ] . flags = SMB2_LOCK_FLAG_EXCLUSIVE ;
status = smb2_lock ( tree , & lck ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* Disconnect/Reconnect. */
talloc_free ( tree ) ;
tree = NULL ;
2013-09-25 03:25:49 +04:00
if ( ! torture_smb2_connection_ext ( tctx , 0 , & options , & tree ) ) {
2009-03-31 02:59:06 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = & h ;
io . in . lease_request = & ls ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h = io . out . file . handle ;
lck . in . file . handle = h ;
el [ 0 ] . flags = SMB2_LOCK_FLAG_UNLOCK ;
status = smb2_lock ( tree , & lck ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
done :
smb2_util_close ( tree , h ) ;
smb2_util_unlink ( tree , fname ) ;
2011-10-28 02:11:08 +04:00
talloc_free ( tree ) ;
2009-03-31 02:59:06 +04:00
return ret ;
}
2012-02-21 21:03:27 +04:00
/**
* Open with a RH lease , disconnect , open in another tree , reconnect .
*
* This test actually demonstrates a minimum level of respect for the durable
* open in the face of another open . As long as this test shows an inability to
* reconnect after an open , the oplock / lease tests above will certainly
* demonstrate an error on reconnect .
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_open2_lease ( struct torture_context * tctx ,
struct smb2_tree * tree1 ,
struct smb2_tree * tree2 )
2009-03-31 02:59:06 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_create io1 , io2 ;
struct smb2_lease ls ;
2016-10-19 11:27:14 +03:00
struct smb2_handle h1 = { { 0 } } ;
struct smb2_handle h2 = { { 0 } } ;
2009-03-31 02:59:06 +04:00
NTSTATUS status ;
char fname [ 256 ] ;
bool ret = true ;
uint64_t lease ;
2012-02-23 12:16:55 +04:00
uint32_t caps ;
2013-09-25 03:25:49 +04:00
struct smbcli_options options ;
options = tree1 - > session - > transport - > options ;
2012-02-23 12:16:55 +04:00
caps = smb2cli_conn_server_capabilities ( tree1 - > session - > transport - > conn ) ;
if ( ! ( caps & SMB2_CAP_LEASING ) ) {
torture_skip ( tctx , " leases are not supported " ) ;
}
2009-03-31 02:59:06 +04:00
/*
* Choose a random name and random lease in case the state is left a
* little funky .
*/
lease = random ( ) ;
2012-03-01 02:19:59 +04:00
snprintf ( fname , 256 , " durable_open_open2_lease_%s.dat " ,
2012-02-21 21:01:57 +04:00
generate_random_str ( tctx , 8 ) ) ;
2009-03-31 02:59:06 +04:00
/* Clean slate */
smb2_util_unlink ( tree1 , fname ) ;
/* Create with lease */
2011-11-09 03:22:55 +04:00
smb2_lease_create_share ( & io1 , & ls , false /* dir */ , fname ,
smb2_util_share_access ( " " ) ,
lease ,
smb2_util_lease_state ( " RH " ) ) ;
io1 . in . durable_open = true ;
2009-03-31 02:59:06 +04:00
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h1 = io1 . out . file . handle ;
2011-10-29 19:25:00 +04:00
CHECK_VAL ( io1 . out . durable_open , true ) ;
2009-03-31 02:59:06 +04:00
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . oplock_level , SMB2_OPLOCK_LEVEL_LEASE ) ;
CHECK_VAL ( io1 . out . lease_response . lease_key . data [ 0 ] , lease ) ;
CHECK_VAL ( io1 . out . lease_response . lease_key . data [ 1 ] , ~ lease ) ;
CHECK_VAL ( io1 . out . lease_response . lease_state ,
2011-11-09 03:22:55 +04:00
smb2_util_lease_state ( " RH " ) ) ;
2009-03-31 02:59:06 +04:00
/* Disconnect */
talloc_free ( tree1 ) ;
tree1 = NULL ;
/* Open the file in tree2 */
2012-02-21 21:00:30 +04:00
smb2_oplock_create ( & io2 , fname , SMB2_OPLOCK_LEVEL_NONE ) ;
2009-03-31 02:59:06 +04:00
status = smb2_create ( tree2 , mem_ctx , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h2 = io2 . out . file . handle ;
2015-12-29 02:44:11 +03:00
CHECK_CREATED ( & io2 , EXISTED , FILE_ATTRIBUTE_ARCHIVE ) ;
2009-03-31 02:59:06 +04:00
/* Reconnect */
2013-09-25 03:25:49 +04:00
if ( ! torture_smb2_connection_ext ( tctx , 0 , & options , & tree1 ) ) {
2009-03-31 02:59:06 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io1 ) ;
io1 . in . fname = fname ;
io1 . in . durable_handle = & h1 ;
io1 . in . lease_request = & ls ;
/*
* Windows7 ( build 7000 ) will give away an open immediately if the
* original client is gone . ( ZML : This seems like a bug . It should give
* some time for the client to reconnect ! )
*/
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
h1 = io1 . out . file . handle ;
done :
2015-06-24 02:47:31 +03:00
if ( tree1 ! = NULL ) {
smb2_util_close ( tree1 , h1 ) ;
smb2_util_unlink ( tree1 , fname ) ;
talloc_free ( tree1 ) ;
}
2009-03-31 02:59:06 +04:00
smb2_util_close ( tree2 , h2 ) ;
smb2_util_unlink ( tree2 , fname ) ;
2011-10-28 02:11:08 +04:00
talloc_free ( tree2 ) ;
2009-03-31 02:59:06 +04:00
return ret ;
2009-03-26 23:35:39 +03:00
}
2012-02-21 21:09:14 +04:00
/**
* Open with a batch oplock , disconnect , open in another tree , reconnect .
*
* This test actually demonstrates a minimum level of respect for the durable
* open in the face of another open . As long as this test shows an inability to
* reconnect after an open , the oplock / lease tests above will certainly
* demonstrate an error on reconnect .
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_open2_oplock ( struct torture_context * tctx ,
struct smb2_tree * tree1 ,
struct smb2_tree * tree2 )
2012-02-21 21:09:14 +04:00
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_create io1 , io2 ;
2016-10-19 11:27:14 +03:00
struct smb2_handle h1 = { { 0 } } ;
struct smb2_handle h2 = { { 0 } } ;
2012-02-21 21:09:14 +04:00
NTSTATUS status ;
char fname [ 256 ] ;
bool ret = true ;
/*
* Choose a random name and random lease in case the state is left a
* little funky .
*/
2012-03-01 02:19:59 +04:00
snprintf ( fname , 256 , " durable_open_open2_oplock_%s.dat " ,
2012-02-21 21:09:14 +04:00
generate_random_str ( tctx , 8 ) ) ;
/* Clean slate */
smb2_util_unlink ( tree1 , fname ) ;
/* Create with batch oplock */
smb2_oplock_create ( & io1 , fname , SMB2_OPLOCK_LEVEL_BATCH ) ;
io1 . in . durable_open = true ;
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h1 = io1 . out . file . handle ;
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io1 . out . durable_open , true ) ;
CHECK_VAL ( io1 . out . oplock_level , SMB2_OPLOCK_LEVEL_BATCH ) ;
/* Disconnect */
talloc_free ( tree1 ) ;
tree1 = NULL ;
/* Open the file in tree2 */
smb2_oplock_create ( & io2 , fname , SMB2_OPLOCK_LEVEL_NONE ) ;
status = smb2_create ( tree2 , mem_ctx , & io2 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
h2 = io2 . out . file . handle ;
CHECK_CREATED ( & io1 , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
/* Reconnect */
if ( ! torture_smb2_connection ( tctx , & tree1 ) ) {
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io1 ) ;
io1 . in . fname = fname ;
io1 . in . durable_handle = & h1 ;
status = smb2_create ( tree1 , mem_ctx , & io1 ) ;
CHECK_STATUS ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
h1 = io1 . out . file . handle ;
done :
smb2_util_close ( tree2 , h2 ) ;
smb2_util_unlink ( tree2 , fname ) ;
2013-02-13 17:11:57 +04:00
if ( tree1 ! = NULL ) {
smb2_util_close ( tree1 , h1 ) ;
smb2_util_unlink ( tree1 , fname ) ;
}
2012-02-21 21:09:14 +04:00
talloc_free ( tree1 ) ;
talloc_free ( tree2 ) ;
return ret ;
}
2012-09-07 02:53:38 +04:00
/**
* test behaviour with initial allocation size
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_alloc_size ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-09-07 02:53:38 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io ;
bool ret = true ;
uint64_t previous_session_id ;
uint64_t alloc_size_step ;
2019-06-20 17:10:52 +03:00
uint64_t initial_alloc_size = 0x1000 ;
2012-09-07 02:53:38 +04:00
const uint8_t * b = NULL ;
2013-09-25 09:20:30 +04:00
struct smbcli_options options ;
options = tree - > session - > transport - > options ;
2012-09-07 02:53:38 +04:00
/* Choose a random name in case the state is left a little funky. */
2012-09-07 12:50:48 +04:00
snprintf ( fname , 256 , " durable_open_alloc_size_%s.dat " ,
2012-09-07 02:53:38 +04:00
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io . in . durable_open = true ;
io . in . alloc_size = initial_alloc_size ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_NOT_VAL ( io . out . alloc_size , 0 ) ;
alloc_size_step = io . out . alloc_size ;
CHECK_CREATED_SIZE ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ,
alloc_size_step , 0 ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
/* prepare buffer */
b = talloc_zero_size ( mem_ctx , alloc_size_step ) ;
2015-06-17 04:20:29 +03:00
CHECK_NOT_NULL ( b ) ;
2012-09-07 02:53:38 +04:00
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
/* disconnect, reconnect and then do durable reopen */
talloc_free ( tree ) ;
tree = NULL ;
2013-09-25 09:20:30 +04:00
if ( ! torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree ) )
{
2012-09-07 02:53:38 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED_SIZE ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ,
alloc_size_step , 0 ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
h = & _h ;
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
/* write one byte */
status = smb2_util_write ( tree , * h , b , 0 , 1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* disconnect, reconnect and then do durable reopen */
talloc_free ( tree ) ;
tree = NULL ;
2013-09-25 09:20:30 +04:00
if ( ! torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree ) )
{
2012-09-07 02:53:38 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED_SIZE ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ,
alloc_size_step , 1 ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
h = & _h ;
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
/* write more byte than initial allocation size */
status = smb2_util_write ( tree , * h , b , 1 , alloc_size_step ) ;
/* disconnect, reconnect and then do durable reopen */
talloc_free ( tree ) ;
tree = NULL ;
2013-09-25 09:20:30 +04:00
if ( ! torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree ) )
{
2012-09-07 02:53:38 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
CHECK_CREATED_SIZE ( & io , EXISTED , FILE_ATTRIBUTE_ARCHIVE ,
alloc_size_step * 2 , alloc_size_step + 1 ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
h = & _h ;
done :
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-09-07 14:09:13 +04:00
/**
* test behaviour when a disconnect happens while creating a read - only file
*/
2013-02-13 00:51:06 +04:00
static bool test_durable_open_read_only ( struct torture_context * tctx ,
struct smb2_tree * tree )
2012-09-07 14:09:13 +04:00
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
char fname [ 256 ] ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
struct smb2_create io ;
bool ret = true ;
uint64_t previous_session_id ;
const uint8_t b = 0 ;
uint64_t alloc_size = 0 ;
2013-09-25 09:20:30 +04:00
struct smbcli_options options ;
options = tree - > session - > transport - > options ;
2012-09-07 14:09:13 +04:00
/* Choose a random name in case the state is left a little funky. */
snprintf ( fname , 256 , " durable_open_initial_alloc_%s.dat " ,
generate_random_str ( tctx , 8 ) ) ;
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create_share ( & io , fname ,
smb2_util_share_access ( " " ) ,
smb2_util_oplock_level ( " b " ) ) ;
io . in . durable_open = true ;
io . in . file_attributes = FILE_ATTRIBUTE_READONLY ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
previous_session_id = smb2cli_session_current_id ( tree - > session - > smbXcli ) ;
/* write one byte */
status = smb2_util_write ( tree , * h , & b , 0 , 1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
/* disconnect, reconnect and then do durable reopen */
talloc_free ( tree ) ;
tree = NULL ;
2013-09-25 09:20:30 +04:00
if ( ! torture_smb2_connection_ext ( tctx , previous_session_id ,
& options , & tree ) )
{
2012-09-07 14:09:13 +04:00
torture_warning ( tctx , " couldn't reconnect, bailing \n " ) ;
ret = false ;
goto done ;
}
ZERO_STRUCT ( io ) ;
io . in . fname = fname ;
io . in . durable_handle = h ;
h = NULL ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
alloc_size = io . out . alloc_size ;
CHECK_CREATED_SIZE ( & io , EXISTED ,
FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE ,
alloc_size , 1 ) ;
CHECK_VAL ( io . out . oplock_level , smb2_util_oplock_level ( " b " ) ) ;
_h = io . out . file . handle ;
h = & _h ;
/* write one byte */
status = smb2_util_write ( tree , * h , & b , 1 , 1 ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
done :
if ( h ! = NULL ) {
union smb_setfileinfo sfinfo ;
ZERO_STRUCT ( sfinfo ) ;
sfinfo . basic_info . level = RAW_SFILEINFO_BASIC_INFORMATION ;
sfinfo . basic_info . in . file . handle = * h ;
sfinfo . basic_info . in . attrib = FILE_ATTRIBUTE_NORMAL ;
smb2_setinfo_file ( tree , & sfinfo ) ;
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
talloc_free ( tree ) ;
talloc_free ( mem_ctx ) ;
return ret ;
}
2012-09-07 02:53:38 +04:00
2013-02-12 20:45:23 +04:00
/**
* durable open with oplock , disconnect , exit
*/
static bool test_durable_open_oplock_disconnect ( struct torture_context * tctx ,
struct smb2_tree * tree )
{
TALLOC_CTX * mem_ctx = talloc_new ( tctx ) ;
struct smb2_create io ;
struct smb2_handle _h ;
struct smb2_handle * h = NULL ;
NTSTATUS status ;
char fname [ 256 ] ;
bool ret = true ;
snprintf ( fname , 256 , " durable_open_oplock_disconnect_%s.dat " ,
2013-04-03 11:27:26 +04:00
generate_random_str ( mem_ctx , 8 ) ) ;
2013-02-12 20:45:23 +04:00
smb2_util_unlink ( tree , fname ) ;
smb2_oplock_create ( & io , fname , SMB2_OPLOCK_LEVEL_BATCH ) ;
io . in . durable_open = true ;
status = smb2_create ( tree , mem_ctx , & io ) ;
CHECK_STATUS ( status , NT_STATUS_OK ) ;
_h = io . out . file . handle ;
h = & _h ;
CHECK_CREATED ( & io , CREATED , FILE_ATTRIBUTE_ARCHIVE ) ;
CHECK_VAL ( io . out . durable_open , true ) ;
CHECK_VAL ( io . out . oplock_level , SMB2_OPLOCK_LEVEL_BATCH ) ;
/* disconnect */
talloc_free ( tree ) ;
tree = NULL ;
done :
if ( tree ! = NULL ) {
if ( h ! = NULL ) {
smb2_util_close ( tree , * h ) ;
}
smb2_util_unlink ( tree , fname ) ;
}
2013-04-03 11:27:26 +04:00
talloc_free ( mem_ctx ) ;
2013-02-12 20:45:23 +04:00
return ret ;
}
2017-04-25 01:25:38 +03:00
struct torture_suite * torture_smb2_durable_open_init ( TALLOC_CTX * ctx )
2009-03-26 19:32:50 +03:00
{
2009-03-26 23:35:39 +03:00
struct torture_suite * suite =
2017-04-25 01:25:38 +03:00
torture_suite_create ( ctx , " durable-open " ) ;
2009-03-26 19:32:50 +03:00
2012-03-01 02:19:59 +04:00
torture_suite_add_1smb2_test ( suite , " open-oplock " , test_durable_open_open_oplock ) ;
torture_suite_add_1smb2_test ( suite , " open-lease " , test_durable_open_open_lease ) ;
2012-01-27 16:03:08 +04:00
torture_suite_add_1smb2_test ( suite , " reopen1 " , test_durable_open_reopen1 ) ;
2013-11-29 21:20:01 +04:00
torture_suite_add_1smb2_test ( suite , " reopen1a " , test_durable_open_reopen1a ) ;
2016-03-15 12:02:14 +03:00
torture_suite_add_1smb2_test ( suite , " reopen1a-lease " , test_durable_open_reopen1a_lease ) ;
2012-01-27 16:06:09 +04:00
torture_suite_add_1smb2_test ( suite , " reopen2 " , test_durable_open_reopen2 ) ;
2013-09-25 01:08:24 +04:00
torture_suite_add_1smb2_test ( suite , " reopen2-lease " , test_durable_open_reopen2_lease ) ;
2013-09-25 20:31:10 +04:00
torture_suite_add_1smb2_test ( suite , " reopen2-lease-v2 " , test_durable_open_reopen2_lease_v2 ) ;
2012-02-26 05:36:13 +04:00
torture_suite_add_1smb2_test ( suite , " reopen2a " , test_durable_open_reopen2a ) ;
2012-01-27 20:21:25 +04:00
torture_suite_add_1smb2_test ( suite , " reopen3 " , test_durable_open_reopen3 ) ;
2012-01-30 15:08:38 +04:00
torture_suite_add_1smb2_test ( suite , " reopen4 " , test_durable_open_reopen4 ) ;
2012-06-21 00:28:54 +04:00
torture_suite_add_1smb2_test ( suite , " delete_on_close1 " ,
test_durable_open_delete_on_close1 ) ;
2012-09-11 16:08:28 +04:00
torture_suite_add_1smb2_test ( suite , " delete_on_close2 " ,
test_durable_open_delete_on_close2 ) ;
2012-09-07 19:23:46 +04:00
torture_suite_add_1smb2_test ( suite , " file-position " ,
2009-03-26 19:32:50 +03:00
test_durable_open_file_position ) ;
2010-12-11 05:26:31 +03:00
torture_suite_add_2smb2_test ( suite , " oplock " , test_durable_open_oplock ) ;
torture_suite_add_2smb2_test ( suite , " lease " , test_durable_open_lease ) ;
2012-06-22 02:28:26 +04:00
torture_suite_add_1smb2_test ( suite , " lock-oplock " , test_durable_open_lock_oplock ) ;
2012-06-21 14:10:09 +04:00
torture_suite_add_1smb2_test ( suite , " lock-lease " , test_durable_open_lock_lease ) ;
2012-03-01 02:19:59 +04:00
torture_suite_add_2smb2_test ( suite , " open2-lease " ,
test_durable_open_open2_lease ) ;
torture_suite_add_2smb2_test ( suite , " open2-oplock " ,
test_durable_open_open2_oplock ) ;
2012-09-07 02:53:38 +04:00
torture_suite_add_1smb2_test ( suite , " alloc-size " ,
test_durable_open_alloc_size ) ;
2012-09-07 14:09:13 +04:00
torture_suite_add_1smb2_test ( suite , " read-only " ,
test_durable_open_read_only ) ;
2009-03-26 19:32:50 +03:00
suite - > description = talloc_strdup ( suite , " SMB2-DURABLE-OPEN tests " ) ;
2009-03-27 15:25:26 +03:00
return suite ;
2009-03-26 19:32:50 +03:00
}
2013-02-12 20:45:23 +04:00
2017-04-25 01:25:38 +03:00
struct torture_suite * torture_smb2_durable_open_disconnect_init ( TALLOC_CTX * ctx )
2013-02-12 20:45:23 +04:00
{
struct torture_suite * suite =
2017-04-25 01:25:38 +03:00
torture_suite_create ( ctx ,
2013-02-12 20:45:23 +04:00
" durable-open-disconnect " ) ;
torture_suite_add_1smb2_test ( suite , " open-oplock-disconnect " ,
test_durable_open_oplock_disconnect ) ;
suite - > description = talloc_strdup ( suite ,
" SMB2-DURABLE-OPEN-DISCONNECT tests " ) ;
return suite ;
}