s4-torture: add additional oplock break test
authorJose A. Rivera <jarrpa@samba.org>
Thu, 29 Sep 2016 05:33:46 +0000 (07:33 +0200)
committerMichael Adam <obnox@samba.org>
Tue, 18 Sep 2018 10:34:32 +0000 (12:34 +0200)
This test verifies that Windows will use an alternate channel to process the
oplock break when the original channel's tcp connection has been reset.

Signed-off-by: Jose A. Rivera <jarrpa@samba.org>
Pair-Programmed-With: Guenther Deschner <gd@samba.org>

source4/torture/smb2/multichannel.c

index 3d1d3413e2788b920fac502a6a28f612c7a92304..0d36576588072eec0e93255cbe8b8bb287493922 100644 (file)
@@ -508,7 +508,7 @@ static bool test_multichannel_oplock_break(struct torture_context *tctx,
        CHECK_VAL(break_info.count, 1);
        CHECK_PTR(break_info.received_transport, transport2B);
 
-       /* FIXME: further closing or cleanup needed? */
+       /* cleanup everything */
        torture_reset_break_info(tctx, &break_info);
 
        smb2_util_close(tree1, h_client1_file1);
@@ -682,6 +682,99 @@ static bool test_multichannel_oplock_break(struct torture_context *tctx,
 
        CHECK_VAL(break_info.count, 1);
 
+       unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
+       torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
+
+       /* next test: disconnect 2C and trigger break */
+
+       torture_reset_break_info(tctx, &break_info);
+
+       /*
+        * now add a third channel and repeat the test, we need to reestablish
+        * transport2C because the remote end has invalidated our connection
+        */
+
+       status = smb2_connect(tctx,
+                       host,
+                       lpcfg_smb_ports(tctx->lp_ctx),
+                       share,
+                       lpcfg_resolve_context(tctx->lp_ctx),
+                       credentials,
+                       &tree2C,
+                       tctx->ev,
+                       &transport2_options,
+                       lpcfg_socket_options(tctx->lp_ctx),
+                       lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+                       );
+       torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+                       "smb2_connect failed");
+       transport2C = tree2C->session->transport;
+
+       /*
+        * Now bind the session2 to the transport2C
+        */
+       session2C = smb2_session_channel(transport2C,
+                       lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+                       tree2A, session2A);
+
+       tree2C->smbXcli = tree2A->smbXcli;
+       tree2C->session = session2C;
+
+       torture_assert(tctx, session2C != NULL, "smb2_session_channel failed");
+
+       transport2C->oplock.handler = torture_oplock_ack_handler;
+       transport2C->oplock.private_data = tree2C;
+       torture_comment(tctx, "transport2C[%p]\n", transport2C);
+
+       torture_comment(tctx, "established transport 2C\n");
+
+       status = smb2_session_setup_spnego(session2C,
+                       popt_get_cmdline_credentials(),
+                       0 /* previous_session_id */);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       torture_comment(tctx, "bound session2C to session2A\n");
+
+       torture_comment(tctx, "client 2 opening fname3 over newly established transport2C\n");
+
+       status = smb2_create(tree2C, mem_ctx, &io3);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client2_file3 = io3.out.file.handle;
+       CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       if (share_is_so) {
+               CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
+               CHECK_VAL(io3.out.durable_open_v2, false);
+               CHECK_VAL(io3.out.timeout, 0);
+       } else {
+               CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
+               CHECK_VAL(io3.out.durable_open_v2, true);
+               CHECK_VAL(io3.out.timeout, io3.in.timeout);
+       }
+       CHECK_VAL(io3.out.durable_open, false);
+       CHECK_VAL(break_info.count, 0);
+
+       torture_comment(tctx, "explicit disconnect of transport2C\n");
+       smbXcli_conn_disconnect(transport2C->conn, NT_STATUS_FOOBAR);
+
+       torture_comment(tctx, "client1 opens fname3 via session1\n");
+
+       status = smb2_create(tree1, mem_ctx, &io3);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client1_file3 = io3.out.file.handle;
+       CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+       if (share_is_so) {
+               CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
+               CHECK_VAL(io3.out.durable_open_v2, false);
+               CHECK_VAL(io3.out.timeout, 0);
+       } else {
+               CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
+               CHECK_VAL(io3.out.durable_open_v2, false);
+               CHECK_VAL(io3.out.timeout, 0);
+       }
+       CHECK_VAL(io3.out.durable_open, false);
+       CHECK_VAL(break_info.count, 1);
+       CHECK_PTR(break_info.received_transport, transport2B);
+
        if (h != NULL) {
                smb2_util_close(tree1, *h);
                h = NULL;