1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-08 04:58:40 +03:00

s4:torture/smb2: add smb2.lease.timeout-disconnect test

This reproduces a problem that is triggered when
smbd_server_connection_terminate() is called recursively.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14533

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Stefan Metzmacher 2020-09-23 04:58:22 +02:00 committed by Jeremy Allison
parent 638c4435a0
commit 2a0626c32a
2 changed files with 147 additions and 0 deletions

View File

@ -0,0 +1 @@
^samba3.smb2.lease.timeout-disconnect

View File

@ -4149,6 +4149,151 @@ done:
return ret;
}
static bool test_lease_timeout_disconnect(struct torture_context *tctx,
struct smb2_tree *tree1)
{
TALLOC_CTX *mem_ctx = talloc_new(tctx);
NTSTATUS status;
bool ret = true;
struct smbcli_options transport2_options;
struct smbcli_options transport3_options;
struct smb2_tree *tree2 = NULL;
struct smb2_tree *tree3 = NULL;
struct smb2_transport *transport1 = tree1->session->transport;
struct smb2_transport *transport2;
struct smb2_transport *transport3;
const char *fname = "lease_timeout_logoff.dat" ;
uint32_t caps;
struct smb2_create io1;
struct smb2_create io2;
struct smb2_request *req2 = NULL;
struct smb2_lease ls1;
caps = smb2cli_conn_server_capabilities(
tree1->session->transport->conn);
if (!(caps & SMB2_CAP_LEASING)) {
torture_skip(tctx, "leases are not supported");
}
smb2_util_unlink(tree1, fname);
/* Connect 2nd connection */
torture_comment(tctx, "connect tree2 with the same client_guid\n");
transport2_options = transport1->options;
if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
torture_warning(tctx, "couldn't reconnect, bailing\n");
return false;
}
transport2 = tree2->session->transport;
/* Connect 3rd connection */
torture_comment(tctx, "connect tree3 with the same client_guid\n");
transport3_options = transport1->options;
if (!torture_smb2_connection_ext(tctx, 0, &transport3_options, &tree3)) {
torture_warning(tctx, "couldn't reconnect, bailing\n");
return false;
}
transport3 = tree3->session->transport;
/* Set lease handlers */
transport1->lease.handler = torture_lease_handler;
transport1->lease.private_data = tree1;
transport2->lease.handler = torture_lease_handler;
transport2->lease.private_data = tree2;
transport3->lease.handler = torture_lease_handler;
transport3->lease.private_data = tree3;
smb2_lease_create_share(&io1, &ls1, false, fname,
smb2_util_share_access(""),
LEASE1,
smb2_util_lease_state("RH"));
io1.in.durable_open = true;
smb2_generic_create(&io2, NULL, false, fname,
NTCREATEX_DISP_OPEN_IF,
SMB2_OPLOCK_LEVEL_NONE, 0, 0);
torture_comment(tctx, "tree1: create file[%s] with durable RH lease (SHARE NONE)\n", fname);
torture_reset_lease_break_info(tctx, &lease_break_info);
lease_break_info.lease_skip_ack = true;
status = smb2_create(tree1, mem_ctx, &io1);
CHECK_STATUS(status, NT_STATUS_OK);
CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
CHECK_VAL(lease_break_info.count, 0);
torture_comment(tctx, "tree1: skip lease acks\n");
torture_reset_lease_break_info(tctx, &lease_break_info);
lease_break_info.lease_skip_ack = true;
torture_comment(tctx, "tree2: open file[%s] without lease (SHARE RWD)\n", fname);
req2 = smb2_create_send(tree2, &io2);
torture_assert(tctx, req2 != NULL, "req2 started");
torture_comment(tctx, "tree1: wait for lease break\n");
torture_wait_for_lease_break(tctx);
CHECK_VAL(lease_break_info.count, 1);
CHECK_BREAK_INFO("RH", "R", LEASE1);
torture_comment(tctx, "tree1: reset lease handler\n");
torture_reset_lease_break_info(tctx, &lease_break_info);
lease_break_info.lease_skip_ack = true;
CHECK_VAL(lease_break_info.count, 0);
torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
torture_assert_int_equal(tctx, req2->state,
SMB2_REQUEST_RECV,
"SMB2_REQUEST_RECV");
torture_comment(tctx, "sleep 1\n");
smb_msleep(1000);
torture_comment(tctx, "transport1: keepalive\n");
status = smb2_keepalive(transport1);
CHECK_STATUS(status, NT_STATUS_OK);
torture_comment(tctx, "transport2: keepalive\n");
status = smb2_keepalive(transport2);
CHECK_STATUS(status, NT_STATUS_OK);
torture_comment(tctx, "transport3: keepalive\n");
status = smb2_keepalive(transport3);
CHECK_STATUS(status, NT_STATUS_OK);
torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
torture_assert_int_equal(tctx, req2->state,
SMB2_REQUEST_RECV,
"SMB2_REQUEST_RECV");
torture_comment(tctx, "tree2: check for STATUS_PENDING\n");
torture_assert(tctx, req2->cancel.can_cancel, "STATUS_PENDING");
torture_comment(tctx, "sleep 1\n");
smb_msleep(1000);
torture_comment(tctx, "transport1: keepalive\n");
status = smb2_keepalive(transport1);
CHECK_STATUS(status, NT_STATUS_OK);
torture_comment(tctx, "transport2: disconnect\n");
TALLOC_FREE(tree2);
torture_comment(tctx, "sleep 1\n");
smb_msleep(1000);
torture_comment(tctx, "transport1: keepalive\n");
status = smb2_keepalive(transport1);
CHECK_STATUS(status, NT_STATUS_OK);
torture_comment(tctx, "transport1: disconnect\n");
TALLOC_FREE(tree1);
torture_comment(tctx, "sleep 1\n");
smb_msleep(1000);
torture_comment(tctx, "transport3: keepalive\n");
status = smb2_keepalive(transport3);
CHECK_STATUS(status, NT_STATUS_OK);
torture_comment(tctx, "transport3: disconnect\n");
TALLOC_FREE(tree3);
done:
return ret;
}
struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx)
{
struct torture_suite *suite =
@ -4190,6 +4335,7 @@ struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx)
torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink);
torture_suite_add_1smb2_test(suite, "timeout-disconnect", test_lease_timeout_disconnect);
suite->description = talloc_strdup(suite, "SMB2-LEASE tests");