added a test for the NT SMBgetatr bug in smbtorture
[Samba.git] / source / utils / torture.c
blob06f9f5f1fbc7bd5249e15a47cd19b297f4d15e68
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB torture tester
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.
22 #ifdef SYSLOG
23 #undef SYSLOG
24 #endif
26 #include "includes.h"
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);
52 return False;
55 if (!cli_session_request(c, host, 0x20, myname)) {
56 printf("%s rejected the session\n",host);
57 cli_shutdown(c);
58 return False;
61 c->protocol = max_protocol;
63 if (!cli_negprot(c)) {
64 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
65 cli_shutdown(c);
66 return False;
69 if (!cli_session_setup(c, username, password, strlen(password),
70 "", 0, workgroup)) {
71 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
72 cli_shutdown(c);
73 return False;
76 if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
77 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
78 cli_shutdown(c);
79 return False;
82 return True;
87 static void close_connection(struct cli_state *c)
89 if (!cli_tdis(c)) {
90 printf("tdis failed (%s)\n", cli_errstr(c));
93 cli_shutdown(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)) {
100 int eclass, num;
101 cli_error(c, &eclass, &num);
102 if (eclass != ERRDOS || num != ERRlock) {
103 printf("lock failed (%s)\n",
104 cli_errstr(c));
105 return False;
108 return True;
112 static BOOL rw_torture(struct cli_state *c, int numops)
114 char *lockfname = "\\torture.lck";
115 fstring fname;
116 int fnum;
117 int fnum2;
118 int pid2, pid = getpid();
119 int i;
121 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
122 DENY_NONE);
123 if (fnum2 == -1)
124 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
125 if (fnum2 == -1) {
126 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
127 return False;
131 for (i=0;i<numops;i++) {
132 unsigned n = (unsigned)random()%10;
133 if (i % 10 == 0) {
134 printf("%d\r", i); fflush(stdout);
136 sprintf(fname,"\\torture.%u", n);
138 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
139 return False;
142 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
143 if (fnum == -1) {
144 printf("open failed (%s)\n", cli_errstr(c));
145 break;
148 if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
149 printf("write failed (%s)\n", cli_errstr(c));
152 pid2 = 0;
154 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
155 printf("read failed (%s)\n", cli_errstr(c));
158 if (pid2 != pid) {
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));
175 printf("%d\n", i);
177 return True;
180 static void usage(void)
182 printf("Usage: smbtorture \\\\server\\share <options>\n");
184 printf("\t-U user%%pass\n");
185 printf("\t-N numprocs\n");
186 printf("\t-n my_netbios_name\n");
187 printf("\t-W workgroup\n");
188 printf("\t-o num_operations\n");
189 printf("\t-O socket_options\n");
190 printf("\t-m maximum protocol\n");
191 printf("\n");
193 exit(1);
198 static void run_torture(int numops)
200 static struct cli_state cli;
202 if (open_connection(&cli)) {
203 cli_sockopt(&cli, sockops);
205 printf("pid %d OK\n", getpid());
207 rw_torture(&cli, numops);
209 close_connection(&cli);
214 This test checks for two things:
216 1) correct support for retaining locks over a close (ie. the server
217 must not use posix semantics)
218 2) support for lock timeouts
220 static void run_locktest1(void)
222 static struct cli_state cli1, cli2;
223 char *fname = "\\locktest.lck";
224 int fnum1, fnum2, fnum3;
225 time_t t1, t2;
227 if (!open_connection(&cli1) || !open_connection(&cli2)) {
228 return;
230 cli_sockopt(&cli1, sockops);
231 cli_sockopt(&cli2, sockops);
233 printf("starting locktest1\n");
235 cli_unlink(&cli1, fname);
237 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
238 if (fnum1 == -1) {
239 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
240 return;
242 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
243 if (fnum2 == -1) {
244 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
245 return;
247 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
248 if (fnum3 == -1) {
249 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
250 return;
253 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
254 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
255 return;
259 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
260 printf("lock2 succeeded! This is a locking bug\n");
261 return;
262 } else {
263 int eclass, num;
264 cli_error(&cli2, &eclass, &num);
265 if (eclass != ERRDOS || num != ERRlock) {
266 printf("error should have been ERRDOS/ERRlock (%s)\n",
267 cli_errstr(&cli2));
268 return;
273 printf("Testing lock timeouts\n");
274 t1 = time(NULL);
275 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
276 printf("lock3 succeeded! This is a locking bug\n");
277 return;
278 } else {
279 int eclass, num;
280 cli_error(&cli2, &eclass, &num);
281 if (eclass != ERRDOS || num != ERRlock) {
282 printf("error should have been ERRDOS/ERRlock (%s)\n",
283 cli_errstr(&cli2));
284 return;
287 t2 = time(NULL);
289 if (t2 - t1 < 5) {
290 printf("error: This server appears not to support timed lock requests\n");
293 if (!cli_close(&cli1, fnum2)) {
294 printf("close1 failed (%s)\n", cli_errstr(&cli1));
295 return;
298 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
299 printf("lock4 succeeded! This is a locking bug\n");
300 return;
301 } else {
302 int eclass, num;
303 cli_error(&cli2, &eclass, &num);
304 if (eclass != ERRDOS || num != ERRlock) {
305 printf("error should have been ERRDOS/ERRlock (%s)\n",
306 cli_errstr(&cli2));
307 return;
311 if (!cli_close(&cli1, fnum1)) {
312 printf("close2 failed (%s)\n", cli_errstr(&cli1));
313 return;
316 if (!cli_close(&cli2, fnum3)) {
317 printf("close3 failed (%s)\n", cli_errstr(&cli2));
318 return;
321 if (!cli_unlink(&cli1, fname)) {
322 printf("unlink failed (%s)\n", cli_errstr(&cli1));
323 return;
327 close_connection(&cli1);
328 close_connection(&cli2);
330 printf("Passed locktest1\n");
335 This test checks that
337 1) the server supports multiple locking contexts on the one SMB
338 connection, distinguished by PID.
340 2) the server correctly fails overlapping locks made by the same PID (this
341 goes against POSIX behaviour, which is why it is tricky to implement)
343 3) the server denies unlock requests by an incorrect client PID
345 static void run_locktest2(void)
347 static struct cli_state cli;
348 char *fname = "\\locktest.lck";
349 int fnum1, fnum2, fnum3;
351 if (!open_connection(&cli)) {
352 return;
355 cli_sockopt(&cli, sockops);
357 printf("starting locktest2\n");
359 cli_unlink(&cli, fname);
361 cli_setpid(&cli, 1);
363 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
364 if (fnum1 == -1) {
365 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
366 return;
369 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
370 if (fnum2 == -1) {
371 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
372 return;
375 cli_setpid(&cli, 2);
377 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
378 if (fnum3 == -1) {
379 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
380 return;
383 cli_setpid(&cli, 1);
385 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
386 printf("lock1 failed (%s)\n", cli_errstr(&cli));
387 return;
390 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
391 printf("lock2 succeeded! This is a locking bug\n");
392 } else {
393 int eclass, num;
394 cli_error(&cli, &eclass, &num);
395 if (eclass != ERRDOS || num != ERRlock) {
396 printf("error should have been ERRDOS/ERRlock (%s)\n",
397 cli_errstr(&cli));
398 return;
402 cli_setpid(&cli, 2);
404 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
405 printf("unlock1 succeeded! This is a locking bug\n");
408 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
409 printf("lock3 succeeded! This is a locking bug\n");
410 } else {
411 int eclass, num;
412 cli_error(&cli, &eclass, &num);
413 if (eclass != ERRDOS || num != ERRlock) {
414 printf("error should have been ERRDOS/ERRlock (%s)\n",
415 cli_errstr(&cli));
416 return;
420 cli_setpid(&cli, 1);
422 if (!cli_close(&cli, fnum1)) {
423 printf("close1 failed (%s)\n", cli_errstr(&cli));
424 return;
427 if (!cli_close(&cli, fnum2)) {
428 printf("close2 failed (%s)\n", cli_errstr(&cli));
429 return;
432 if (!cli_close(&cli, fnum3)) {
433 printf("close3 failed (%s)\n", cli_errstr(&cli));
434 return;
437 close_connection(&cli);
439 printf("locktest2 finished\n");
444 This test checks that
446 1) the server supports the full offset range in lock requests
448 static void run_locktest3(int numops)
450 static struct cli_state cli1, cli2;
451 char *fname = "\\locktest.lck";
452 int fnum1, fnum2, i;
453 uint32 offset;
455 #define NEXT_OFFSET offset += (~(uint32)0) / numops
457 if (!open_connection(&cli1) || !open_connection(&cli2)) {
458 return;
460 cli_sockopt(&cli1, sockops);
461 cli_sockopt(&cli2, sockops);
463 printf("starting locktest3\n");
465 cli_unlink(&cli1, fname);
467 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
468 if (fnum1 == -1) {
469 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
470 return;
472 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
473 if (fnum2 == -1) {
474 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
475 return;
478 for (offset=i=0;i<numops;i++) {
479 NEXT_OFFSET;
480 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
481 printf("lock1 %d failed (%s)\n",
483 cli_errstr(&cli1));
484 return;
487 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
488 printf("lock2 %d failed (%s)\n",
490 cli_errstr(&cli1));
491 return;
495 for (offset=i=0;i<numops;i++) {
496 NEXT_OFFSET;
498 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
499 printf("error: lock1 %d succeeded!\n", i);
500 return;
503 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
504 printf("error: lock2 %d succeeded!\n", i);
505 return;
508 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
509 printf("error: lock3 %d succeeded!\n", i);
510 return;
513 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
514 printf("error: lock4 %d succeeded!\n", i);
515 return;
519 for (offset=i=0;i<numops;i++) {
520 NEXT_OFFSET;
522 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
523 printf("unlock1 %d failed (%s)\n",
525 cli_errstr(&cli1));
526 return;
529 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
530 printf("unlock2 %d failed (%s)\n",
532 cli_errstr(&cli1));
533 return;
537 if (!cli_close(&cli1, fnum1)) {
538 printf("close1 failed (%s)\n", cli_errstr(&cli1));
541 if (!cli_close(&cli2, fnum2)) {
542 printf("close2 failed (%s)\n", cli_errstr(&cli2));
545 if (!cli_unlink(&cli1, fname)) {
546 printf("unlink failed (%s)\n", cli_errstr(&cli1));
547 return;
550 close_connection(&cli1);
551 close_connection(&cli2);
553 printf("finished locktest3\n");
558 This test checks that
560 1) the server does not allow an unlink on a file that is open
562 static void run_unlinktest(void)
564 static struct cli_state cli;
565 char *fname = "\\unlink.tst";
566 int fnum;
568 if (!open_connection(&cli)) {
569 return;
572 cli_sockopt(&cli, sockops);
574 printf("starting unlink test\n");
576 cli_unlink(&cli, fname);
578 cli_setpid(&cli, 1);
580 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
581 if (fnum == -1) {
582 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
583 return;
586 if (cli_unlink(&cli, fname)) {
587 printf("error: server allowed unlink on an open file\n");
590 close_connection(&cli);
592 printf("unlink test finished\n");
597 static void browse_callback(char *sname, uint32 stype, char *comment)
599 printf("\t%20.20s %08x %s\n", sname, stype, comment);
604 This test checks the browse list code
607 static void run_browsetest(void)
609 static struct cli_state cli;
611 printf("staring browse test\n");
613 if (!open_connection(&cli)) {
614 return;
617 printf("domain list:\n");
618 cli_NetServerEnum(&cli, workgroup,
619 SV_TYPE_DOMAIN_ENUM,
620 browse_callback);
622 printf("machine list:\n");
623 cli_NetServerEnum(&cli, workgroup,
624 SV_TYPE_ALL,
625 browse_callback);
627 close_connection(&cli);
629 printf("browse test finished\n");
634 This checks how the getatr calls works
636 static void run_attrtest(void)
638 static struct cli_state cli;
639 int fnum;
640 struct stat st;
641 char *fname = "\\attrib.tst";
643 printf("staring attrib test\n");
645 if (!open_connection(&cli)) {
646 return;
649 cli_unlink(&cli, fname);
650 fnum = cli_open(&cli, fname,
651 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
652 cli_close(&cli, fnum);
653 if (!cli_stat(&cli, fname, &st)) {
654 printf("getatr failed (%s)\n", cli_errstr(&cli));
657 if (abs(st.st_mtime - time(NULL)) > 2) {
658 printf("ERROR: SMBgetatr bug. time is %s",
659 ctime(&st.st_mtime));
662 close_connection(&cli);
664 printf("attrib test finished\n");
668 static void create_procs(int nprocs, int numops)
670 int i, status;
672 for (i=0;i<nprocs;i++) {
673 if (fork() == 0) {
674 int mypid = getpid();
675 srandom(mypid ^ time(NULL));
676 run_torture(numops);
677 _exit(0);
681 for (i=0;i<nprocs;i++)
682 waitpid(0, &status, 0);
687 /****************************************************************************
688 main program
689 ****************************************************************************/
690 int main(int argc,char *argv[])
692 int nprocs=1, numops=100;
693 int opt;
694 char *p;
695 int gotpass = 0;
696 extern char *optarg;
697 extern int optind;
698 extern FILE *dbf;
700 dbf = stdout;
702 charset_initialise();
704 if (argc < 2) {
705 usage();
708 if (strncmp(argv[1], "\\\\", 2)) {
709 usage();
712 fstrcpy(host, &argv[1][2]);
713 p = strchr(&host[2],'\\');
714 if (!p) {
715 usage();
717 *p = 0;
718 fstrcpy(share, p+1);
720 get_myname(myname,NULL);
722 if (*username == 0 && getenv("LOGNAME")) {
723 strcpy(username,getenv("LOGNAME"));
726 argc--;
727 argv++;
730 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
731 switch (opt) {
732 case 'W':
733 fstrcpy(workgroup,optarg);
734 break;
735 case 'm':
736 max_protocol = interpret_protocol(optarg, max_protocol);
737 break;
738 case 'N':
739 nprocs = atoi(optarg);
740 break;
741 case 'o':
742 numops = atoi(optarg);
743 break;
744 case 'O':
745 sockops = optarg;
746 break;
747 case 'n':
748 fstrcpy(myname, optarg);
749 break;
750 case 'U':
751 strcpy(username,optarg);
752 p = strchr(username,'%');
753 if (p) {
754 *p = 0;
755 strcpy(password, p+1);
756 gotpass = 1;
758 break;
759 default:
760 printf("Unknown option %c (%d)\n", (char)opt, opt);
761 usage();
766 while (!gotpass) {
767 p = getpass("Password:");
768 if (p) {
769 strcpy(password, p);
770 gotpass = 1;
774 printf("host=%s share=%s user=%s myname=%s\n",
775 host, share, username, myname);
777 start_timer();
778 create_procs(nprocs, numops);
779 printf("rw_torture: %g secs\n", end_timer());
781 run_locktest1();
782 run_locktest2();
783 run_locktest3(numops);
784 run_unlinktest();
785 run_browsetest();
786 run_attrtest();
788 return(0);