fixed a connection bug in torture test
[samba.git] / source3 / utils / torture.c
index d1bd6e5f00e5f027f115f646ebd12812e1a67479..3ef4d5133f7d8e627d38616f44c6cecdd19cfdbe 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    SMB torture tester
-   Copyright (C) Andrew Tridgell 1997
+   Copyright (C) Andrew Tridgell 1997-1998
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -19,9 +19,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#ifdef SYSLOG
-#undef SYSLOG
-#endif
+#define NO_SYSLOG
 
 #include "includes.h"
 
@@ -32,12 +30,12 @@ static char *sockops="";
 
 static struct timeval tp1,tp2;
 
-static void start_timer()
+static void start_timer(void)
 {
        gettimeofday(&tp1,NULL);
 }
 
-static double end_timer()
+static double end_timer(void)
 {
        gettimeofday(&tp2,NULL);
        return((tp2.tv_sec - tp1.tv_sec) + 
@@ -47,33 +45,41 @@ static double end_timer()
 
 static BOOL open_connection(struct cli_state *c)
 {
+       struct nmb_name called, calling;
+
+       ZERO_STRUCTP(c);
+
+       make_nmb_name(&calling, myname, 0x0, "");
+       make_nmb_name(&called , host, 0x20, "");
+
        if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
                printf("Failed to connect with %s\n", host);
                return False;
        }
 
-       if (!cli_session_request(c, host, 0x20, myname)) {
-               printf("%s rejected the session\n",host);
+       if (!cli_session_request(c, &calling, &called)) {
                cli_shutdown(c);
+               printf("%s rejected the session\n",host);
                return False;
        }
 
-       c->protocol = max_protocol;
-
        if (!cli_negprot(c)) {
                printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
                cli_shutdown(c);
                return False;
        }
 
-       if (!cli_session_setup(c, username, password, strlen(password),
-                              "", 0, workgroup)) {
-               printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
+       if (!cli_session_setup(c, username, 
+                              password, strlen(password),
+                              password, strlen(password),
+                              workgroup)) {
                cli_shutdown(c);
+               printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
                return False;
        }
 
-       if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
+       if (!cli_send_tconX(c, share, "?????",
+                           password, strlen(password)+1)) {
                printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
                cli_shutdown(c);
                return False;
@@ -94,16 +100,30 @@ static void close_connection(struct cli_state *c)
 }
 
 
+/* check if the server produced the expected error code */
+static BOOL check_error(struct cli_state *c, 
+                       uint8 eclass, uint32 ecode, uint32 nterr)
+{
+       uint8 class;
+       uint32 num;
+       int eno;
+       eno = cli_error(c, &class, &num);
+       if ((eclass != class || ecode != num) &&
+           num != (nterr&0xFFFFFF)) {
+               printf("unexpected error code class=%d code=%d\n", 
+                        (int)class, (int)num);
+               printf(" expected %d/%d %d\n", 
+                      (int)eclass, (int)ecode, (int)nterr);
+               return False;
+       }
+       return True;
+}
+
+
 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
 {
        while (!cli_lock(c, fnum, offset, len, -1)) {
-               int eclass, num;
-               cli_error(c, &eclass, &num);
-               if (eclass != ERRDOS || num != ERRlock) {
-                       printf("lock failed (%s)\n", 
-                              cli_errstr(c));
-                       return False;
-               }
+               if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
        }
        return True;
 }
@@ -116,7 +136,8 @@ static BOOL rw_torture(struct cli_state *c, int numops)
        int fnum;
        int fnum2;
        int pid2, pid = getpid();
-       int i;
+       int i, j;
+       char buf[1024];
 
        fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
                         DENY_NONE);
@@ -129,11 +150,11 @@ static BOOL rw_torture(struct cli_state *c, int numops)
 
 
        for (i=0;i<numops;i++) {
-               unsigned n = (unsigned)random()%10;
+               unsigned n = (unsigned)sys_random()%10;
                if (i % 10 == 0) {
                        printf("%d\r", i); fflush(stdout);
                }
-               sprintf(fname,"\\torture.%u", n);
+               slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
 
                if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
                        return False;
@@ -145,10 +166,18 @@ static BOOL rw_torture(struct cli_state *c, int numops)
                        break;
                }
 
-               if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+               if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
                        printf("write failed (%s)\n", cli_errstr(c));
                }
 
+               for (j=0;j<50;j++) {
+                       if (cli_write(c, fnum, 0, (char *)buf, 
+                                     sizeof(pid)+(j*sizeof(buf)), 
+                                     sizeof(buf)) != sizeof(buf)) {
+                               printf("write failed (%s)\n", cli_errstr(c));
+                       }
+               }
+
                pid2 = 0;
 
                if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
@@ -172,6 +201,9 @@ static BOOL rw_torture(struct cli_state *c, int numops)
                }
        }
 
