2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1997
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.
28 static fstring host, workgroup, share, password, username, myname;
29 static int max_protocol = PROTOCOL_NT1;
30 static char *sockops="";
33 static struct timeval tp1,tp2;
35 static void start_timer()
37 gettimeofday(&tp1,NULL);
40 static double end_timer()
42 gettimeofday(&tp2,NULL);
43 return((tp2.tv_sec - tp1.tv_sec) +
44 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
48 static BOOL open_connection(struct cli_state *c)
50 if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
51 printf("Failed to connect with %s\n", host);
55 if (!cli_session_request(c, host, 0x20, myname)) {
56 printf("%s rejected the session\n",host);
61 c->protocol = max_protocol;
63 if (!cli_negprot(c)) {
64 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
69 if (!cli_session_setup(c, username, password, strlen(password),
71 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
76 if (!cli_send_tconX(c, share, "A:", 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();
121 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
124 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
126 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
131 for (i=0;i<numops;i++) {
132 unsigned n = (unsigned)random()%10;
134 printf("%d\r", i); fflush(stdout);
136 sprintf(fname,"\\torture.%u", n);
138 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
142 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
144 printf("open failed (%s)\n", cli_errstr(c));
148 if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
149 printf("write failed (%s)\n", cli_errstr(c));
154 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
155 printf("read failed (%s)\n", cli_errstr(c));
159 printf("data corruption!\n");
162 if (!cli_close(c, fnum)) {
163 printf("close failed (%s)\n", cli_errstr(c));
166 if (!cli_unlink(c, fname)) {
167 printf("unlink failed (%s)\n", cli_errstr(c));
170 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
171 printf("unlock failed (%s)\n", cli_errstr(c));
176 cli_unlink(c, lockfname);
183 static void usage(void)
185 printf("Usage: smbtorture \\\\server\\share <options>\n");
187 printf("\t-U user%%pass\n");
188 printf("\t-N numprocs\n");
189 printf("\t-n my_netbios_name\n");
190 printf("\t-W workgroup\n");
191 printf("\t-o num_operations\n");
192 printf("\t-O socket_options\n");
193 printf("\t-m maximum protocol\n");
201 static void run_torture(int numops)
203 static struct cli_state cli;
205 if (open_connection(&cli)) {
206 cli_sockopt(&cli, sockops);
208 printf("pid %d OK\n", getpid());
210 rw_torture(&cli, numops);
212 close_connection(&cli);
217 This test checks for two things:
219 1) correct support for retaining locks over a close (ie. the server
220 must not use posix semantics)
221 2) support for lock timeouts
223 static void run_locktest1(void)
225 static struct cli_state cli1, cli2;
226 char *fname = "\\locktest.lck";
227 int fnum1, fnum2, fnum3;
230 if (!open_connection(&cli1) || !open_connection(&cli2)) {
233 cli_sockopt(&cli1, sockops);
234 cli_sockopt(&cli2, sockops);
236 printf("starting locktest1\n");
238 cli_unlink(&cli1, fname);
240 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
242 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
245 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
247 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
250 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
252 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
256 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
257 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
262 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
263 printf("lock2 succeeded! This is a locking bug\n");
267 cli_error(&cli2, &eclass, &num);
268 if (eclass != ERRDOS || num != ERRlock) {
269 printf("error should have been ERRDOS/ERRlock (%s)\n",
276 printf("Testing lock timeouts\n");
278 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
279 printf("lock3 succeeded! This is a locking bug\n");
283 cli_error(&cli2, &eclass, &num);
284 if (eclass != ERRDOS || num != ERRlock) {
285 printf("error should have been ERRDOS/ERRlock (%s)\n",
293 printf("error: This server appears not to support timed lock requests\n");
296 if (!cli_close(&cli1, fnum2)) {
297 printf("close1 failed (%s)\n", cli_errstr(&cli1));
301 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
302 printf("lock4 succeeded! This is a locking bug\n");
306 cli_error(&cli2, &eclass, &num);
307 if (eclass != ERRDOS || num != ERRlock) {
308 printf("error should have been ERRDOS/ERRlock (%s)\n",
314 if (!cli_close(&cli1, fnum1)) {
315 printf("close2 failed (%s)\n", cli_errstr(&cli1));
319 if (!cli_close(&cli2, fnum3)) {
320 printf("close3 failed (%s)\n", cli_errstr(&cli2));
324 if (!cli_unlink(&cli1, fname)) {
325 printf("unlink failed (%s)\n", cli_errstr(&cli1));
330 close_connection(&cli1);
331 close_connection(&cli2);
333 printf("Passed locktest1\n");
338 This test checks that
340 1) the server supports multiple locking contexts on the one SMB
341 connection, distinguished by PID.
343 2) the server correctly fails overlapping locks made by the same PID (this
344 goes against POSIX behaviour, which is why it is tricky to implement)
346 3) the server denies unlock requests by an incorrect client PID
348 static void run_locktest2(void)
350 static struct cli_state cli;
351 char *fname = "\\locktest.lck";
352 int fnum1, fnum2, fnum3;
354 if (!open_connection(&cli)) {
358 cli_sockopt(&cli, sockops);
360 printf("starting locktest2\n");
362 cli_unlink(&cli, fname);
366 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
368 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
372 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
374 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
380 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
382 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
388 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
389 printf("lock1 failed (%s)\n", cli_errstr(&cli));
393 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
394 printf("lock2 succeeded! This is a locking bug\n");
397 cli_error(&cli, &eclass, &num);
398 if (eclass != ERRDOS || num != ERRlock) {
399 printf("error should have been ERRDOS/ERRlock (%s)\n",
407 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
408 printf("unlock1 succeeded! This is a locking bug\n");
411 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
412 printf("lock3 succeeded! This is a locking bug\n");
415 cli_error(&cli, &eclass, &num);
416 if (eclass != ERRDOS || num != ERRlock) {
417 printf("error should have been ERRDOS/ERRlock (%s)\n",
425 if (!cli_close(&cli, fnum1)) {
426 printf("close1 failed (%s)\n", cli_errstr(&cli));
430 if (!cli_close(&cli, fnum2)) {
431 printf("close2 failed (%s)\n", cli_errstr(&cli));
435 if (!cli_close(&cli, fnum3)) {
436 printf("close3 failed (%s)\n", cli_errstr(&cli));
440 close_connection(&cli);
442 printf("locktest2 finished\n");
447 This test checks that
449 1) the server supports the full offset range in lock requests
451 static void run_locktest3(int numops)
453 static struct cli_state cli1, cli2;
454 char *fname = "\\locktest.lck";
458 #define NEXT_OFFSET offset += (~(uint32)0) / numops
460 if (!open_connection(&cli1) || !open_connection(&cli2)) {
463 cli_sockopt(&cli1, sockops);
464 cli_sockopt(&cli2, sockops);
466 printf("starting locktest3\n");
468 cli_unlink(&cli1, fname);
470 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
472 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
475 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
477 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
481 for (offset=i=0;i<numops;i++) {
483 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
484 printf("lock1 %d failed (%s)\n",
490 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
491 printf("lock2 %d failed (%s)\n",
498 for (offset=i=0;i<numops;i++) {
501 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
502 printf("error: lock1 %d succeeded!\n", i);
506 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
507 printf("error: lock2 %d succeeded!\n", i);
511 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
512 printf("error: lock3 %d succeeded!\n", i);
516 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
517 printf("error: lock4 %d succeeded!\n", i);
522 for (offset=i=0;i<numops;i++) {
525 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
526 printf("unlock1 %d failed (%s)\n",
532 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
533 printf("unlock2 %d failed (%s)\n",
540 if (!cli_close(&cli1, fnum1)) {
541 printf("close1 failed (%s)\n", cli_errstr(&cli1));
544 if (!cli_close(&cli2, fnum2)) {
545 printf("close2 failed (%s)\n", cli_errstr(&cli2));
548 if (!cli_unlink(&cli1, fname)) {
549 printf("unlink failed (%s)\n", cli_errstr(&cli1));
553 close_connection(&cli1);
554 close_connection(&cli2);
556 printf("finished locktest3\n");
561 This test checks that
563 1) the server does not allow an unlink on a file that is open
565 static void run_unlinktest(void)
567 static struct cli_state cli;
568 char *fname = "\\unlink.tst";
571 if (!open_connection(&cli)) {
575 cli_sockopt(&cli, sockops);
577 printf("starting unlink test\n");
579 cli_unlink(&cli, fname);
583 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
585 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
589 if (cli_unlink(&cli, fname)) {
590 printf("error: server allowed unlink on an open file\n");
593 cli_close(&cli, fnum);
594 cli_unlink(&cli, fname);
596 close_connection(&cli);
598 printf("unlink test finished\n");
603 static void browse_callback(char *sname, uint32 stype, char *comment)
605 printf("\t%20.20s %08x %s\n", sname, stype, comment);
610 This test checks the browse list code
613 static void run_browsetest(void)
615 static struct cli_state cli;
617 printf("starting browse test\n");
619 if (!open_connection(&cli)) {
623 printf("domain list:\n");
624 cli_NetServerEnum(&cli, workgroup,
628 printf("machine list:\n");
629 cli_NetServerEnum(&cli, workgroup,
633 close_connection(&cli);
635 printf("browse test finished\n");
640 This checks how the getatr calls works
642 static void run_attrtest(void)
644 static struct cli_state cli;
647 char *fname = "\\attrib.tst";
649 printf("starting attrib test\n");
651 if (!open_connection(&cli)) {
655 cli_unlink(&cli, fname);
656 fnum = cli_open(&cli, fname,
657 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
658 cli_close(&cli, fnum);
659 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
660 printf("getatr failed (%s)\n", cli_errstr(&cli));
663 if (abs(t - time(NULL)) > 2) {
664 printf("ERROR: SMBgetatr bug. time is %s",
669 t2 = t-60*60*24; /* 1 day ago */
671 if (!cli_setatr(&cli, fname, 0, t2)) {
672 printf("setatr failed (%s)\n", cli_errstr(&cli));
675 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
676 printf("getatr failed (%s)\n", cli_errstr(&cli));
680 printf("ERROR: getatr/setatr bug. times are\n%s",
682 printf("%s", ctime(&t2));
685 cli_unlink(&cli, fname);
687 close_connection(&cli);
689 printf("attrib test finished\n");
694 This checks a couple of trans2 calls
696 static void run_trans2test(void)
698 static struct cli_state cli;
701 time_t c_time, a_time, m_time, w_time, m_time2;
702 char *fname = "\\trans2.tst";
703 char *dname = "\\trans2";
704 char *fname2 = "\\trans2\\trans2.tst";
706 printf("starting trans2 test\n");
708 if (!open_connection(&cli)) {
712 cli_unlink(&cli, fname);
713 fnum = cli_open(&cli, fname,
714 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
715 if (!cli_qfileinfo(&cli, fnum, &c_time, &a_time, &m_time, &size)) {
716 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
718 cli_close(&cli, fnum);
722 cli_unlink(&cli, fname);
723 fnum = cli_open(&cli, fname,
724 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
725 cli_close(&cli, fnum);
727 if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size)) {
728 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
730 if (c_time != m_time) {
731 printf("create time=%s", ctime(&c_time));
732 printf("modify time=%s", ctime(&m_time));
733 printf("This system appears to have sticky create times\n");
735 if (a_time % (60*60) == 0) {
736 printf("access time=%s", ctime(&a_time));
737 printf("This system appears to set a midnight access time\n");
740 if (abs(m_time - time(NULL)) > 60*60*24*7) {
741 printf("ERROR: totally incorrect times - maybe word reversed?\n");
746 cli_unlink(&cli, fname);
747 fnum = cli_open(&cli, fname,
748 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
749 cli_close(&cli, fnum);
750 if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
752 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
754 if (w_time < 60*60*24*2) {
755 printf("write time=%s", ctime(&w_time));
756 printf("This system appears to set a initial 0 write time\n");
760 cli_unlink(&cli, fname);
763 /* check if the server updates the directory modification time
764 when creating a new file */
765 if (!cli_mkdir(&cli, dname)) {
766 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
769 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
771 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
774 fnum = cli_open(&cli, fname2,
775 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
776 cli_write(&cli, fnum, (char *)&fnum, 0, sizeof(fnum));
777 cli_close(&cli, fnum);
778 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
780 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
782 if (m_time2 == m_time)
783 printf("This system does not update directory modification times\n");
785 cli_unlink(&cli, fname2);
786 cli_rmdir(&cli, dname);
789 close_connection(&cli);
791 printf("trans2 test finished\n");
795 static void create_procs(int nprocs, int numops)
799 for (i=0;i<nprocs;i++) {
801 int mypid = getpid();
802 srandom(mypid ^ time(NULL));
808 for (i=0;i<nprocs;i++)
809 waitpid(0, &status, 0);
814 /****************************************************************************
816 ****************************************************************************/
817 int main(int argc,char *argv[])
819 int nprocs=1, numops=100;
829 charset_initialise();
835 if (strncmp(argv[1], "\\\\", 2)) {
839 fstrcpy(host, &argv[1][2]);
840 p = strchr(&host[2],'\\');
847 get_myname(myname,NULL);
849 if (*username == 0 && getenv("LOGNAME")) {
850 strcpy(username,getenv("LOGNAME"));
857 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
860 fstrcpy(workgroup,optarg);
863 max_protocol = interpret_protocol(optarg, max_protocol);
866 nprocs = atoi(optarg);
869 numops = atoi(optarg);
875 fstrcpy(myname, optarg);
878 strcpy(username,optarg);
879 p = strchr(username,'%');
882 strcpy(password, p+1);
887 printf("Unknown option %c (%d)\n", (char)opt, opt);
894 p = getpass("Password:");
901 printf("host=%s share=%s user=%s myname=%s\n",
902 host, share, username, myname);
905 create_procs(nprocs, numops);
906 printf("rw_torture: %g secs\n", end_timer());
910 run_locktest3(numops);