summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/libsmb/clientgen.c10
-rw-r--r--source3/utils/torture.c336
3 files changed, 295 insertions, 52 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index d3d905481f..98c671ea86 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -69,6 +69,7 @@ void cli_shutdown(struct cli_state *cli);
char *cli_errstr(struct cli_state *cli);
void cli_error(struct cli_state *cli, int *eclass, int *num);
void cli_sockopt(struct cli_state *cli, char *options);
+int cli_setpid(struct cli_state *cli, int pid);
/*The following definitions come from clientutil.c */
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index b2ecb07ded..b98f2fca69 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -1072,3 +1072,13 @@ void cli_sockopt(struct cli_state *cli, char *options)
{
set_socket_options(cli->fd, options);
}
+
+/****************************************************************************
+set the PID to use for smb messages. Return the old pid.
+****************************************************************************/
+int cli_setpid(struct cli_state *cli, int pid)
+{
+ int ret = cli->pid;
+ cli->pid = pid;
+ return ret;
+}
diff --git a/source3/utils/torture.c b/source3/utils/torture.c
index f3d76e0ee2..67a363df27 100644
--- a/source3/utils/torture.c
+++ b/source3/utils/torture.c
@@ -25,7 +25,6 @@
#include "includes.h"
-static struct cli_state cli;
static fstring host, workgroup, share, password, username, myname;
static char *sockops="";
@@ -45,62 +44,61 @@ static double end_timer()
}
-static int open_connection(void)
+static BOOL open_connection(struct cli_state *c)
{
- if (!cli_initialise(&cli) || !cli_connect(&cli, host, NULL)) {
+ if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
printf("Failed to connect with %s\n", host);
+ return False;
}
- if (!cli_session_request(&cli, host, 0x20, myname)) {
+ if (!cli_session_request(c, host, 0x20, myname)) {
printf("%s rejected the session\n",host);
- cli_shutdown(&cli);
- return -1;
+ cli_shutdown(c);
+ return False;
}
- if (!cli_negprot(&cli)) {
- printf("%s rejected the negprot (%s)\n",host, cli_errstr(&cli));
- cli_shutdown(&cli);
- return -1;
+ if (!cli_negprot(c)) {
+ printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
}
- if (!cli_session_setup(&cli, username, password, strlen(password),
+ if (!cli_session_setup(c, username, password, strlen(password),
"", 0, workgroup)) {
- printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(&cli));
- cli_shutdown(&cli);
- return -1;
+ printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
}
- if (!cli_send_tconX(&cli, share, "A:", password, strlen(password)+1)) {
- printf("%s refused tree connect (%s)\n", host, cli_errstr(&cli));
- cli_shutdown(&cli);
- return -1;
+ if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
+ printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
}
- return 0;
+ return True;
}
-static void close_connection(void)
+static void close_connection(struct cli_state *c)
{
- if (!cli_tdis(&cli)) {
- printf("tdis failed (%s)\n", cli_errstr(&cli));
+ if (!cli_tdis(c)) {
+ printf("tdis failed (%s)\n", cli_errstr(c));
}
- cli_shutdown(&cli);
+ cli_shutdown(c);
}
-
-
-static BOOL wait_lock(int fnum, uint32 offset, uint32 len)
+static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
{
- while (!cli_lock(&cli, fnum, offset, len, -1)) {
+ while (!cli_lock(c, fnum, offset, len, -1)) {
int eclass, num;
- cli_error(&cli, &eclass, &num);
+ cli_error(c, &eclass, &num);
if (eclass != ERRDOS || num != ERRlock) {
printf("lock failed (%s)\n",
- cli_errstr(&cli));
+ cli_errstr(c));
return False;
}
}
@@ -108,7 +106,7 @@ static BOOL wait_lock(int fnum, uint32 offset, uint32 len)
}
-static int rw_torture(int numops)
+static BOOL rw_torture(struct cli_state *c, int numops)
{
char *lockfname = "\\torture.lck";
fstring fname;
@@ -117,13 +115,13 @@ static int rw_torture(int numops)
int pid2, pid = getpid();
int i;
- fnum2 = cli_open(&cli, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
DENY_NONE);
if (fnum2 == -1)
- fnum2 = cli_open(&cli, lockfname, O_RDWR, DENY_NONE);
+ fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
if (fnum2 == -1) {
- printf("open of %s failed (%s)\n", lockfname, cli_errstr(&cli));
- return -1;
+ printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
+ return False;
}
@@ -134,46 +132,46 @@ static int rw_torture(int numops)
}
sprintf(fname,"\\torture.%u", n);
- if (!wait_lock(fnum2, n*sizeof(int), sizeof(int))) {
- return -1;
+ if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ return False;
}
- fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
+ fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
if (fnum == -1) {
- printf("open failed (%s)\n", cli_errstr(&cli));
+ printf("open failed (%s)\n", cli_errstr(c));
break;
}
- if (cli_write(&cli, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
- printf("write failed (%s)\n", cli_errstr(&cli));
+ if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("write failed (%s)\n", cli_errstr(c));
}
pid2 = 0;
- if (cli_read(&cli, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
- printf("read failed (%s)\n", cli_errstr(&cli));
+ if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("read failed (%s)\n", cli_errstr(c));
}
if (pid2 != pid) {
printf("data corruption!\n");
}
- if (!cli_close(&cli, fnum)) {
- printf("close failed (%s)\n", cli_errstr(&cli));
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
}
- if (!cli_unlink(&cli, fname)) {
- printf("unlink failed (%s)\n", cli_errstr(&cli));
+ if (!cli_unlink(c, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c));
}
- if (!cli_unlock(&cli, fnum2, n*sizeof(int), sizeof(int), -1)) {
- printf("unlock failed (%s)\n", cli_errstr(&cli));
+ if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
+ printf("unlock failed (%s)\n", cli_errstr(c));
}
}
printf("%d\n", i);
- return 0;
+ return True;
}
static void usage(void)
@@ -195,15 +193,246 @@ static void usage(void)
static void run_torture(int numops)
{
- if (open_connection() == 0) {
+ static struct cli_state cli;
+
+ if (open_connection(&cli)) {
cli_sockopt(&cli, sockops);
printf("pid %d OK\n", getpid());
- rw_torture(numops);
+ rw_torture(&cli, numops);
+
+ close_connection(&cli);
+ }
+}
+
+/*
+ This test checks for two things:
+
+ 1) correct support for retaining locks over a close (ie. the server
+ must not use posix semantics)
+ 2) support for lock timeouts
+ */
+static void run_locktest1(void)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\locktest.lck";
+ int fnum1, fnum2, fnum3;
+ time_t t1, t2;
- close_connection();
+ if (!open_connection(&cli1) || !open_connection(&cli2)) {
+ return;
}
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest1\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+
+ printf("Testing lock timeouts\n");
+ t1 = time(NULL);
+ if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+ t2 = time(NULL);
+
+ if (t2 - t1 < 5) {
+ printf("This server appears not to support timed lock requests\n");
+ }
+
+ if (!cli_close(&cli1, fnum2)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock4 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_close(&cli2, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ close_connection(&cli1);
+ close_connection(&cli2);
+
+ printf("Passed locktest1\n");
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports multiple locking contexts on the one SMB
+ connection, distinguished by PID.
+
+ 2) the server correctly fails overlapping locks made by the same PID (this
+ goes against POSIX behaviour, which is why it is tricky to implement)
+
+ 3) the server denies unlock requests by an incorrect client PID
+*/
+static void run_locktest2(void)
+{
+ static struct cli_state cli;
+ char *fname = "\\locktest.lck";
+ int fnum1, fnum2, fnum3;
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ printf("starting locktest2\n");
+
+ cli_unlink(&cli, fname);
+
+ cli_setpid(&cli, 1);
+
+ fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ cli_setpid(&cli, 2);
+
+ fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (cli_lock(&cli, fnum2, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 2);
+
+ if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
+ printf("unlock1 succeeded! This is a locking bug\n");
+ }
+
+ if (cli_lock(&cli, fnum3, 0, 4, 0)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_close(&cli, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ close_connection(&cli);
+
+ printf("locktest2 finished\n");
}
@@ -317,6 +546,9 @@ static void create_procs(int nprocs, int numops)
create_procs(nprocs, numops);
printf("rw_torture: %g secs\n", end_timer());
+ run_locktest1();
+ run_locktest2();
+
return(0);
}