]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4/torture: add a comprehensive "non-oplock-break-trigger" access mask test case
authorRalph Boehme <slow@samba.org>
Tue, 3 Mar 2020 11:09:09 +0000 (12:09 +0100)
committerJeremy Allison <jra@samba.org>
Thu, 30 Apr 2020 19:32:44 +0000 (19:32 +0000)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14357

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/knownfail
source4/torture/smb2/oplock.c

index 09276dd22613a809b337d795c1eb5c0cb10d0da2..6394a2957c348cd9f6f2be5c38f889d34881dbd1 100644 (file)
 ^samba4.smb2.oplock.batch20\(.*\)$ # samba 4 oplocks are a mess
 ^samba4.smb2.oplock.batch26\(.*\)$
 ^samba4.smb2.oplock.stream1 # samba 4 oplocks are a mess
+^samba4.smb2.oplock.statopen1\(ad_dc_ntvfs\)$ # fails with ACCESS_DENIED on a SYNCHRONIZE_ACCESS open
 ^samba4.smb2.getinfo.complex # streams on directories does not work
 ^samba4.smb2.getinfo.qfs_buffercheck # S4 does not do the INFO_LENGTH_MISMATCH/BUFFER_OVERFLOW thingy
 ^samba4.smb2.getinfo.qfile_buffercheck # S4 does not do the INFO_LENGTH_MISMATCH/BUFFER_OVERFLOW thingy
index 30bbd92e7ec3f3ac215a7d84e65321dd5774f285..72c63353533e26331f366018931d23db2046b851 100644 (file)
@@ -38,6 +38,7 @@
 #include "torture/smb2/proto.h"
 
 #include "lib/util/sys_rw.h"
+#include "libcli/security/security.h"
 
 #define CHECK_RANGE(v, min, max) do { \
        if ((v) < (min) || (v) > (max)) { \
@@ -3968,6 +3969,159 @@ static bool test_smb2_oplock_levelII502(struct torture_context *tctx,
        return true;
 }
 
+static bool test_oplock_statopen1_do(struct torture_context *tctx,
+                                    struct smb2_tree *tree,
+                                    uint32_t access_mask,
+                                    bool expect_stat_open)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(tctx);
+       struct smb2_create cr;
+       struct smb2_handle h1 = {{0}};
+       struct smb2_handle h2 = {{0}};
+       NTSTATUS status;
+       const char *fname = "oplock_statopen1.dat";
+       bool ret = true;
+
+       /* Open file with exclusive oplock. */
+       cr = (struct smb2_create) {
+               .in.desired_access = SEC_FILE_ALL,
+               .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+               .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+               .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+               .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+               .in.fname = fname,
+               .in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH,
+       };
+       status = smb2_create(tree, mem_ctx, &cr);
+       torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+                                       "smb2_create failed\n");
+       h1 = cr.out.file.handle;
+       CHECK_VAL(cr.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+       /* Stat open */
+       cr = (struct smb2_create) {
+               .in.desired_access = access_mask,
+               .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+               .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+               .in.create_disposition = NTCREATEX_DISP_OPEN,
+               .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+               .in.fname = fname,
+       };
+       status = smb2_create(tree, mem_ctx, &cr);
+       torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+                                       "smb2_create failed\n");
+       h2 = cr.out.file.handle;
+
+       if (expect_stat_open) {
+               torture_wait_for_oplock_break(tctx);
+               CHECK_VAL(break_info.count, 0);
+               CHECK_VAL(break_info.level, 0);
+               CHECK_VAL(break_info.failures, 0);
+               if (!ret) {
+                       goto done;
+               }
+       } else {
+               CHECK_VAL(break_info.count, 1);
+       }
+
+done:
+       if (!smb2_util_handle_empty(h2)) {
+               smb2_util_close(tree, h2);
+       }
+       if (!smb2_util_handle_empty(h1)) {
+               smb2_util_close(tree, h1);
+       }
+       talloc_free(mem_ctx);
+       return ret;
+}
+
+static bool test_smb2_oplock_statopen1(struct torture_context *tctx,
+                                      struct smb2_tree *tree)
+{
+       const char *fname = "oplock_statopen1.dat";
+       size_t i;
+       bool ret = true;
+       struct {
+               uint32_t access_mask;
+               bool expect_stat_open;
+       } tests[] = {
+               {
+                       .access_mask = FILE_READ_DATA,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = FILE_WRITE_DATA,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = FILE_READ_EA,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = FILE_WRITE_EA,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = FILE_EXECUTE,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = FILE_READ_ATTRIBUTES,
+                       .expect_stat_open = true,
+               },
+               {
+                       .access_mask = FILE_WRITE_ATTRIBUTES,
+                       .expect_stat_open = true,
+               },
+               {
+                       .access_mask = DELETE_ACCESS,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = READ_CONTROL_ACCESS,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = WRITE_DAC_ACCESS,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = WRITE_OWNER_ACCESS,
+                       .expect_stat_open = false,
+               },
+               {
+                       .access_mask = SYNCHRONIZE_ACCESS,
+                       .expect_stat_open = true,
+               },
+       };
+
+       tree->session->transport->oplock.handler = torture_oplock_handler;
+       tree->session->transport->oplock.private_data = tree;
+
+       for (i = 0; i < ARRAY_SIZE(tests); i++) {
+               ZERO_STRUCT(break_info);
+
+               ret = test_oplock_statopen1_do(tctx,
+                                              tree,
+                                              tests[i].access_mask,
+                                              tests[i].expect_stat_open);
+               if (ret == true) {
+                       continue;
+               }
+               torture_result(tctx, TORTURE_FAIL,
+                              "test %zu: access_mask: %s, "
+                              "expect_stat_open: %s\n",
+                              i,
+                              get_sec_mask_str(tree, tests[i].access_mask),
+                              tests[i].expect_stat_open ? "yes" : "no");
+               goto done;
+       }
+
+done:
+       smb2_util_unlink(tree, fname);
+       return ret;
+}
+
 struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx)
 {
        struct torture_suite *suite =
@@ -4016,6 +4170,7 @@ struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx)
                                     test_smb2_oplock_levelII501);
        torture_suite_add_2smb2_test(suite, "levelii502",
                                     test_smb2_oplock_levelII502);
+       torture_suite_add_1smb2_test(suite, "statopen1", test_smb2_oplock_statopen1);
        suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
 
        return suite;