+       cli_close(c, fnum2);
+       cli_unlink(c, lockfname);
+
        printf("%d\n", i);
 
        return True;
@@ -179,7 +211,7 @@ static BOOL rw_torture(struct cli_state *c, int numops)
 
 static void usage(void)
 {
-       printf("Usage: smbtorture \\\\server\\share <options>\n");
+       printf("Usage: smbtorture //server/share <options>\n");
 
        printf("\t-U user%%pass\n");
        printf("\t-N numprocs\n");
@@ -220,7 +252,7 @@ static void run_torture(int numops)
 static void run_locktest1(void)
 {
        static struct cli_state cli1, cli2;
-       char *fname = "\\locktest.lck";
+       char *fname = "\\lockt1.lck";
        int fnum1, fnum2, fnum3;
        time_t t1, t2;
 
@@ -260,13 +292,7 @@ static void run_locktest1(void)
                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;
-               }
+               if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
        }
 
 
@@ -276,13 +302,7 @@ static void run_locktest1(void)
                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;
-               }
+               if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
        }
        t2 = time(NULL);
 
@@ -299,13 +319,7 @@ static void run_locktest1(void)
                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 (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
        }
 
        if (!cli_close(&cli1, fnum1)) {
@@ -345,7 +359,7 @@ static void run_locktest1(void)
 static void run_locktest2(void)
 {
        static struct cli_state cli;
-       char *fname = "\\locktest.lck";
+       char *fname = "\\lockt2.lck";
        int fnum1, fnum2, fnum3;
 
        if (!open_connection(&cli)) {
@@ -390,13 +404,7 @@ static void run_locktest2(void)
        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;
-               }
+               if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
        }
 
        cli_setpid(&cli, 2);
@@ -408,13 +416,7 @@ static void run_locktest2(void)
        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;
-               }
+               if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
        }
 
        cli_setpid(&cli, 1);
@@ -448,7 +450,7 @@ static void run_locktest2(void)
 static void run_locktest3(int numops)
 {
        static struct cli_state cli1, cli2;
-       char *fname = "\\locktest.lck";
+       char *fname = "\\lockt3.lck";
        int fnum1, fnum2, i;
        uint32 offset;
 
@@ -554,6 +556,59 @@ static void run_locktest3(int numops)
 }
 
 
