s4:torture/smb2: make smb2.lock.replay_broken_windows more obvious
authorStefan Metzmacher <metze@samba.org>
Wed, 2 Oct 2019 12:51:26 +0000 (14:51 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 15 Oct 2019 07:36:22 +0000 (09:36 +0200)
This test check the SMB 2.1.0 behaviour of lock sequence checking,
which is only turned on for resilient handles.

Even Windows Server 2019 only implements lock sequence checking only
for resilient and persistent handles as a server.
While its client side uses lock sequence checking if it negotiated
multichannel with the server.

Hopefully this will be fixed in future Windows versions.

Make it clear that this test is supposed to pass against the legacy
Windows servers which violate the specification:

  [MS-SMB2] 3.3.5.14 Receiving an SMB2 LOCK Request

  ...

  If the LockSequence value in the SMB2 LOCK Request (section 2.2.26) is not zero,
  and either one of the following conditions is TRUE, the server SHOULD verify
  whether the lock/unlock request with that LockSequence value has been
  successfully processed before:
  * Connection.Dialect is "2.1" and Open.IsResilient is TRUE.
  * Connection.Dialect belongs to the SMB 3.x dialect family.<318>

  ...

  <318> Section 3.3.5.14: Windows 8, Windows Server 2012, Windows 8.1, and Windows Server 2012
  R2 do not verify the LockSequence value in the SMB2 LOCK Request (section 2.2.26) when both
  Open.IsResilient and Open.IsPersistent are FALSE.

Note <318> also applies to Windows Server 2016 and 2019.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
source4/torture/smb2/lock.c

index 5cb4a0376c4e29a289397c259a8b675c740c964c..586fbd8806ef96ef9c136fca6c50cc694c4cec1c 100644 (file)
@@ -2873,9 +2873,37 @@ done:
 
 /**
  * Test lock replay detection
+ *
+ * This test check the SMB 2.1.0 behaviour of lock sequence checking,
+ * which is only turned on for resilient handles.
+ *
+ * Make it clear that this test is supposed to pass against the legacy
+ * Windows servers which violate the specification:
+ *
+ *   [MS-SMB2] 3.3.5.14 Receiving an SMB2 LOCK Request
+ *
+ *   ...
+ *
+ *   If the LockSequence value in the SMB2 LOCK Request (section 2.2.26) is not
+ *   zero, and either one of the following conditions is TRUE, the server SHOULD
+ *   verify whether the lock/unlock request with that LockSequence value has
+ *   been successfully processed before:
+ *   * Connection.Dialect is "2.1" and Open.IsResilient is TRUE.
+ *   * Connection.Dialect belongs to the SMB 3.x dialect family.<318>
+ *
+ *   ...
+ *
+ *   <318> Section 3.3.5.14: Windows 8, Windows Server 2012, Windows 8.1, and
+ *   Windows Server 2012 R2 do not verify the LockSequence value in the
+ *   SMB2 LOCK Request (section 2.2.26) when both Open.IsResilient and
+ *   Open.IsPersistent are FALSE.
+ *
+ * Note <318> also applies to all versions (at least) up to Windows Server 2019.
+ *
+ * Hopefully this will be fixed in future Windows versions.
  */
-static bool test_replay(struct torture_context *torture,
-                         struct smb2_tree *tree)
+static bool test_replay_broken_windows(struct torture_context *torture,
+                                      struct smb2_tree *tree)
 {
        NTSTATUS status;
        bool ret = true;
@@ -2884,11 +2912,11 @@ static bool test_replay(struct torture_context *torture,
        struct smb2_lock lck;
        struct smb2_lock_element el;
        uint8_t res_req[8];
-       const char *fname = BASEDIR "\\replay.txt";
+       const char *fname = BASEDIR "\\replay_broken_windows.txt";
        struct smb2_transport *transport = tree->session->transport;
 
        if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB2_10) {
-               torture_skip(torture, "SMB 2.100 Dialect family or above \
+               torture_skip(torture, "SMB 2.1.0 Dialect family or above \
                                required for Lock Replay tests\n");
        }
 
@@ -2919,7 +2947,27 @@ static bool test_replay(struct torture_context *torture,
        status = smb2_lock(tree, &lck);
        CHECK_STATUS(status, NT_STATUS_OK);
        status = smb2_lock(tree, &lck);
+       if (NT_STATUS_IS_OK(status)) {
+               lck.in.lock_sequence = 0x020 + 0x2;
+               status = smb2_lock(tree, &lck);
+               CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+               lck.in.lock_sequence = 0x010 + 0x1;
+               status = smb2_lock(tree, &lck);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               if (smbXcli_conn_protocol(transport->conn) > PROTOCOL_SMB2_10) {
+                       torture_skip_goto(torture, done,
+                                         "SMB3 Server implements LockSequence "
+                                         "for all handles\n");
+               }
+       }
        CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+       if (smbXcli_conn_protocol(transport->conn) > PROTOCOL_SMB2_10) {
+               torture_comment(torture,
+                               "\nSMB3 Server implements LockSequence as SMB 2.1.0"
+                               " LEGACY BROKEN Windows!!!\n\n");
+       }
+       torture_comment(torture,
+                       "Testing SMB 2.1.0 LockSequence for ResilientHandles\n");
 
        el.flags = SMB2_LOCK_FLAG_UNLOCK;
        status = smb2_lock(tree, &lck);
@@ -3183,7 +3231,8 @@ struct torture_suite *torture_smb2_lock_init(TALLOC_CTX *ctx)
        torture_suite_add_1smb2_test(suite, "range", test_range);
        torture_suite_add_2smb2_test(suite, "overlap", test_overlap);
        torture_suite_add_1smb2_test(suite, "truncate", test_truncate);
-       torture_suite_add_1smb2_test(suite, "replay", test_replay);
+       torture_suite_add_1smb2_test(suite, "replay_broken_windows",
+                                    test_replay_broken_windows);
        torture_suite_add_1smb2_test(suite, "ctdb-delrec-deadlock", test_deadlock);
 
        suite->description = talloc_strdup(suite, "SMB2-LOCK tests");