1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

r3386: - fixed --seed option in smbtorture

- 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 commit is contained in:
Andrew Tridgell 2004-10-30 04:59:52 +00:00 committed by Gerald (Jerry) Carter
parent 91139ed8d4
commit b95493d3d1
2 changed files with 281 additions and 4 deletions

View 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;
}

View 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));