+/*
+test whether fnums and tids open on one VC are available on another (a major
+security hole)
+*/
+static void run_fdpasstest(void)
+{
+       static struct cli_state cli1, cli2;
+       char *fname = "\\fdpass.tst";
+       int fnum1;
+       pstring buf;
+
+       if (!open_connection(&cli1) || !open_connection(&cli2)) {
+               return;
+       }
+       cli_sockopt(&cli1, sockops);
+       cli_sockopt(&cli2, sockops);
+
+       printf("starting fdpasstest\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;
+       }
+
+       if (cli_write(&cli1, fnum1, 0, "hello world\n", 0, 13) != 13) {
+               printf("write failed (%s)\n", cli_errstr(&cli1));
+               return;
+       }
+
+       cli2.vuid = cli1.vuid;
+       cli2.cnum = cli1.cnum;
+       cli2.pid = cli1.pid;
+
+
+       if (cli_read(&cli2, fnum1, buf, 0, 13) == 13) {
+               printf("read succeeded! nasty security hole [%s]\n",
+                      buf);
+               return;
+       }
+
+       cli_close(&cli1, fnum1);
+       cli_unlink(&cli1, fname);
+
+       close_connection(&cli1);
+       close_connection(&cli2);
+
+       printf("finished fdpasstest\n");
+}
+
+
 /*
   This test checks that 
 
@@ -587,19 +642,122 @@ static void run_unlinktest(void)
                printf("error: server allowed unlink on an open file\n");
        }
 
+       cli_close(&cli, fnum);
+       cli_unlink(&cli, fname);
+
        close_connection(&cli);
 
        printf("unlink test finished\n");
 }
 
 
+/*
+test how many open files this server supports on the one socket
+*/
+static void run_maxfidtest(int n)
+{
+       static struct cli_state cli;
+       char *template = "\\maxfid.%d.%d";
+       fstring fname;
+       int fnum;
+       int retries=4;
+
+       srandom(getpid());
+
+       while (!open_connection(&cli) && retries--) msleep(random() % 2000);
+
+       if (retries <= 0) {
+               printf("failed to connect\n");
+               return;
+       }
+
+       cli_sockopt(&cli, sockops);
+
+       printf("starting maxfid test\n");
+
+       fnum = 0;
+       while (1) {
+               slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
+               if (cli_open(&cli, fname, 
+                            O_RDWR|O_CREAT|O_TRUNC, DENY_NONE) ==
+                   -1) {
+                       printf("open of %s failed (%s)\n", 
+                              fname, cli_errstr(&cli));
+                       printf("maximum fnum is %d\n", fnum);
+                       break;
+               }
+               fnum++;
+       }
+
+       printf("cleaning up\n");
+       while (fnum > n) {
+               fnum--;
+               slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
+               if (cli_unlink(&cli, fname)) {
+                       printf("unlink of %s failed (%s)\n", 
+                              fname, cli_errstr(&cli));
+               }
+       }
+
+       printf("maxfid test finished\n");
+       close_connection(&cli);
+}
+
+/* generate a random buffer */
+static void rand_buf(char *buf, int len)
+{
+       while (len--) {
+               *buf = sys_random();
+               buf++;
+       }
+}
+
+/* send random IPC commands */
+static void run_randomipc(void)
+{
+       char *rparam = NULL;
+       char *rdata = NULL;
+       int rdrcnt,rprcnt;
+       pstring param;
+       int api, param_len, i;
+       static struct cli_state cli;
+
+       printf("starting random ipc test\n");
+
+       if (!open_connection(&cli)) {
+               return;
+       }
 
-static void browse_callback(char *sname, uint32 stype, char *comment)
+       for (i=0;i<50000;i++) {
+               api = sys_random() % 500;
+               param_len = (sys_random() % 64);
+
+               rand_buf(param, param_len);
+  
+               SSVAL(param,0,api); 
+
+               cli_api(&cli, 
+                       param, param_len, 8,  
+                       NULL, 0, BUFFER_SIZE, 
+                       &rparam, &rprcnt,     
+                       &rdata, &rdrcnt);
+       }
+
+       close_connection(&cli);
+
+       printf("finished random ipc test\n");
+}
+
+
+
+static void browse_callback(const char *sname, uint32 stype, 
+                           const char *comment)
 {
        printf("\t%20.20s %08x %s\n", sname, stype, comment);
 }
 
 
+
 /*
   This test checks the browse list code
 
@@ -608,7 +766,7 @@ static void run_browsetest(void)
 {
        static struct cli_state cli;
 
-       printf("staring browse test\n");
+       printf("starting browse test\n");
 
        if (!open_connection(&cli)) {
                return;
@@ -640,7 +798,7 @@ static void run_attrtest(void)
        time_t t, t2;
        char *fname = "\\attrib.tst";
 
-       printf("staring attrib test\n");
+       printf("starting attrib test\n");
 
        if (!open_connection(&cli)) {
                return;
@@ -676,6 +834,8 @@ static void run_attrtest(void)
                printf("%s", ctime(&t2));
        }
 
+       cli_unlink(&cli, fname);
+
        close_connection(&cli);
 
        printf("attrib test finished\n");
@@ -689,11 +849,13 @@ static void run_trans2test(void)
 {
        static struct cli_state cli;
        int fnum;
-       uint32 size;
-       time_t c_time, a_time, m_time, w_time;
+       size_t size;
+       time_t c_time, a_time, m_time, w_time, m_time2;
        char *fname = "\\trans2.tst";
+       char *dname = "\\trans2";
+       char *fname2 = "\\trans2\\trans2.tst";
 
-       printf("staring trans2 test\n");
+       printf("starting trans2 test\n");
 
        if (!open_connection(&cli)) {
                return;
@@ -702,7 +864,7 @@ static void run_trans2test(void)
        cli_unlink(&cli, fname);
        fnum = cli_open(&cli, fname, 
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
-       if (!cli_qfileinfo(&cli, fnum, &c_time, &a_time, &m_time, &size)) {
+       if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time)) {
                printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
        }
        cli_close(&cli, fnum);
@@ -714,7 +876,7 @@ static void run_trans2test(void)
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
        cli_close(&cli, fnum);
 
-       if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size)) {
+       if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
                printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
        } else {
                if (c_time != m_time) {
@@ -727,7 +889,7 @@ static void run_trans2test(void)
                        printf("This system appears to set a midnight access time\n");
                }
 
-               if (abs(m_time - time(NULL)) > 60) {
+               if (abs(m_time - time(NULL)) > 60*60*24*7) {
                        printf("ERROR: totally incorrect times - maybe word reversed?\n");
                }
        }
@@ -738,7 +900,7 @@ static void run_trans2test(void)
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
        cli_close(&cli, fnum);
        if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time, 
-                           &w_time, &size)) {
+                           &w_time, &size, NULL)) {
                printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
        } else {
                if (w_time < 60*60*24*2) {
@@ -747,21 +909,50 @@ static void run_trans2test(void)
                }
        }
 
+       cli_unlink(&cli, fname);
+
+
+       /* check if the server updates the directory modification time
+           when creating a new file */
+       if (!cli_mkdir(&cli, dname)) {
+               printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
+       }
+       sleep(3);
+       if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time, 
+                           &w_time, &size, NULL)) {
+               printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+       }
+
+       fnum = cli_open(&cli, fname2, 
+                       O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+       cli_write(&cli, fnum,  0, (char *)&fnum, 0, sizeof(fnum));
+       cli_close(&cli, fnum);
+       if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2, 
+                           &w_time, &size, NULL)) {
+               printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+       } else {
+               if (m_time2 == m_time)
+                       printf("This system does not update directory modification times\n");
+       }
+       cli_unlink(&cli, fname2);
+       cli_rmdir(&cli, dname);
+
+
        close_connection(&cli);
 
        printf("trans2 test finished\n");
 }
 
 
