2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1997-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 static fstring host, workgroup, share, password, username, myname;
27 static int max_protocol = PROTOCOL_NT1;
28 static char *sockops="";
31 static struct timeval tp1,tp2;
33 static void start_timer(void)
35 gettimeofday(&tp1,NULL);
38 static double end_timer(void)
40 gettimeofday(&tp2,NULL);
41 return((tp2.tv_sec - tp1.tv_sec) +
42 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
46 static BOOL open_connection(struct cli_state *c)
48 if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
49 printf("Failed to connect with %s\n", host);
53 if (!cli_session_request(c, host, 0x20, myname)) {
54 printf("%s rejected the session\n",host);
59 c->protocol = max_protocol;
61 if (!cli_negprot(c)) {
62 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
67 if (!cli_session_setup(c, username, password, strlen(password),
69 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
74 if (!cli_send_tconX(c, share,
75 strstr(share,"IPC$")?"IPC":"A:",
76 password, strlen(password)+1)) {
77 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
87 static void close_connection(struct cli_state *c)
90 printf("tdis failed (%s)\n", cli_errstr(c));
97 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
99 while (!cli_lock(c, fnum, offset, len, -1)) {
101 cli_error(c, &eclass, &num);
102 if (eclass != ERRDOS || num != ERRlock) {
103 printf("lock failed (%s)\n",
112 static BOOL rw_torture(struct cli_state *c, int numops)
114 char *lockfname = "\\torture.lck";
118 int pid2, pid = getpid();
122 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
125 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
127 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
132 for (i=0;i<numops;i++) {
133 unsigned n = (unsigned)sys_random()%10;
135 printf("%d\r", i); fflush(stdout);
137 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
139 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
143 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
145 printf("open failed (%s)\n", cli_errstr(c));
149 if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
150 printf("write failed (%s)\n", cli_errstr(c));
154 if (cli_write(c, fnum, (char *)buf,
155 sizeof(pid)+(j*sizeof(buf)),
156 sizeof(buf)) != sizeof(buf)) {
157 printf("write failed (%s)\n", cli_errstr(c));
163 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
164 printf("read failed (%s)\n", cli_errstr(c));
168 printf("data corruption!\n");
171 if (!cli_close(c, fnum)) {
172 printf("close failed (%s)\n", cli_errstr(c));
175 if (!cli_unlink(c, fname)) {
176 printf("unlink failed (%s)\n", cli_errstr(c));
179 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
180 printf("unlock failed (%s)\n", cli_errstr(c));
185 cli_unlink(c, lockfname);
192 static void usage(void)
194 printf("Usage: smbtorture //server/share <options>\n");
196 printf("\t-U user%%pass\n");
197 printf("\t-N numprocs\n");
198 printf("\t-n my_netbios_name\n");
199 printf("\t-W workgroup\n");
200 printf("\t-o num_operations\n");
201 printf("\t-O socket_options\n");
202 printf("\t-m maximum protocol\n");
210 static void run_torture(int numops)
212 static struct cli_state cli;
214 if (open_connection(&cli)) {
215 cli_sockopt(&cli, sockops);
217 printf("pid %d OK\n", getpid());
219 rw_torture(&cli, numops);
221 close_connection(&cli);
226 This test checks for two things:
228 1) correct support for retaining locks over a close (ie. the server
229 must not use posix semantics)
230 2) support for lock timeouts
232 static void run_locktest1(void)
234 static struct cli_state cli1, cli2;
235 char *fname = "\\lockt1.lck";
236 int fnum1, fnum2, fnum3;
239 if (!open_connection(&cli1) || !open_connection(&cli2)) {
242 cli_sockopt(&cli1, sockops);
243 cli_sockopt(&cli2, sockops);
245 printf("starting locktest1\n");
247 cli_unlink(&cli1, fname);
249 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
251 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
254 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
256 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
259 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
261 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
265 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
266 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
271 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
272 printf("lock2 succeeded! This is a locking bug\n");
276 cli_error(&cli2, &eclass, &num);
277 if (eclass != ERRDOS || num != ERRlock) {
278 printf("error should have been ERRDOS/ERRlock (%s)\n",
285 printf("Testing lock timeouts\n");
287 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
288 printf("lock3 succeeded! This is a locking bug\n");
292 cli_error(&cli2, &eclass, &num);
293 if (eclass != ERRDOS || num != ERRlock) {
294 printf("error should have been ERRDOS/ERRlock (%s)\n",
302 printf("error: This server appears not to support timed lock requests\n");
305 if (!cli_close(&cli1, fnum2)) {
306 printf("close1 failed (%s)\n", cli_errstr(&cli1));
310 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
311 printf("lock4 succeeded! This is a locking bug\n");
315 cli_error(&cli2, &eclass, &num);
316 if (eclass != ERRDOS || num != ERRlock) {
317 printf("error should have been ERRDOS/ERRlock (%s)\n",
323 if (!cli_close(&cli1, fnum1)) {
324 printf("close2 failed (%s)\n", cli_errstr(&cli1));
328 if (!cli_close(&cli2, fnum3)) {
329 printf("close3 failed (%s)\n", cli_errstr(&cli2));
333 if (!cli_unlink(&cli1, fname)) {
334 printf("unlink failed (%s)\n", cli_errstr(&cli1));
339 close_connection(&cli1);
340 close_connection(&cli2);
342 printf("Passed locktest1\n");
347 This test checks that
349 1) the server supports multiple locking contexts on the one SMB
350 connection, distinguished by PID.
352 2) the server correctly fails overlapping locks made by the same PID (this
353 goes against POSIX behaviour, which is why it is tricky to implement)
355 3) the server denies unlock requests by an incorrect client PID
357 static void run_locktest2(void)
359 static struct cli_state cli;
360 char *fname = "\\lockt2.lck";
361 int fnum1, fnum2, fnum3;
363 if (!open_connection(&cli)) {
367 cli_sockopt(&cli, sockops);
369 printf("starting locktest2\n");
371 cli_unlink(&cli, fname);
375 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
377 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
381 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
383 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
389 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
391 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
397 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
398 printf("lock1 failed (%s)\n", cli_errstr(&cli));
402 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
403 printf("lock2 succeeded! This is a locking bug\n");
406 cli_error(&cli, &eclass, &num);
407 if (eclass != ERRDOS || num != ERRlock) {
408 printf("error should have been ERRDOS/ERRlock (%s)\n",
416 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
417 printf("unlock1 succeeded! This is a locking bug\n");
420 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
421 printf("lock3 succeeded! This is a locking bug\n");
424 cli_error(&cli, &eclass, &num);
425 if (eclass != ERRDOS || num != ERRlock) {
426 printf("error should have been ERRDOS/ERRlock (%s)\n",
434 if (!cli_close(&cli, fnum1)) {
435 printf("close1 failed (%s)\n", cli_errstr(&cli));
439 if (!cli_close(&cli, fnum2)) {
440 printf("close2 failed (%s)\n", cli_errstr(&cli));
444 if (!cli_close(&cli, fnum3)) {
445 printf("close3 failed (%s)\n", cli_errstr(&cli));
449 close_connection(&cli);
451 printf("locktest2 finished\n");
456 This test checks that
458 1) the server supports the full offset range in lock requests
460 static void run_locktest3(int numops)
462 static struct cli_state cli1, cli2;
463 char *fname = "\\lockt3.lck";
467 #define NEXT_OFFSET offset += (~(uint32)0) / numops
469 if (!open_connection(&cli1) || !open_connection(&cli2)) {
472 cli_sockopt(&cli1, sockops);
473 cli_sockopt(&cli2, sockops);
475 printf("starting locktest3\n");
477 cli_unlink(&cli1, fname);
479 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
481 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
484 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
486 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
490 for (offset=i=0;i<numops;i++) {
492 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
493 printf("lock1 %d failed (%s)\n",
499 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
500 printf("lock2 %d failed (%s)\n",
507 for (offset=i=0;i<numops;i++) {
510 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
511 printf("error: lock1 %d succeeded!\n", i);
515 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
516 printf("error: lock2 %d succeeded!\n", i);
520 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
521 printf("error: lock3 %d succeeded!\n", i);
525 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
526 printf("error: lock4 %d succeeded!\n", i);
531 for (offset=i=0;i<numops;i++) {
534 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
535 printf("unlock1 %d failed (%s)\n",
541 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
542 printf("unlock2 %d failed (%s)\n",
549 if (!cli_close(&cli1, fnum1)) {
550 printf("close1 failed (%s)\n", cli_errstr(&cli1));
553 if (!cli_close(&cli2, fnum2)) {
554 printf("close2 failed (%s)\n", cli_errstr(&cli2));
557 if (!cli_unlink(&cli1, fname)) {
558 printf("unlink failed (%s)\n", cli_errstr(&cli1));
562 close_connection(&cli1);
563 close_connection(&cli2);
565 printf("finished locktest3\n");
570 This test checks that
572 1) the server does not allow an unlink on a file that is open
574 static void run_unlinktest(void)
576 static struct cli_state cli;
577 char *fname = "\\unlink.tst";
580 if (!open_connection(&cli)) {
584 cli_sockopt(&cli, sockops);
586 printf("starting unlink test\n");
588 cli_unlink(&cli, fname);
592 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
594 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
598 if (cli_unlink(&cli, fname)) {
599 printf("error: server allowed unlink on an open file\n");
602 cli_close(&cli, fnum);
603 cli_unlink(&cli, fname);
605 close_connection(&cli);
607 printf("unlink test finished\n");
610 /* generate a random buffer */
611 static void rand_buf(char *buf, int len)
619 /* send random IPC commands */
620 static void run_randomipc(void)
626 int api, param_len, i;
627 static struct cli_state cli;
635 printf("starting random ipc test\n");
637 if (!open_connection(&cli)) {
641 for (i=0;i<1000;i++) {
642 api = sys_random() % 500;
643 param_len = sys_random() % 64;
645 rand_buf(param, param_len);
651 NULL, 0, BUFFER_SIZE,
656 close_connection(&cli);
658 printf("finished random ipc test\n");
663 static void browse_callback(char *sname, uint32 stype, char *comment)
665 printf("\t%20.20s %08x %s\n", sname, stype, comment);
671 This test checks the browse list code
674 static void run_browsetest(void)
676 static struct cli_state cli;
678 printf("starting browse test\n");
680 if (!open_connection(&cli)) {
684 printf("domain list:\n");
685 cli_NetServerEnum(&cli, workgroup,
689 printf("machine list:\n");
690 cli_NetServerEnum(&cli, workgroup,
694 close_connection(&cli);
696 printf("browse test finished\n");
701 This checks how the getatr calls works
703 static void run_attrtest(void)
705 static struct cli_state cli;
708 char *fname = "\\attrib.tst";
710 printf("starting attrib test\n");
712 if (!open_connection(&cli)) {
716 cli_unlink(&cli, fname);
717 fnum = cli_open(&cli, fname,
718 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
719 cli_close(&cli, fnum);
720 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
721 printf("getatr failed (%s)\n", cli_errstr(&cli));
724 if (abs(t - time(NULL)) > 2) {
725 printf("ERROR: SMBgetatr bug. time is %s",
730 t2 = t-60*60*24; /* 1 day ago */
732 if (!cli_setatr(&cli, fname, 0, t2)) {
733 printf("setatr failed (%s)\n", cli_errstr(&cli));
736 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
737 printf("getatr failed (%s)\n", cli_errstr(&cli));
741 printf("ERROR: getatr/setatr bug. times are\n%s",
743 printf("%s", ctime(&t2));
746 cli_unlink(&cli, fname);
748 close_connection(&cli);
750 printf("attrib test finished\n");
755 This checks a couple of trans2 calls
757 static void run_trans2test(void)
759 static struct cli_state cli;
762 time_t c_time, a_time, m_time, w_time, m_time2;
763 char *fname = "\\trans2.tst";
764 char *dname = "\\trans2";
765 char *fname2 = "\\trans2\\trans2.tst";
767 printf("starting trans2 test\n");
769 if (!open_connection(&cli)) {
773 cli_unlink(&cli, fname);
774 fnum = cli_open(&cli, fname,
775 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
776 if (!cli_qfileinfo(&cli, fnum, &c_time, &a_time, &m_time, &size, NULL)) {
777 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
779 cli_close(&cli, fnum);
783 cli_unlink(&cli, fname);
784 fnum = cli_open(&cli, fname,
785 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
786 cli_close(&cli, fnum);
788 if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
789 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
791 if (c_time != m_time) {
792 printf("create time=%s", ctime(&c_time));
793 printf("modify time=%s", ctime(&m_time));
794 printf("This system appears to have sticky create times\n");
796 if (a_time % (60*60) == 0) {
797 printf("access time=%s", ctime(&a_time));
798 printf("This system appears to set a midnight access time\n");
801 if (abs(m_time - time(NULL)) > 60*60*24*7) {
802 printf("ERROR: totally incorrect times - maybe word reversed?\n");
807 cli_unlink(&cli, fname);
808 fnum = cli_open(&cli, fname,
809 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
810 cli_close(&cli, fnum);
811 if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
812 &w_time, &size, NULL)) {
813 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
815 if (w_time < 60*60*24*2) {
816 printf("write time=%s", ctime(&w_time));
817 printf("This system appears to set a initial 0 write time\n");
821 cli_unlink(&cli, fname);
824 /* check if the server updates the directory modification time
825 when creating a new file */
826 if (!cli_mkdir(&cli, dname)) {
827 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
830 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
831 &w_time, &size, NULL)) {
832 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
835 fnum = cli_open(&cli, fname2,
836 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
837 cli_write(&cli, fnum, (char *)&fnum, 0, sizeof(fnum));
838 cli_close(&cli, fnum);
839 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
840 &w_time, &size, NULL)) {
841 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
843 if (m_time2 == m_time)
844 printf("This system does not update directory modification times\n");
846 cli_unlink(&cli, fname2);
847 cli_rmdir(&cli, dname);
850 close_connection(&cli);
852 printf("trans2 test finished\n");
856 static void create_procs(int nprocs, int numops)
860 for (i=0;i<nprocs;i++) {
862 int mypid = getpid();
863 sys_srandom(mypid ^ time(NULL));
869 for (i=0;i<nprocs;i++)
870 waitpid(0, &status, 0);
875 /****************************************************************************
877 ****************************************************************************/
878 int main(int argc,char *argv[])
880 int nprocs=1, numops=100;
890 charset_initialise();
896 for(p = argv[1]; *p; p++)
900 if (strncmp(argv[1], "//", 2)) {
904 fstrcpy(host, &argv[1][2]);
905 p = strchr(&host[2],'/');
912 get_myname(myname,NULL);
914 if (*username == 0 && getenv("LOGNAME")) {
915 pstrcpy(username,getenv("LOGNAME"));
922 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
925 fstrcpy(workgroup,optarg);
928 max_protocol = interpret_protocol(optarg, max_protocol);
931 nprocs = atoi(optarg);
934 numops = atoi(optarg);
940 fstrcpy(myname, optarg);
943 pstrcpy(username,optarg);
944 p = strchr(username,'%');
947 pstrcpy(password, p+1);
952 printf("Unknown option %c (%d)\n", (char)opt, opt);
959 p = getpass("Password:");
961 pstrcpy(password, p);
966 printf("host=%s share=%s user=%s myname=%s\n",
967 host, share, username, myname);
972 create_procs(nprocs, numops);
973 printf("rw_torture: %g secs\n", end_timer());
977 run_locktest3(numops);