summaryrefslogtreecommitdiff
path: root/source4/torture
diff options
context:
space:
mode:
Diffstat (limited to 'source4/torture')
-rw-r--r--source4/torture/basic/denytest.c273
-rw-r--r--source4/torture/torture.c12
2 files changed, 281 insertions, 4 deletions
diff --git a/source4/torture/basic/denytest.c b/source4/torture/basic/denytest.c
index 6dd38e8e79..32f44044cc 100644
--- a/source4/torture/basic/denytest.c
+++ b/source4/torture/basic/denytest.c
@@ -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;
+}
diff --git a/source4/torture/torture.c b/source4/torture/torture.c
index 713e4cd6f1..08670a0724 100644
--- a/source4/torture/torture.c
+++ b/source4/torture/torture.c
@@ -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));