r3386: - fixed --seed option in smbtorture
authorAndrew Tridgell <tridge@samba.org>
Sat, 30 Oct 2004 04:59:52 +0000 (04:59 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:05:03 +0000 (13:05 -0500)
- added new tests BASE-NTDENY1 and BASE-NTDENY2. These are the
  ntcreatex equivalents of the BASE-DENY1 and BASE-DENY2
  tests. Unfortunately, with ntcreatex there are 4 million combination
  and trying each one takes 1 second, so randomised testing is the
  only choice. The BASE-DENY1 test can operate in parallel with
  hundreds of connections, speeding things up a bit (as most time is
  spent waiting 1 second for a sharing violation to come back)
(This used to be commit b95493d3d16581b8dd8f4727cd10631c18e16748)

source4/torture/basic/denytest.c
source4/torture/torture.c

index 6dd38e8e79cea93fb88d4c31a0201662eb51ed95..32f44044cc6b3282323ac6ba50b4b49711c5d504 100644 (file)
@@ -1398,7 +1398,6 @@ static const struct {
 
 static void progress_bar(uint_t i, uint_t total)
 {
-       if (i % 10 != 0) return;
        printf("%5d/%5d\r", i, total);
        fflush(stdout);
 }
@@ -1651,3 +1650,275 @@ BOOL torture_denytest3(void)
        return True;
 }
 
+struct bit_value {
+       uint32_t value;
+       const char *name;
+};
+
+static uint32_t map_bits(const struct bit_value *bv, int b, int nbits)
+{
+       int i;
+       uint32_t ret = 0;
+       for (i=0;i<nbits;i++) {
+               if (b & (1<<i)) {
+                       ret |= bv[i].value;
+               }
+       }
+       return ret;
+}
+
+static const char *bit_string(TALLOC_CTX *mem_ctx, const struct bit_value *bv, int b, int nbits)
+{
+       char *ret = NULL;
+       int i;
+       for (i=0;i<nbits;i++) {
+               if (b & (1<<i)) {
+                       if (ret == NULL) {
+                               ret = talloc_asprintf(mem_ctx, "%s", bv[i].name);
+                       } else {
+                               ret = talloc_asprintf_append(ret, " | %s", bv[i].name);
+                       }
+               }
+       }
+       if (ret == NULL) ret = talloc_strdup(mem_ctx, "(NONE)");
+       return ret;
+}
+
+
+/*
+  determine if two opens conflict
+*/
+static NTSTATUS predict_share_conflict(uint32_t sa1, uint32_t am1, uint32_t sa2, uint32_t am2,
+                                      enum deny_result *res)
+{
+#define CHECK_MASK(am, sa, right, share) do { \
+       if (((am) & (right)) && !((sa) & (share))) { \
+               *res = A_0; \
+               return NT_STATUS_SHARING_VIOLATION; \
+       }} while (0)
+
+       *res = A_0;
+       if (am2 & SA_RIGHT_FILE_WRITE_APPEND) {
+               *res += A_W;
+       }
+       if (am2 & SA_RIGHT_FILE_READ_DATA) {
+               *res += A_R;
+       }
+
+       /* if either open involves no read.write or delete access then
+          it can't conflict */
+       if (!(am1 & (SA_RIGHT_FILE_WRITE_APPEND | 
+                    SA_RIGHT_FILE_READ_EXEC | 
+                    STD_RIGHT_DELETE_ACCESS))) {
+               return NT_STATUS_OK;
+       }
+       if (!(am2 & (SA_RIGHT_FILE_WRITE_APPEND | 
+                    SA_RIGHT_FILE_READ_EXEC | 
+                    STD_RIGHT_DELETE_ACCESS))) {
+               return NT_STATUS_OK;
+       }
+
+       /* check the basic share access */
+       CHECK_MASK(am1, sa2, 
+                  SA_RIGHT_FILE_WRITE_APPEND, 
+                  NTCREATEX_SHARE_ACCESS_WRITE);
+       CHECK_MASK(am2, sa1, 
+                  SA_RIGHT_FILE_WRITE_APPEND, 
+                  NTCREATEX_SHARE_ACCESS_WRITE);
+
+       CHECK_MASK(am1, sa2, 
+                  SA_RIGHT_FILE_READ_EXEC, 
+                  NTCREATEX_SHARE_ACCESS_READ);
+       CHECK_MASK(am2, sa1, 
+                  SA_RIGHT_FILE_READ_EXEC, 
+                  NTCREATEX_SHARE_ACCESS_READ);
+
+       CHECK_MASK(am1, sa2, 
+                  STD_RIGHT_DELETE_ACCESS, 
+                  NTCREATEX_SHARE_ACCESS_DELETE);
+       CHECK_MASK(am2, sa1, 
+                  STD_RIGHT_DELETE_ACCESS, 
+                  NTCREATEX_SHARE_ACCESS_DELETE);
+
+       return NT_STATUS_OK;
+}
+
+/*
+  a denytest for ntcreatex
+ */
+static BOOL torture_ntdenytest(struct smbcli_state *cli1, struct smbcli_state *cli2, int client)
+{
+       const struct bit_value share_access_bits[] = {
+               { NTCREATEX_SHARE_ACCESS_READ,   "S_R" },
+               { NTCREATEX_SHARE_ACCESS_WRITE,  "S_W" },
+               { NTCREATEX_SHARE_ACCESS_DELETE, "S_D" }
+       };
+       const struct bit_value access_mask_bits[] = {
+               { SA_RIGHT_FILE_READ_DATA,        "R_DATA" },
+               { SA_RIGHT_FILE_WRITE_DATA,       "W_DATA" },
+               { SA_RIGHT_FILE_READ_ATTRIBUTES,  "R_ATTR" },
+               { SA_RIGHT_FILE_WRITE_ATTRIBUTES, "W_ATTR" },
+               { SA_RIGHT_FILE_READ_EA,          "R_EAS " },
+               { SA_RIGHT_FILE_WRITE_EA,         "W_EAS " },
+               { SA_RIGHT_FILE_APPEND_DATA,      "A_DATA" },
+               { SA_RIGHT_FILE_EXECUTE,          "EXEC  " }
+       };
+       int fnum1;
+       int i;
+       BOOL correct = True;
+       struct timeval tv, tv_start;
+       const char *fname;
+       int nbits1 = ARRAY_SIZE(share_access_bits);
+       int nbits2 = ARRAY_SIZE(access_mask_bits);
+       union smb_open io1, io2;
+       extern int torture_numops;
+       int failures = 0;
+
+       fname = talloc_asprintf(cli1, "\\ntdeny_%d.dat", client);
+
+       smbcli_unlink(cli1->tree, fname);
+       fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       smbcli_write(cli1->tree, fnum1, 0, fname, 0, strlen(fname));
+       smbcli_close(cli1->tree, fnum1);
+
+       GetTimeOfDay(&tv_start);
+
+       io1.ntcreatex.level = RAW_OPEN_NTCREATEX;
+       io1.ntcreatex.in.root_fid = 0;
+       io1.ntcreatex.in.flags = 0;
+       io1.ntcreatex.in.create_options = 0;
+       io1.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       io1.ntcreatex.in.alloc_size = 0;
+       io1.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       io1.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io1.ntcreatex.in.security_flags = 0;
+       io1.ntcreatex.in.fname = fname;
+       io2 = io1;
+
+       printf("testing %d entries on %s\n", torture_numops, fname);
+
+       for (i=0;i<torture_numops;i++) {
+               NTSTATUS status1, status2, status2_p;
+               int64_t tdif;
+               TALLOC_CTX *mem_ctx = talloc(NULL, 0);
+               enum deny_result res, res2;
+               int b_sa1 = random() & ((1<<nbits1)-1);
+               int b_am1 = random() & ((1<<nbits2)-1);
+               int b_sa2 = random() & ((1<<nbits1)-1);
+               int b_am2 = random() & ((1<<nbits2)-1);
+
+               progress_bar(i, torture_numops);
+               
+               io1.ntcreatex.in.share_access = map_bits(share_access_bits, b_sa1, nbits1);
+               io1.ntcreatex.in.access_mask  = map_bits(access_mask_bits,  b_am1, nbits2);
+               
+               io2.ntcreatex.in.share_access = map_bits(share_access_bits, b_sa2, nbits1);
+               io2.ntcreatex.in.access_mask  = map_bits(access_mask_bits,  b_am2, nbits2);
+               
+               status1 = smb_raw_open(cli1->tree, mem_ctx, &io1);
+               status2 = smb_raw_open(cli2->tree, mem_ctx, &io2);
+               
+               if (!NT_STATUS_IS_OK(status1)) {
+                       res = A_X;
+               } else if (!NT_STATUS_IS_OK(status2)) {
+                       res = A_0;
+               } else {
+                       char x = 1;
+                       res = A_0;
+                       if (smbcli_read(cli2->tree, 
+                                       io2.ntcreatex.out.fnum, (void *)&x, 0, 1) == 1) {
+                               res += A_R;
+                       }
+                       if (smbcli_write(cli2->tree, 
+                                        io2.ntcreatex.out.fnum, 0, (void *)&x, 0, 1) == 1) {
+                               res += A_W;
+                       }
+               }
+               
+               if (NT_STATUS_IS_OK(status1)) {
+                       smbcli_close(cli1->tree, io1.ntcreatex.out.fnum);
+               }
+               if (NT_STATUS_IS_OK(status2)) {
+                       smbcli_close(cli2->tree, io2.ntcreatex.out.fnum);
+               }
+               
+               status2_p = predict_share_conflict(io1.ntcreatex.in.share_access,
+                                                  io1.ntcreatex.in.access_mask,
+                                                  io2.ntcreatex.in.share_access,
+                                                  io2.ntcreatex.in.access_mask, &res2);
+               
+               GetTimeOfDay(&tv);
+               tdif = usec_time_diff(&tv, &tv_start);
+               tdif /= 1000;
+               if (torture_showall || 
+                   !NT_STATUS_EQUAL(status2, status2_p) ||
+                   res != res2) {
+                       printf("\n%-20s %-70s\n%-20s %-70s %4s %4s  %s/%s\n",
+                              bit_string(mem_ctx, share_access_bits, b_sa1, nbits1),
+                              bit_string(mem_ctx, access_mask_bits,  b_am1, nbits2),
+                              bit_string(mem_ctx, share_access_bits, b_sa2, nbits1),
+                              bit_string(mem_ctx, access_mask_bits,  b_am2, nbits2),
+                              resultstr(res),
+                              resultstr(res2),
+                              nt_errstr(status2),
+                              nt_errstr(status2_p));
+                       fflush(stdout);
+               }
+               
+               if (res != res2 ||
+                   !NT_STATUS_EQUAL(status2, status2_p)) {
+                       CHECK_MAX_FAILURES(failed);
+                       correct = False;
+               }
+               
+               talloc_free(mem_ctx);
+       }
+
+failed:
+       smbcli_unlink(cli1->tree, fname);
+       
+       printf("finshed ntdenytest (%d failures)\n", failures);
+       return correct;
+}
+
+
+
+/*
+  a denytest for ntcreatex
+ */
+BOOL torture_ntdenytest1(struct smbcli_state *cli, int client)
+{
+       extern int torture_seed;
+
+       srandom(torture_seed + client);
+
+       printf("starting ntdenytest1 client %d\n", client);
+
+       return torture_ntdenytest(cli, cli, client);
+}
+
+/*
+  a denytest for ntcreatex
+ */
+BOOL torture_ntdenytest2(void)
+{
+       struct smbcli_state *cli1, *cli2;
+       BOOL ret;
+
+       if (!torture_open_connection(&cli1)) {
+               return False;
+       }
+
+       if (!torture_open_connection(&cli2)) {
+               return False;
+       }
+
+       printf("starting ntdenytest2\n");
+
+       ret = torture_ntdenytest(cli1, cli2, 0);
+
+       torture_close_connection(cli1);
+       torture_close_connection(cli2);
+
+       return ret;
+}
index 713e4cd6f1803073b10af9cf740b5c8fbc069e47..08670a072467950506368dddf5ed783759bf8f4b 100644 (file)
@@ -24,6 +24,7 @@ int torture_nprocs=4;
 int torture_numops=100;
 int torture_entries=1000;
 int torture_failures=1;