-static void create_procs(int nprocs, int numops)
+static void create_procs(int nprocs, int numops, void (*fn)(int ))
 {
        int i, status;
 
        for (i=0;i<nprocs;i++) {
                if (fork() == 0) {
                        int mypid = getpid();
-                       srandom(mypid ^ time(NULL));
-                       run_torture(numops);
+                       sys_srandom(mypid ^ time(NULL));
+                       fn(numops);
                        _exit(0);
                }
        }
@@ -793,12 +984,16 @@ static void create_procs(int nprocs, int numops)
                usage();
        }
 
-       if (strncmp(argv[1], "\\\\", 2)) {
+        for(p = argv[1]; *p; p++)
+          if(*p == '\\')
+            *p = '/';
+       if (strncmp(argv[1], "//", 2)) {
                usage();
        }
 
        fstrcpy(host, &argv[1][2]);
-       p = strchr(&host[2],'\\');
+       p = strchr(&host[2],'/');
        if (!p) {
                usage();
        }
@@ -808,7 +1003,7 @@ static void create_procs(int nprocs, int numops)
        get_myname(myname,NULL);
 
        if (*username == 0 && getenv("LOGNAME")) {
-         strcpy(username,getenv("LOGNAME"));
+         pstrcpy(username,getenv("LOGNAME"));
        }
 
        argc--;
@@ -836,11 +1031,11 @@ static void create_procs(int nprocs, int numops)
                        fstrcpy(myname, optarg);
                        break;
                case 'U':
-                       strcpy(username,optarg);
+                       pstrcpy(username,optarg);
                        p = strchr(username,'%');
                        if (p) {
                                *p = 0;
-                               strcpy(password, p+1);
+                               pstrcpy(password, p+1);
                                gotpass = 1;
                        }
                        break;
@@ -854,7 +1049,7 @@ static void create_procs(int nprocs, int numops)
        while (!gotpass) {
                p = getpass("Password:");
                if (p) {
-                       strcpy(password, p);
+                       pstrcpy(password, p);
                        gotpass = 1;
                }
        }
@@ -862,10 +1057,7 @@ static void create_procs(int nprocs, int numops)
        printf("host=%s share=%s user=%s myname=%s\n", 
               host, share, username, myname);
 
-       start_timer();
-       create_procs(nprocs, numops);
-       printf("rw_torture: %g secs\n", end_timer());
-
+       run_fdpasstest();
        run_locktest1();
        run_locktest2();
        run_locktest3(numops);
@@ -874,6 +1066,14 @@ static void create_procs(int nprocs, int numops)
        run_attrtest();
        run_trans2test();
 
+       create_procs(nprocs, numops, run_maxfidtest);
+
+       start_timer();
+       create_procs(nprocs, numops, run_torture);
+       printf("rw_torture: %g secs\n", end_timer());
+
+       run_randomipc();        
+
        return(0);
 }