The branch, master has been updated via a354758 s4:torture:smb2: add durable_open_basic2 test: test durable open against all lease types via 976f980 s4:torture:smb2: add a new durable_open_basic1 test: test open against all oplock types via f8aeca1 s4:torture:smb2: check wheter open was durable in existing tests via 530cd2a s4:libcli: in smb2_create_recv, map SMB2_CREATE_DURABLE_HANDLE_RESPONSE buffer smb2_create.out.durable_open via d01b248 source4/libcli: add bool durable_open to smb2_create.out. via de967f2 s4:torture: test also break semantics between batch-oplocks and leases via 69ca2bd s4:torture:smb2: adapt comment in durable-open.lease test according to current information. via 5975e8a s4:torture:smb2: fix the durable_open test to succeed against w7 and w2k8r2 from f30f71c Fix bug #8548 - winbind_samlogon_retry_loop ignores logon_parameters flags.
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit a354758da50d09341bbea237548de52e3821a198 Author: Michael Adam <ob...@samba.org> Date: Sat Oct 29 17:28:38 2011 +0200 s4:torture:smb2: add durable_open_basic2 test: test durable open against all lease types Autobuild-User: Michael Adam <ob...@samba.org> Autobuild-Date: Sun Oct 30 20:17:16 CET 2011 on sn-devel-104 commit 976f9806c9255202bd3c3d2f927d2d854f7034f8 Author: Michael Adam <ob...@samba.org> Date: Sat Oct 29 17:26:53 2011 +0200 s4:torture:smb2: add a new durable_open_basic1 test: test open against all oplock types commit f8aeca1018cf036b3294f2d6807fd35b2de2c44b Author: Michael Adam <ob...@samba.org> Date: Sat Oct 29 17:25:00 2011 +0200 s4:torture:smb2: check wheter open was durable in existing tests commit 530cd2aac6178570c182b6f33364c7d3c6316c00 Author: Michael Adam <ob...@samba.org> Date: Sat Oct 29 13:18:05 2011 +0200 s4:libcli: in smb2_create_recv, map SMB2_CREATE_DURABLE_HANDLE_RESPONSE buffer smb2_create.out.durable_open commit d01b248d4f6260c9d67a82e6497f8f4c99666a4c Author: Michael Adam <ob...@samba.org> Date: Sat Oct 29 13:16:07 2011 +0200 source4/libcli: add bool durable_open to smb2_create.out. The server gives indication whether the open was durable we should record this. commit de967f22fc9e5a6f9f95be90e882935761295917 Author: Michael Adam <ob...@samba.org> Date: Sat Oct 29 14:48:58 2011 +0200 s4:torture: test also break semantics between batch-oplocks and leases This must have been a typo (listing EXCLUSIVE twice). But BATCH and EXCLUSIVE oplocks apparently share the same break semantics with respect to leases. commit 69ca2bd048fa8ec98ab668baf651d3e84f7e919c Author: Michael Adam <ob...@samba.org> Date: Sun Oct 30 18:40:00 2011 +0100 s4:torture:smb2: adapt comment in durable-open.lease test according to current information. commit 5975e8a3f46f3d6f99d997d36f874141f80b9c33 Author: Michael Adam <ob...@samba.org> Date: Sat Oct 29 11:56:48 2011 +0200 s4:torture:smb2: fix the durable_open test to succeed against w7 and w2k8r2 When a first client that has a durable open with share read/write/delete and a read-write-handle lease on the file disconnects, a second client will succeed in opening the file and the new client will be given a RWH-lease if requested, not only a RH-lease, as was previously checked in the test. This might have been a bug in win7 build 7000, which is what the comments in the test give as reference. ----------------------------------------------------------------------- Summary of changes: source4/libcli/raw/interfaces.h | 1 + source4/libcli/smb2/create.c | 7 + source4/torture/smb2/durable_open.c | 270 ++++++++++++++++++++++++++++++++++- source4/torture/smb2/lease.c | 2 +- 4 files changed, 278 insertions(+), 2 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h index 7bb5255..7aba48b 100644 --- a/source4/libcli/raw/interfaces.h +++ b/source4/libcli/raw/interfaces.h @@ -1741,6 +1741,7 @@ union smb_open { uint32_t maximal_access; uint8_t on_disk_id[32]; struct smb2_lease lease_response; + bool durable_open; /* tagged blobs in the reply */ struct smb2_create_blobs blobs; diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c index 4e15064..438651f 100644 --- a/source4/libcli/smb2/create.c +++ b/source4/libcli/smb2/create.c @@ -274,6 +274,13 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct io->out.lease_response.lease_flags = IVAL(data, 20); io->out.lease_response.lease_duration = BVAL(data, 24); } + if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNQ) == 0) { + if (io->out.blobs.blobs[i].data.length != 8) { + smb2_request_destroy(req); + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + io->out.durable_open = true; + } } data_blob_free(&blob); diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c index 544f404..33ce1e9 100644 --- a/source4/torture/smb2/durable_open.c +++ b/source4/torture/smb2/durable_open.c @@ -49,6 +49,261 @@ CHECK_VAL((__io)->out.reserved2, 0); \ } while(0) + +static inline uint32_t map_lease(const char *ls) +{ + uint32_t val = 0; + int i; + + for (i = 0; i < strlen(ls); i++) { + switch (ls[i]) { + case 'R': + val |= SMB2_LEASE_READ; + break; + case 'H': + val |= SMB2_LEASE_HANDLE; + break; + case 'W': + val |= SMB2_LEASE_WRITE; + break; + } + } + + return val; +} + +/** + * 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 { + uint8_t level; + bool expected; +}; + +#define NUM_OPLOCK_OPEN_TESTS 4 +struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] = +{ + { SMB2_OPLOCK_LEVEL_NONE, false }, + { SMB2_OPLOCK_LEVEL_II, false }, + { SMB2_OPLOCK_LEVEL_EXCLUSIVE, false }, + { SMB2_OPLOCK_LEVEL_BATCH, true }, +}; + +static bool test_one_durable_open_basic1(struct torture_context *tctx, + struct smb2_tree *tree, + const char *fname, + struct smb2_create io, + struct durable_open_vs_oplock test) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h; + struct smb2_handle *h = NULL; + bool ret = true; + + smb2_util_unlink(tree, fname); + + io.in.fname = fname; + io.in.oplock_level = test.level; + 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, test.level); + +done: + if (h != NULL) { + smb2_util_close(tree, *h); + } + smb2_util_unlink(tree, fname); + talloc_free(mem_ctx); + + return ret; +} + +bool test_durable_open_basic1(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_create io; + char fname[256]; + bool ret = true; + int i; + + /* Choose a random name in case the state is left a little funky. */ + snprintf(fname, 256, "durable_open_basic1_%s.dat", generate_random_str(tctx, 8)); + + smb2_util_unlink(tree, fname); + + ZERO_STRUCT(io); + io.in.security_flags = 0x00; + io.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + io.in.create_flags = 0x00000000; + io.in.reserved = 0x00000000; + io.in.desired_access = SEC_RIGHTS_FILE_ALL; + io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | + NTCREATEX_SHARE_ACCESS_DELETE; + io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | + NTCREATEX_OPTIONS_ASYNC_ALERT | + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | + 0x00200000; + io.in.durable_open = true; + io.in.fname = fname; + + /* test various oplock levels with durable open */ + + for (i = 0; i < NUM_OPLOCK_OPEN_TESTS; i++) { + ret = test_one_durable_open_basic1(tctx, + tree, + fname, + io, + durable_open_vs_oplock_table[i]); + if (ret == false) { + goto done; + } + } + +done: + smb2_util_unlink(tree, fname); + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + +/** + * 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; + bool expected; +}; + +#define NUM_LEASE_OPEN_TESTS 5 +struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] = +{ + { "", false }, + { "R", false }, + { "RW", false }, + { "RH", true }, + { "RHW", true }, +}; + +static bool test_one_durable_open_basic2(struct torture_context *tctx, + struct smb2_tree *tree, + const char *fname, + struct smb2_create io, + struct durable_open_vs_lease test) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle _h; + struct smb2_handle *h = NULL; + bool ret = true; + struct smb2_lease ls; + uint64_t lease; + + smb2_util_unlink(tree, fname); + + io.in.fname = fname; + io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE; + + lease = random(); + + ZERO_STRUCT(ls); + ls.lease_key.data[0] = lease; + ls.lease_key.data[1] = ~lease; + ls.lease_state = map_lease(test.type); + io.in.lease_request = &ls; + + 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); + CHECK_VAL(io.out.lease_response.lease_state, map_lease(test.type)); +done: + if (h != NULL) { + smb2_util_close(tree, *h); + } + smb2_util_unlink(tree, fname); + talloc_free(mem_ctx); + + return ret; +} + +bool test_durable_open_basic2(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_create io; + char fname[256]; + bool ret = true; + int i; + + /* Choose a random name in case the state is left a little funky. */ + snprintf(fname, 256, "durable_open_basic2_%s.dat", generate_random_str(tctx, 8)); + + smb2_util_unlink(tree, fname); + + ZERO_STRUCT(io); + io.in.security_flags = 0x00; + io.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + io.in.create_flags = 0x00000000; + io.in.reserved = 0x00000000; + io.in.desired_access = SEC_RIGHTS_FILE_ALL; + io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | + NTCREATEX_SHARE_ACCESS_DELETE; + io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | + NTCREATEX_OPTIONS_ASYNC_ALERT | + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | + 0x00200000; + io.in.durable_open = true; + io.in.fname = fname; + + /* test various oplock levels with durable open */ + + for (i = 0; i < NUM_LEASE_OPEN_TESTS; i++) { + ret = test_one_durable_open_basic2(tctx, + tree, + fname, + io, + durable_open_vs_lease_table[i]); + if (ret == false) { + goto done; + } + } + +done: + smb2_util_unlink(tree, fname); + talloc_free(tree); + talloc_free(mem_ctx); + + return ret; +} + /* basic testing of SMB2 durable opens regarding the position information on the handle @@ -92,6 +347,7 @@ bool test_durable_open_file_position(struct torture_context *tctx, 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); /* TODO: check extra blob content */ @@ -138,6 +394,7 @@ bool test_durable_open_file_position(struct torture_context *tctx, status = smb2_create(tree2, mem_ctx, &io2); CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VAL(io2.out.durable_open, true); CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH); CHECK_VAL(io2.out.reserved, 0x00); CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED); @@ -217,6 +474,7 @@ bool test_durable_open_oplock(struct torture_context *tctx, 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 after getting the batch */ @@ -232,6 +490,7 @@ bool test_durable_open_oplock(struct torture_context *tctx, CHECK_STATUS(status, NT_STATUS_OK); h2 = io2.out.file.handle; CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io2.out.durable_open, true); CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH); /* What if tree1 tries to come back and reclaim? */ @@ -321,6 +580,7 @@ bool test_durable_open_lease(struct torture_context *tctx, status = smb2_create(tree1, mem_ctx, &io1); CHECK_STATUS(status, NT_STATUS_OK); h1 = io1.out.file.handle; + CHECK_VAL(io1.out.durable_open, true); CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); @@ -337,17 +597,21 @@ bool test_durable_open_lease(struct torture_context *tctx, * 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?) + * + * obnox: Current windows 7 and w2k8r2 grant RHW instead of RH. + * Test is adapted accordingly. */ status = smb2_create(tree2, mem_ctx, &io2); CHECK_STATUS(status, NT_STATUS_OK); h2 = io2.out.file.handle; + CHECK_VAL(io2.out.durable_open, true); 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, - SMB2_LEASE_READ|SMB2_LEASE_HANDLE); + SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE); /* What if tree1 tries to come back and reclaim? */ if (!torture_smb2_connection(tctx, &tree1)) { @@ -432,6 +696,7 @@ bool test_durable_open_lock(struct torture_context *tctx, 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_LEASE); CHECK_VAL(io.out.lease_response.lease_key.data[0], lease); CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease); @@ -545,6 +810,7 @@ bool test_durable_open_open(struct torture_context *tctx, status = smb2_create(tree1, mem_ctx, &io1); CHECK_STATUS(status, NT_STATUS_OK); h1 = io1.out.file.handle; + CHECK_VAL(io1.out.durable_open, true); CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); @@ -601,6 +867,8 @@ struct torture_suite *torture_smb2_durable_open_init(void) struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "durable-open"); + torture_suite_add_1smb2_test(suite, "basic1", test_durable_open_basic1); + torture_suite_add_1smb2_test(suite, "basic2", test_durable_open_basic2); torture_suite_add_2smb2_test(suite, "file-position", test_durable_open_file_position); torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock); diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c index 564394f..3d3f17d 100644 --- a/source4/torture/smb2/lease.c +++ b/source4/torture/smb2/lease.c @@ -550,7 +550,7 @@ static inline uint32_t oplock(const char *op) { case 'x': return SMB2_OPLOCK_LEVEL_EXCLUSIVE; case 'b': - return SMB2_OPLOCK_LEVEL_EXCLUSIVE; + return SMB2_OPLOCK_LEVEL_BATCH; default: continue; } -- Samba Shared Repository