+int torture_seed=0;
 static int procnum; /* records process count number when forking */
 static struct smbcli_state *current_cli;
 static BOOL use_oplocks;
@@ -359,7 +360,6 @@ static BOOL rw_torture3(struct smbcli_state *c, const char *lockfname)
        ssize_t sent = 0;
        BOOL correct = True;
 
-       srandom(1);
        for (i = 0; i < sizeof(buf); i += sizeof(uint32_t))
        {
                SIVAL(buf, i, sys_random());
@@ -2419,6 +2419,8 @@ static struct {
        {"BASE-DENY1",  torture_denytest1, 0},
        {"BASE-DENY2",  torture_denytest2, 0},
        {"BASE-DENY3",  torture_denytest3, 0},
+       {"BASE-NTDENY1",  NULL, torture_ntdenytest1},
+       {"BASE-NTDENY2",  torture_ntdenytest2, 0},
        {"BASE-TCON",  run_tcon_test, 0},
        {"BASE-TCONDEV",  run_tcon_devtype_test, 0},
        {"BASE-VUID", run_vuidtest, 0},
@@ -2655,7 +2657,7 @@ static BOOL is_binding_string(const char *binding_string)
        struct poptOption long_options[] = {
                POPT_AUTOHELP
                {"smb-ports",   'p', POPT_ARG_STRING, NULL,             0,      "SMB ports",    NULL},
-               {"seed",          0, POPT_ARG_STRING, NULL,             0,      "seed",         NULL},
+               {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "seed",         NULL},
                {"num-progs",     0, POPT_ARG_INT,  &torture_nprocs,    0,      "num progs",    NULL},
                {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
                {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
@@ -2712,7 +2714,11 @@ static BOOL is_binding_string(const char *binding_string)
 
        lp_load(dyn_CONFIGFILE,True,False,False);
        load_interfaces();
-       srandom(time(NULL));
+       if (torture_seed == 0) {
+               torture_seed = time(NULL);
+       } 
+       printf("Using seed %d\n", torture_seed);
+       srandom(torture_seed);
 
        argv_new = discard_const_p(char *, poptGetArgs(pc));