diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c index c1b6420..8db5b5c 100644 --- a/source4/torture/smb2/lease.c +++ b/source4/torture/smb2/lease.c @@ -47,7 +47,6 @@ #define CHECK_CREATED(__io, __created, __attribute) \ do { \ CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \ - CHECK_VAL((__io)->out.alloc_size, 0); \ CHECK_VAL((__io)->out.size, 0); \ CHECK_VAL((__io)->out.file_attr, (__attribute)); \ CHECK_VAL((__io)->out.reserved2, 0); \ @@ -2802,6 +2801,144 @@ done: return ret; } +static bool test_lease_breaking7(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_create io1 = {}; + struct smb2_create io2 = {}; + struct smb2_create io3 = {}; + struct smb2_create io4 = {}; + struct smb2_lease ls1 = {}; + struct smb2_lease ls2 = {}; + struct smb2_lease ls3 = {}; + struct smb2_handle h1 = {}; + struct smb2_handle h3 = {}; + struct smb2_handle h4 = {}; + const char *fname = "lease_breaking7.dat"; + struct smb2_write w; + bool ret = true; + NTSTATUS status; + uint32_t caps; + + caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn); + if (!(caps & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + caps = smb2cli_conn_server_capabilities(tree2->session->transport->conn); + if (!(caps & SMB2_CAP_LEASING)) { + torture_skip(tctx, "leases are not supported"); + } + + smb2_util_unlink(tree1, fname); + + tree1->session->transport->lease.handler = torture_lease_handler; + tree1->session->transport->lease.private_data = tree1; + tree1->session->transport->oplock.handler = torture_oplock_handler; + tree1->session->transport->oplock.private_data = tree1; + + tree2->session->transport->lease.handler = torture_lease_handler; + tree2->session->transport->lease.private_data = tree2; + tree2->session->transport->oplock.handler = torture_oplock_handler; + tree2->session->transport->oplock.private_data = tree2; + + ZERO_STRUCT(break_info); + + smb2_lease_create_share(&io1, &ls1, false, fname, + smb2_util_share_access("RWD"), + LEASE1, + smb2_util_lease_state("RH")); + io2.in.create_disposition = NTCREATEX_DISP_CREATE; + 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_LEASE(&io1, "RH", true, LEASE1, 0); + + /* Write some data into the file. */ + ZERO_STRUCT(w); + w.in.file.handle = h1; + w.in.offset = 0; + w.in.data = data_blob_talloc(mem_ctx, NULL, 4096); + memset(w.in.data.data, 'o', w.in.data.length); + status = smb2_write(tree1, &w); + CHECK_STATUS(status, NT_STATUS_OK); + + CHECK_NO_BREAK(tctx); + + /* + * a conflicting open just gets SHARING_VIOLATION, no break. + */ + smb2_lease_create_share(&io2, &ls2, false, fname, + smb2_util_share_access("R"), + LEASE1, + smb2_util_lease_state("RH")); + io2.in.create_disposition = NTCREATEX_DISP_OPEN; + status = smb2_create(tree2, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); + + CHECK_NO_BREAK(tctx); + + /* + * We now ask the server about the current lease state + * which should still be "RH". + */ + smb2_lease_create_share(&io3, &ls3, false, fname, + smb2_util_share_access("RWD"), + LEASE1, + smb2_util_lease_state("")); + io3.in.create_disposition = NTCREATEX_DISP_OPEN; + status = smb2_create(tree1, mem_ctx, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + h3 = io3.out.file.handle; + + CHECK_VAL(io3.out.create_action, NTCREATEX_ACTION_EXISTED); + CHECK_VAL(io3.out.size, 4096); + CHECK_VAL(io3.out.file_attr, FILE_ATTRIBUTE_ARCHIVE); + + CHECK_LEASE(&io3, "RH", true, LEASE1, 0); + + /* Now open with truncate on the new guid. */ + smb2_lease_create_share(&io4, &ls2, false, fname, + smb2_util_share_access("RWD"), + LEASE1, + smb2_util_lease_state("RH")); + io4.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; + status = smb2_create(tree2, mem_ctx, &io4); + CHECK_STATUS(status, NT_STATUS_OK); + + CHECK_NO_BREAK(tctx); + + CHECK_VAL(io4.out.create_action, NTCREATEX_ACTION_TRUNCATED); + CHECK_VAL(io4.out.size, 0); + CHECK_VAL(io4.out.file_attr, FILE_ATTRIBUTE_ARCHIVE); + h4 = io4.out.file.handle; + + /* + * a conflicting open with a differnet lease key gets SHARING_VIOLATION + * plus a break. + */ + smb2_lease_create_share(&io2, &ls2, false, fname, + smb2_util_share_access("R"), + LEASE2, + smb2_util_lease_state("RH")); + io2.in.create_disposition = NTCREATEX_DISP_OPEN; + status = smb2_create(tree2, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); + + CHECK_BREAK_INFO("RH", "R", LEASE1); + +done: + smb2_util_close(tree1, h1); + smb2_util_close(tree1, h3); + smb2_util_close(tree2, h4); + smb2_util_unlink(tree1, fname); + talloc_free(mem_ctx); + return ret; +} + + static bool test_lease_lock1(struct torture_context *tctx, struct smb2_tree *tree1a, struct smb2_tree *tree2) @@ -3555,6 +3692,31 @@ static bool test_lease_v2_rename(struct torture_context *tctx, h1 = io.out.file.handle; CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch); + + /* Now rename back - what happens ? */ + ZERO_STRUCT(sinfo); + sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; + sinfo.rename_information.in.file.handle = h; + sinfo.rename_information.in.overwrite = true; + sinfo.rename_information.in.new_name = fname; + status = smb2_setinfo_file(tree, &sinfo); + CHECK_STATUS(status, NT_STATUS_OK); + + /* No lease break. */ + CHECK_NO_BREAK(tctx); + + /* And rename again - what happens ? */ + ZERO_STRUCT(sinfo); + sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; + sinfo.rename_information.in.file.handle = h; + sinfo.rename_information.in.overwrite = true; + sinfo.rename_information.in.new_name = fname_dst; + status = smb2_setinfo_file(tree, &sinfo); + CHECK_STATUS(status, NT_STATUS_OK); + + /* No lease break. */ + CHECK_NO_BREAK(tctx); + smb2_util_close(tree, h1); /* Try another lease key. */ @@ -3827,6 +3989,7 @@ struct torture_suite *torture_smb2_lease_init(void) torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4); torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5); torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6); + torture_suite_add_2smb2_test(suite, "breaking7", test_lease_breaking7); torture_suite_add_2smb2_test(suite, "lock1", test_lease_lock1); torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1); torture_suite_add_1smb2_test(suite, "v2_request_parent",