summaryrefslogtreecommitdiff
path: root/source4/torture/basic/denytest.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/torture/basic/denytest.c')
-rw-r--r--source4/torture/basic/denytest.c273
1 files changed, 272 insertions, 1 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;
+}