added code to test the cli_NetServerEnum() function in clientgen.c
[nivanova/samba-autobuild/.git] / source3 / utils / torture.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB torture tester
5    Copyright (C) Andrew Tridgell 1997
6    
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.
11    
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.
16    
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.
20 */
21
22 #ifdef SYSLOG
23 #undef SYSLOG
24 #endif
25
26 #include "includes.h"
27
28 static fstring host, workgroup, share, password, username, myname;
29 static char *sockops="";
30
31
32 static struct timeval tp1,tp2;
33
34 static void start_timer()
35 {
36         gettimeofday(&tp1,NULL);
37 }
38
39 static double end_timer()
40 {
41         gettimeofday(&tp2,NULL);
42         return((tp2.tv_sec - tp1.tv_sec) + 
43                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
44 }
45
46
47 static BOOL open_connection(struct cli_state *c)
48 {
49         if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
50                 printf("Failed to connect with %s\n", host);
51                 return False;
52         }
53
54         if (!cli_session_request(c, host, 0x20, myname)) {
55                 printf("%s rejected the session\n",host);
56                 cli_shutdown(c);
57                 return False;
58         }
59
60         if (!cli_negprot(c)) {
61                 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
62                 cli_shutdown(c);
63                 return False;
64         }
65
66         if (!cli_session_setup(c, username, password, strlen(password),
67                                "", 0, workgroup)) {
68                 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
69                 cli_shutdown(c);
70                 return False;
71         }
72
73         if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
74                 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
75                 cli_shutdown(c);
76                 return False;
77         }
78
79         return True;
80 }
81
82
83
84 static void close_connection(struct cli_state *c)
85 {
86         if (!cli_tdis(c)) {
87                 printf("tdis failed (%s)\n", cli_errstr(c));
88         }
89
90         cli_shutdown(c);
91 }
92
93
94 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
95 {
96         while (!cli_lock(c, fnum, offset, len, -1)) {
97                 int eclass, num;
98                 cli_error(c, &eclass, &num);
99                 if (eclass != ERRDOS || num != ERRlock) {
100                         printf("lock failed (%s)\n", 
101                                cli_errstr(c));
102                         return False;
103                 }
104         }
105         return True;
106 }
107
108
109 static BOOL rw_torture(struct cli_state *c, int numops)
110 {
111         char *lockfname = "\\torture.lck";
112         fstring fname;
113         int fnum;
114         int fnum2;
115         int pid2, pid = getpid();
116         int i;
117
118         fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
119                          DENY_NONE);
120         if (fnum2 == -1)
121                 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
122         if (fnum2 == -1) {
123                 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
124                 return False;
125         }
126
127
128         for (i=0;i<numops;i++) {
129                 unsigned n = (unsigned)random()%10;
130                 if (i % 10 == 0) {
131                         printf("%d\r", i); fflush(stdout);
132                 }
133                 sprintf(fname,"\\torture.%u", n);
134
135                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
136                         return False;
137                 }
138
139                 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
140                 if (fnum == -1) {
141                         printf("open failed (%s)\n", cli_errstr(c));
142                         break;
143                 }
144
145                 if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
146                         printf("write failed (%s)\n", cli_errstr(c));
147                 }
148
149                 pid2 = 0;
150
151                 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
152                         printf("read failed (%s)\n", cli_errstr(c));
153                 }
154
155                 if (pid2 != pid) {
156                         printf("data corruption!\n");
157                 }
158
159                 if (!cli_close(c, fnum)) {
160                         printf("close failed (%s)\n", cli_errstr(c));
161                 }
162
163                 if (!cli_unlink(c, fname)) {
164                         printf("unlink failed (%s)\n", cli_errstr(c));
165                 }
166
167                 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
168                         printf("unlock failed (%s)\n", cli_errstr(c));
169                 }
170         }
171
172         printf("%d\n", i);
173
174         return True;
175 }
176
177 static void usage(void)
178 {
179         printf("Usage: smbtorture \\\\server\\share <options>\n");
180
181         printf("\t-U user%%pass\n");
182         printf("\t-N numprocs\n");
183         printf("\t-n my_netbios_name\n");
184         printf("\t-W workgroup\n");
185         printf("\t-o num_operations\n");
186         printf("\t-O socket_options\n");
187         printf("\n");
188
189         exit(1);
190 }
191
192
193
194 static void run_torture(int numops)
195 {
196         static struct cli_state cli;
197
198         if (open_connection(&cli)) {
199                 cli_sockopt(&cli, sockops);
200
201                 printf("pid %d OK\n", getpid());
202
203                 rw_torture(&cli, numops);
204
205                 close_connection(&cli);
206         }
207 }
208
209 /*
210   This test checks for two things:
211
212   1) correct support for retaining locks over a close (ie. the server
213      must not use posix semantics)
214   2) support for lock timeouts
215  */
216 static void run_locktest1(void)
217 {
218         static struct cli_state cli1, cli2;
219         char *fname = "\\locktest.lck";
220         int fnum1, fnum2, fnum3;
221         time_t t1, t2;
222
223         if (!open_connection(&cli1) || !open_connection(&cli2)) {
224                 return;
225         }
226         cli_sockopt(&cli1, sockops);
227         cli_sockopt(&cli2, sockops);
228
229         printf("starting locktest1\n");
230
231         cli_unlink(&cli1, fname);
232
233         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
234         if (fnum1 == -1) {
235                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
236                 return;
237         }
238         fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
239         if (fnum2 == -1) {
240                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
241                 return;
242         }
243         fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
244         if (fnum3 == -1) {
245                 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
246                 return;
247         }
248
249         if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
250                 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
251                 return;
252         }
253
254
255         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
256                 printf("lock2 succeeded! This is a locking bug\n");
257                 return;
258         } else {
259                 int eclass, num;
260                 cli_error(&cli2, &eclass, &num);
261                 if (eclass != ERRDOS || num != ERRlock) {
262                         printf("error should have been ERRDOS/ERRlock (%s)\n", 
263                                cli_errstr(&cli2));
264                         return;
265                 }
266         }
267
268
269         printf("Testing lock timeouts\n");
270         t1 = time(NULL);
271         if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
272                 printf("lock3 succeeded! This is a locking bug\n");
273                 return;
274         } else {
275                 int eclass, num;
276                 cli_error(&cli2, &eclass, &num);
277                 if (eclass != ERRDOS || num != ERRlock) {
278                         printf("error should have been ERRDOS/ERRlock (%s)\n", 
279                                cli_errstr(&cli2));
280                         return;
281                 }
282         }
283         t2 = time(NULL);
284
285         if (t2 - t1 < 5) {
286                 printf("error: This server appears not to support timed lock requests\n");
287         }
288
289         if (!cli_close(&cli1, fnum2)) {
290                 printf("close1 failed (%s)\n", cli_errstr(&cli1));
291                 return;
292         }
293
294         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
295                 printf("lock4 succeeded! This is a locking bug\n");
296                 return;
297         } else {
298                 int eclass, num;
299                 cli_error(&cli2, &eclass, &num);
300                 if (eclass != ERRDOS || num != ERRlock) {
301                         printf("error should have been ERRDOS/ERRlock (%s)\n", 
302                                cli_errstr(&cli2));
303                         return;
304                 }
305         }
306
307         if (!cli_close(&cli1, fnum1)) {
308                 printf("close2 failed (%s)\n", cli_errstr(&cli1));
309                 return;
310         }
311
312         if (!cli_close(&cli2, fnum3)) {
313                 printf("close3 failed (%s)\n", cli_errstr(&cli2));
314                 return;
315         }
316
317         if (!cli_unlink(&cli1, fname)) {
318                 printf("unlink failed (%s)\n", cli_errstr(&cli1));
319                 return;
320         }
321
322
323         close_connection(&cli1);
324         close_connection(&cli2);
325
326         printf("Passed locktest1\n");
327 }
328
329
330 /*
331   This test checks that 
332
333   1) the server supports multiple locking contexts on the one SMB
334   connection, distinguished by PID.  
335
336   2) the server correctly fails overlapping locks made by the same PID (this
337      goes against POSIX behaviour, which is why it is tricky to implement)
338
339   3) the server denies unlock requests by an incorrect client PID
340 */
341 static void run_locktest2(void)
342 {
343         static struct cli_state cli;
344         char *fname = "\\locktest.lck";
345         int fnum1, fnum2, fnum3;
346
347         if (!open_connection(&cli)) {
348                 return;
349         }
350
351         cli_sockopt(&cli, sockops);
352
353         printf("starting locktest2\n");
354
355         cli_unlink(&cli, fname);
356
357         cli_setpid(&cli, 1);
358
359         fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
360         if (fnum1 == -1) {
361                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
362                 return;
363         }
364
365         fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
366         if (fnum2 == -1) {
367                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
368                 return;
369         }
370
371         cli_setpid(&cli, 2);
372
373         fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
374         if (fnum3 == -1) {
375                 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
376                 return;
377         }
378
379         cli_setpid(&cli, 1);
380
381         if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
382                 printf("lock1 failed (%s)\n", cli_errstr(&cli));
383                 return;
384         }
385
386         if (cli_lock(&cli, fnum2, 0, 4, 0)) {
387                 printf("lock2 succeeded! This is a locking bug\n");
388         } else {
389                 int eclass, num;
390                 cli_error(&cli, &eclass, &num);
391                 if (eclass != ERRDOS || num != ERRlock) {
392                         printf("error should have been ERRDOS/ERRlock (%s)\n", 
393                                cli_errstr(&cli));
394                         return;
395                 }
396         }
397
398         cli_setpid(&cli, 2);
399
400         if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
401                 printf("unlock1 succeeded! This is a locking bug\n");
402         }
403
404         if (cli_lock(&cli, fnum3, 0, 4, 0)) {
405                 printf("lock3 succeeded! This is a locking bug\n");
406         } else {
407                 int eclass, num;
408                 cli_error(&cli, &eclass, &num);
409                 if (eclass != ERRDOS || num != ERRlock) {
410                         printf("error should have been ERRDOS/ERRlock (%s)\n", 
411                                cli_errstr(&cli));
412                         return;
413                 }
414         }
415
416         cli_setpid(&cli, 1);
417
418         if (!cli_close(&cli, fnum1)) {
419                 printf("close1 failed (%s)\n", cli_errstr(&cli));
420                 return;
421         }
422
423         if (!cli_close(&cli, fnum2)) {
424                 printf("close2 failed (%s)\n", cli_errstr(&cli));
425                 return;
426         }
427
428         if (!cli_close(&cli, fnum3)) {
429                 printf("close3 failed (%s)\n", cli_errstr(&cli));
430                 return;
431         }
432
433         close_connection(&cli);
434
435         printf("locktest2 finished\n");
436 }
437
438
439 /*
440   This test checks that 
441
442   1) the server supports the full offset range in lock requests
443 */
444 static void run_locktest3(int numops)
445 {
446         static struct cli_state cli1, cli2;
447         char *fname = "\\locktest.lck";
448         int fnum1, fnum2, i;
449         uint32 offset;
450
451 #define NEXT_OFFSET offset += (~(uint32)0) / numops
452
453         if (!open_connection(&cli1) || !open_connection(&cli2)) {
454                 return;
455         }
456         cli_sockopt(&cli1, sockops);
457         cli_sockopt(&cli2, sockops);
458
459         printf("starting locktest3\n");
460
461         cli_unlink(&cli1, fname);
462
463         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
464         if (fnum1 == -1) {
465                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
466                 return;
467         }
468         fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
469         if (fnum2 == -1) {
470                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
471                 return;
472         }
473
474         for (offset=i=0;i<numops;i++) {
475                 NEXT_OFFSET;
476                 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
477                         printf("lock1 %d failed (%s)\n", 
478                                i,
479                                cli_errstr(&cli1));
480                         return;
481                 }
482
483                 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
484                         printf("lock2 %d failed (%s)\n", 
485                                i,
486                                cli_errstr(&cli1));
487                         return;
488                 }
489         }
490
491         for (offset=i=0;i<numops;i++) {
492                 NEXT_OFFSET;
493
494                 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
495                         printf("error: lock1 %d succeeded!\n", i);
496                         return;
497                 }
498
499                 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
500                         printf("error: lock2 %d succeeded!\n", i);
501                         return;
502                 }
503
504                 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
505                         printf("error: lock3 %d succeeded!\n", i);
506                         return;
507                 }
508
509                 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
510                         printf("error: lock4 %d succeeded!\n", i);
511                         return;
512                 }
513         }
514
515         for (offset=i=0;i<numops;i++) {
516                 NEXT_OFFSET;
517
518                 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
519                         printf("unlock1 %d failed (%s)\n", 
520                                i,
521                                cli_errstr(&cli1));
522                         return;
523                 }
524
525                 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
526                         printf("unlock2 %d failed (%s)\n", 
527                                i,
528                                cli_errstr(&cli1));
529                         return;
530                 }
531         }
532
533         if (!cli_close(&cli1, fnum1)) {
534                 printf("close1 failed (%s)\n", cli_errstr(&cli1));
535         }
536
537         if (!cli_close(&cli2, fnum2)) {
538                 printf("close2 failed (%s)\n", cli_errstr(&cli2));
539         }
540
541         if (!cli_unlink(&cli1, fname)) {
542                 printf("unlink failed (%s)\n", cli_errstr(&cli1));
543                 return;
544         }
545
546         close_connection(&cli1);
547         close_connection(&cli2);
548
549         printf("finished locktest3\n");
550 }
551
552
553 /*
554   This test checks that 
555
556   1) the server does not allow an unlink on a file that is open
557 */
558 static void run_unlinktest(void)
559 {
560         static struct cli_state cli;
561         char *fname = "\\unlink.tst";
562         int fnum;
563
564         if (!open_connection(&cli)) {
565                 return;
566         }
567
568         cli_sockopt(&cli, sockops);
569
570         printf("starting unlink test\n");
571
572         cli_unlink(&cli, fname);
573
574         cli_setpid(&cli, 1);
575
576         fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
577         if (fnum == -1) {
578                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
579                 return;
580         }
581
582         if (cli_unlink(&cli, fname)) {
583                 printf("error: server allowed unlink on an open file\n");
584         }
585
586         close_connection(&cli);
587
588         printf("unlink test finished\n");
589 }
590
591
592
593 static void browse_callback(char *sname, uint32 stype, char *comment)
594 {
595         printf("\t%20.20s %08x %s\n", sname, stype, comment);
596 }
597
598
599 /*
600   This test checks the browse list code
601
602 */
603 static void run_browsetest(void)
604 {
605         static struct cli_state cli;
606
607         printf("staring browse test\n");
608
609         if (!open_connection(&cli)) {
610                 return;
611         }
612
613         printf("domain list:\n");
614         cli_NetServerEnum(&cli, workgroup, 
615                           SV_TYPE_DOMAIN_ENUM,
616                           browse_callback);
617
618         printf("machine list:\n");
619         cli_NetServerEnum(&cli, workgroup, 
620                           SV_TYPE_ALL,
621                           browse_callback);
622
623         close_connection(&cli);
624
625         printf("browse test finished\n");
626 }
627
628
629
630 static void create_procs(int nprocs, int numops)
631 {
632         int i, status;
633
634         for (i=0;i<nprocs;i++) {
635                 if (fork() == 0) {
636                         int mypid = getpid();
637                         srandom(mypid ^ time(NULL));
638                         run_torture(numops);
639                         _exit(0);
640                 }
641         }
642
643         for (i=0;i<nprocs;i++)
644                 waitpid(0, &status, 0);
645 }
646
647
648
649 /****************************************************************************
650   main program
651 ****************************************************************************/
652  int main(int argc,char *argv[])
653 {
654         int nprocs=1, numops=100;
655         int opt;
656         char *p;
657         int gotpass = 0;
658         extern char *optarg;
659         extern int optind;
660         extern FILE *dbf;
661
662         dbf = stdout;
663
664         charset_initialise();
665
666         if (argc < 2) {
667                 usage();
668         }
669
670         if (strncmp(argv[1], "\\\\", 2)) {
671                 usage();
672         }
673
674         fstrcpy(host, &argv[1][2]);
675         p = strchr(&host[2],'\\');
676         if (!p) {
677                 usage();
678         }
679         *p = 0;
680         fstrcpy(share, p+1);
681
682         get_myname(myname,NULL);
683
684         if (*username == 0 && getenv("LOGNAME")) {
685           strcpy(username,getenv("LOGNAME"));
686         }
687
688         argc--;
689         argv++;
690
691
692         while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:")) != EOF) {
693                 switch (opt) {
694                 case 'W':
695                         fstrcpy(workgroup,optarg);
696                         break;
697                 case 'N':
698                         nprocs = atoi(optarg);
699                         break;
700                 case 'o':
701                         numops = atoi(optarg);
702                         break;
703                 case 'O':
704                         sockops = optarg;
705                         break;
706                 case 'n':
707                         fstrcpy(myname, optarg);
708                         break;
709                 case 'U':
710                         strcpy(username,optarg);
711                         p = strchr(username,'%');
712                         if (p) {
713                                 *p = 0;
714                                 strcpy(password, p+1);
715                                 gotpass = 1;
716                         }
717                         break;
718                 default:
719                         printf("Unknown option %c (%d)\n", (char)opt, opt);
720                         usage();
721                 }
722         }
723
724
725         while (!gotpass) {
726                 p = getpass("Password:");
727                 if (p) {
728                         strcpy(password, p);
729                         gotpass = 1;
730                 }
731         }
732
733         printf("host=%s share=%s user=%s myname=%s\n", 
734                host, share, username, myname);
735
736         start_timer();
737         create_procs(nprocs, numops);
738         printf("rw_torture: %g secs\n", end_timer());
739
740         run_locktest1();
741         run_locktest2();
742         run_locktest3(numops);
743         run_unlinktest();
744         run_browsetest();
745
746         return(0);
747 }
748
749