From: Stefan Metzmacher Date: Wed, 23 Sep 2020 02:58:22 +0000 (+0200) Subject: s4:torture/smb2: add smb2.lease.timeout-disconnect test X-Git-Tag: tevent-0.11.0~1669 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a0626c32ae2803cb6c478717c34bf30231dc3dc;p=thirdparty%2Fsamba.git 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 Reviewed-by: Jeremy Allison --- diff --git a/selftest/knownfail.d/smb2.lease.timeout-disconnect b/selftest/knownfail.d/smb2.lease.timeout-disconnect new file mode 100644 index 00000000000..a277ef43fa6 --- /dev/null +++ b/selftest/knownfail.d/smb2.lease.timeout-disconnect @@ -0,0 +1 @@ +^samba3.smb2.lease.timeout-disconnect diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c index 6b7f10b5eb7..e820cd8b97a 100644 --- a/source4/torture/smb2/lease.c +++ b/source4/torture/smb2/lease.c @@ -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");