refinement of random ipc$ SMBtrans torture test. send requests, and
[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-1998
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 #define NO_SYSLOG
23
24 #include "includes.h"
25
26 extern int DEBUGLEVEL;
27 extern pstring debugf;
28
29 static fstring host, workgroup, share, password, username, myname;
30 static int max_protocol = PROTOCOL_NT1;
31 static char *sockops="";
32
33
34 static struct timeval tp1,tp2;
35
36 static void start_timer(void)
37 {
38         gettimeofday(&tp1,NULL);
39 }
40
41 static double end_timer(void)
42 {
43         gettimeofday(&tp2,NULL);
44         return((tp2.tv_sec - tp1.tv_sec) + 
45                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
46 }
47
48 #define FAILED_NO_ERROR            0
49 #define FAILED_TCP_CONNECT         1
50 #define FAILED_SESSION_REQ         2
51 #define FAILED_SMB_SESS_SETUP      3
52 #define FAILED_SMB_TCON            4
53 #define FAILED_SMB_NEGPROT         5
54 #define FAILED_CLI_STATE_INIT      6
55 #define NUM_ERR_STATES             7
56
57 static char *smb_messages[] =
58 {
59         "No errors in connection",
60         "TCP connection         ",
61         "NetBIOS Session Request",
62         "SMB Session Setup      ",
63         "SMB Tcon               ",
64         "SMB Negprot            ",
65         "Client initialisation  "
66 };
67
68 static int open_connection(struct cli_state *c)
69 {
70         struct nmb_name called, calling;
71
72         ZERO_STRUCTP(c);
73
74         make_nmb_name(&calling, myname, 0x0, "");
75         make_nmb_name(&called , host, 0x20, "");
76
77         if (!cli_initialise(c))
78         {
79                 DEBUG(0,("Failed to connect with %s\n", host));
80                 return FAILED_CLI_STATE_INIT;
81         }
82
83         if (!cli_connect(c, host, NULL)) {
84                 DEBUG(0,("Failed to connect with %s\n", host));
85                 return FAILED_TCP_CONNECT;
86         }
87
88         if (!cli_session_request(c, &calling, &called)) {
89                 cli_shutdown(c);
90                 DEBUG(0,("%s rejected the session\n",host));
91                 return FAILED_SESSION_REQ;
92         }
93
94         if (!cli_negprot(c)) {
95                 DEBUG(0,("%s rejected the negprot (%s)\n",host, cli_errstr(c)));
96                 cli_shutdown(c);
97                 return FAILED_SMB_NEGPROT;
98         }
99
100         if (!cli_session_setup(c, username, 
101                                password, strlen(password),
102                                password, strlen(password),
103                                workgroup)) {
104                 DEBUG(0,("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c)));
105                 cli_shutdown(c);
106                 return FAILED_SMB_SESS_SETUP;
107         }
108
109         if (!cli_send_tconX(c, share, "?????",
110                             password, strlen(password)+1)) {
111                 DEBUG(0,("%s refused tree connect (%s)\n", host, cli_errstr(c)));
112                 cli_shutdown(c);
113                 return FAILED_SMB_TCON;
114         }
115
116         return FAILED_NO_ERROR;
117 }
118
119
120 static void close_connection(struct cli_state *c)
121 {
122         if (!cli_tdis(c)) {
123                 DEBUG(0,("tdis failed (%s)\n", cli_errstr(c)));
124         }
125
126         cli_shutdown(c);
127 }
128
129
130 /* check if the server produced the expected error code */
131 static BOOL check_error(struct cli_state *c, 
132                         uint8 eclass, uint32 ecode, uint32 nterr)
133 {
134         uint8 class;
135         uint32 num;
136         int eno;
137         eno = cli_error(c, &class, &num);
138         if ((eclass != class || ecode != num) &&
139             num != (nterr&0xFFFFFF)) {
140                 DEBUG(0,("unexpected error code class=%d code=%d\n", 
141                          (int)class, (int)num));
142                 DEBUG(0,(" expected %d/%d %d\n", 
143                        (int)eclass, (int)ecode, (int)nterr));
144                 return False;
145         }
146         return True;
147 }
148
149
150 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
151 {
152         while (!cli_lock(c, fnum, offset, len, -1)) {
153                 if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
154         }
155         return True;
156 }
157
158
159 static BOOL rw_torture(struct cli_state *c, int numops)
160 {
161         char *lockfname = "\\torture.lck";
162         fstring fname;
163         int fnum;
164         int fnum2;
165         int pid2, pid = getpid();
166         int i, j;
167         char buf[1024];
168
169         fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
170                          DENY_NONE);
171         if (fnum2 == -1)
172                 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
173         if (fnum2 == -1) {
174                 DEBUG(0,("open of %s failed (%s)\n", lockfname, cli_errstr(c)));
175                 return False;
176         }
177
178
179         for (i=0;i<numops;i++) {
180                 unsigned n = (unsigned)sys_random()%10;
181                 if (i % 10 == 0) {
182                         DEBUG(0,("%d\r", i));
183                 }
184                 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
185
186                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
187                         return False;
188                 }
189
190                 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
191                 if (fnum == -1) {
192                         DEBUG(0,("open failed (%s)\n", cli_errstr(c)));
193                         break;
194                 }
195
196                 if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
197                         DEBUG(0,("write failed (%s)\n", cli_errstr(c)));
198                 }
199
200                 for (j=0;j<50;j++) {
201                         if (cli_write(c, fnum, 0, (char *)buf, 
202                                       sizeof(pid)+(j*sizeof(buf)), 
203                                       sizeof(buf)) != sizeof(buf)) {
204                                 DEBUG(0,("write failed (%s)\n", cli_errstr(c)));
205                         }
206                 }
207
208                 pid2 = 0;
209
210                 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
211                         DEBUG(0,("read failed (%s)\n", cli_errstr(c)));
212                 }
213
214                 if (pid2 != pid) {
215                         DEBUG(0,("data corruption!\n"));
216                 }
217
218                 if (!cli_close(c, fnum)) {
219                         DEBUG(0,("close failed (%s)\n", cli_errstr(c)));
220                 }
221
222                 if (!cli_unlink(c, fname)) {
223                         DEBUG(0,("unlink failed (%s)\n", cli_errstr(c)));
224                 }
225
226                 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
227                         DEBUG(0,("unlock failed (%s)\n", cli_errstr(c)));
228                 }
229         }
230
231         cli_close(c, fnum2);
232         cli_unlink(c, lockfname);
233
234         DEBUG(0,("%d\n", i));
235
236         return True;
237 }
238
239 static void usage(void)
240 {
241         printf("Usage: smbtorture //server/share <options>\n");
242
243         printf("\t-U user%%pass\n");
244         printf("\t-N numprocs\n");
245         printf("\t-n my_netbios_name\n");
246         printf("\t-W workgroup\n");
247         printf("\t-o num_operations\n");
248         printf("\t-O socket_options\n");
249         printf("\t-m maximum protocol\n");
250         printf("\n");
251
252         exit(1);
253 }
254
255
256
257 static void run_torture(int numops)
258 {
259         static struct cli_state cli;
260
261         if (open_connection(&cli) == 0)
262         {
263                 cli_sockopt(&cli, sockops);
264
265                 DEBUG(0,("pid %d OK\n", getpid()));
266
267                 rw_torture(&cli, numops);
268
269                 close_connection(&cli);
270         }
271         else
272         {
273                 DEBUG(0,("pid %d failed\n", getpid()));
274         }
275
276 }
277
278 /*
279   This test checks for two things:
280
281   1) correct support for retaining locks over a close (ie. the server
282      must not use posix semantics)
283   2) support for lock timeouts
284  */
285 static void run_locktest1(void)
286 {
287         static struct cli_state cli1, cli2;
288         char *fname = "\\lockt1.lck";
289         int fnum1, fnum2, fnum3;
290         time_t t1, t2;
291
292         if (open_connection(&cli1) != 0 || open_connection(&cli2) != 0) {
293                 return;
294         }
295         cli_sockopt(&cli1, sockops);
296         cli_sockopt(&cli2, sockops);
297
298         DEBUG(0,("starting locktest1\n"));
299
300         cli_unlink(&cli1, fname);
301
302         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
303         if (fnum1 == -1) {
304                 DEBUG(0,("open of %s failed (%s)\n", fname, cli_errstr(&cli1)));
305                 return;
306         }
307         fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
308         if (fnum2 == -1) {
309                 DEBUG(0,("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1)));
310                 return;
311         }
312         fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
313         if (fnum3 == -1) {
314                 DEBUG(0,("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2)));
315                 return;
316         }
317
318         if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
319                 DEBUG(0,("lock1 failed (%s)\n", cli_errstr(&cli1)));
320                 return;
321         }
322
323
324         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
325                 DEBUG(0,("lock2 succeeded! This is a locking bug\n"));
326                 return;
327         } else {
328                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
329         }
330
331
332         DEBUG(0,("Testing lock timeouts\n"));
333         t1 = time(NULL);
334         if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
335                 DEBUG(0,("lock3 succeeded! This is a locking bug\n"));
336                 return;
337         } else {
338                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
339         }
340         t2 = time(NULL);
341
342         if (t2 - t1 < 5) {
343                 DEBUG(0,("error: This server appears not to support timed lock requests\n"));
344         }
345
346         if (!cli_close(&cli1, fnum2)) {
347                 DEBUG(0,("close1 failed (%s)\n", cli_errstr(&cli1)));
348                 return;
349         }
350
351         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
352                 DEBUG(0,("lock4 succeeded! This is a locking bug\n"));
353                 return;
354         } else {
355                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
356         }
357
358         if (!cli_close(&cli1, fnum1)) {
359                 DEBUG(0,("close2 failed (%s)\n", cli_errstr(&cli1)));
360                 return;
361         }
362
363         if (!cli_close(&cli2, fnum3)) {
364                 DEBUG(0,("close3 failed (%s)\n", cli_errstr(&cli2)));
365                 return;
366         }
367
368         if (!cli_unlink(&cli1, fname)) {
369                 DEBUG(0,("unlink failed (%s)\n", cli_errstr(&cli1)));
370                 return;
371         }
372
373
374         close_connection(&cli1);
375         close_connection(&cli2);
376
377         DEBUG(0,("Passed locktest1\n"));
378 }
379
380
381 /*
382   This test checks that 
383
384   1) the server supports multiple locking contexts on the one SMB
385   connection, distinguished by PID.  
386
387   2) the server correctly fails overlapping locks made by the same PID (this
388      goes against POSIX behaviour, which is why it is tricky to implement)
389
390   3) the server denies unlock requests by an incorrect client PID
391 */
392 static void run_locktest2(void)
393 {
394         static struct cli_state cli;
395         char *fname = "\\lockt2.lck";
396         int fnum1, fnum2, fnum3;
397
398         if (open_connection(&cli) != 0) {
399                 return;
400         }
401
402         cli_sockopt(&cli, sockops);
403
404         DEBUG(0,("starting locktest2\n"));
405
406         cli_unlink(&cli, fname);
407
408         cli_setpid(&cli, 1);
409
410         fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
411         if (fnum1 == -1) {
412                 DEBUG(0,("open of %s failed (%s)\n", fname, cli_errstr(&cli)));
413                 return;
414         }
415
416         fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
417         if (fnum2 == -1) {
418                 DEBUG(0,("open2 of %s failed (%s)\n", fname, cli_errstr(&cli)));
419                 return;
420         }
421
422         cli_setpid(&cli, 2);
423
424         fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
425         if (fnum3 == -1) {
426                 DEBUG(0,("open3 of %s failed (%s)\n", fname, cli_errstr(&cli)));
427                 return;
428         }
429
430         cli_setpid(&cli, 1);
431
432         if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
433                 DEBUG(0,("lock1 failed (%s)\n", cli_errstr(&cli)));
434                 return;
435         }
436
437         if (cli_lock(&cli, fnum2, 0, 4, 0)) {
438                 DEBUG(0,("lock2 succeeded! This is a locking bug\n"));
439         } else {
440                 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
441         }
442
443         cli_setpid(&cli, 2);
444
445         if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
446                 DEBUG(0,("unlock1 succeeded! This is a locking bug\n"));
447         }
448
449         if (cli_lock(&cli, fnum3, 0, 4, 0)) {
450                 DEBUG(0,("lock3 succeeded! This is a locking bug\n"));
451         } else {
452                 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
453         }
454
455         cli_setpid(&cli, 1);
456
457         if (!cli_close(&cli, fnum1)) {
458                 DEBUG(0,("close1 failed (%s)\n", cli_errstr(&cli)));
459                 return;
460         }
461
462         if (!cli_close(&cli, fnum2)) {
463                 DEBUG(0,("close2 failed (%s)\n", cli_errstr(&cli)));
464                 return;
465         }
466
467         if (!cli_close(&cli, fnum3)) {
468                 DEBUG(0,("close3 failed (%s)\n", cli_errstr(&cli)));
469                 return;
470         }
471
472         close_connection(&cli);
473
474         DEBUG(0,("locktest2 finished\n"));
475 }
476
477
478 /*
479   This test checks that 
480
481   1) the server supports the full offset range in lock requests
482 */
483 static void run_locktest3(int numops)
484 {
485         static struct cli_state cli1, cli2;
486         char *fname = "\\lockt3.lck";
487         int fnum1, fnum2, i;
488         uint32 offset;
489
490 #define NEXT_OFFSET offset += (~(uint32)0) / numops
491
492         if (open_connection(&cli1) != 0 || open_connection(&cli2) != 0) {
493                 return;
494         }
495         cli_sockopt(&cli1, sockops);
496         cli_sockopt(&cli2, sockops);
497
498         DEBUG(0,("starting locktest3\n"));
499
500         cli_unlink(&cli1, fname);
501
502         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
503         if (fnum1 == -1) {
504                 DEBUG(0,("open of %s failed (%s)\n", fname, cli_errstr(&cli1)));
505                 return;
506         }
507         fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
508         if (fnum2 == -1) {
509                 DEBUG(0,("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2)));
510                 return;
511         }
512
513         for (offset=i=0;i<numops;i++) {
514                 NEXT_OFFSET;
515                 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
516                         DEBUG(0,("lock1 %d failed (%s)\n", 
517                                i,
518                                cli_errstr(&cli1)));
519                         return;
520                 }
521
522                 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
523                         DEBUG(0,("lock2 %d failed (%s)\n", 
524                                i,
525                                cli_errstr(&cli1)));
526                         return;
527                 }
528         }
529
530         for (offset=i=0;i<numops;i++) {
531                 NEXT_OFFSET;
532
533                 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
534                         DEBUG(0,("error: lock1 %d succeeded!\n", i));
535                         return;
536                 }
537
538                 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
539                         DEBUG(0,("error: lock2 %d succeeded!\n", i));
540                         return;
541                 }
542
543                 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
544                         DEBUG(0,("error: lock3 %d succeeded!\n", i));
545                         return;
546                 }
547
548                 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
549                         DEBUG(0,("error: lock4 %d succeeded!\n", i));
550                         return;
551                 }
552         }
553
554         for (offset=i=0;i<numops;i++) {
555                 NEXT_OFFSET;
556
557                 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
558                         DEBUG(0,("unlock1 %d failed (%s)\n", 
559                                i,
560                                cli_errstr(&cli1)));
561                         return;
562                 }
563
564                 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
565                         DEBUG(0,("unlock2 %d failed (%s)\n", 
566                                i,
567                                cli_errstr(&cli1)));
568                         return;
569                 }
570         }
571
572         if (!cli_close(&cli1, fnum1)) {
573                 DEBUG(0,("close1 failed (%s)\n", cli_errstr(&cli1)));
574         }
575
576         if (!cli_close(&cli2, fnum2)) {
577                 DEBUG(0,("close2 failed (%s)\n", cli_errstr(&cli2)));
578         }
579
580         if (!cli_unlink(&cli1, fname)) {
581                 DEBUG(0,("unlink failed (%s)\n", cli_errstr(&cli1)));
582                 return;
583         }
584
585         close_connection(&cli1);
586         close_connection(&cli2);
587
588         DEBUG(0,("finished locktest3\n"));
589 }
590
591
592 /*
593 test whether fnums and tids open on one VC are available on another (a major
594 security hole)
595 */
596 static void run_fdpasstest(void)
597 {
598         static struct cli_state cli1, cli2;
599         char *fname = "\\fdpass.tst";
600         int fnum1;
601         pstring buf;
602
603         if (open_connection(&cli1) != 0 || open_connection(&cli2) != 0) {
604                 return;
605         }
606         cli_sockopt(&cli1, sockops);
607         cli_sockopt(&cli2, sockops);
608
609         DEBUG(0,("starting fdpasstest\n"));
610
611         cli_unlink(&cli1, fname);
612
613         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
614         if (fnum1 == -1) {
615                 DEBUG(0,("open of %s failed (%s)\n", fname, cli_errstr(&cli1)));
616                 return;
617         }
618
619         if (cli_write(&cli1, fnum1, 0, "hello world\n", 0, 13) != 13) {
620                 DEBUG(0,("write failed (%s)\n", cli_errstr(&cli1)));
621                 return;
622         }
623
624         cli2.vuid = cli1.vuid;
625         cli2.cnum = cli1.cnum;
626         cli2.pid = cli1.pid;
627
628
629         if (cli_read(&cli2, fnum1, buf, 0, 13) == 13) {
630                 DEBUG(0,("read succeeded! nasty security hole [%s]\n",
631                        buf));
632                 return;
633         }
634
635         cli_close(&cli1, fnum1);
636         cli_unlink(&cli1, fname);
637
638         close_connection(&cli1);
639         close_connection(&cli2);
640
641         DEBUG(0,("finished fdpasstest\n"));
642 }
643
644
645 /*
646   This test checks that 
647
648   1) the server does not allow an unlink on a file that is open
649 */
650 static void run_unlinktest(void)
651 {
652         static struct cli_state cli;
653         char *fname = "\\unlink.tst";
654         int fnum;
655
656         if (open_connection(&cli) != 0) {
657                 return;
658         }
659
660         cli_sockopt(&cli, sockops);
661
662         DEBUG(0,("starting unlink test\n"));
663
664         cli_unlink(&cli, fname);
665
666         cli_setpid(&cli, 1);
667
668         fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
669         if (fnum == -1) {
670                 DEBUG(0,("open of %s failed (%s)\n", fname, cli_errstr(&cli)));
671                 return;
672         }
673
674         if (cli_unlink(&cli, fname)) {
675                 DEBUG(0,("error: server allowed unlink on an open file\n"));
676         }
677
678         cli_close(&cli, fnum);
679         cli_unlink(&cli, fname);
680
681         close_connection(&cli);
682
683         DEBUG(0,("unlink test finished\n"));
684 }
685
686
687 /*
688 test how many open files this server supports on the one socket
689 */
690 static void run_maxfidtest(int n)
691 {
692         static struct cli_state cli;
693         char *template = "\\maxfid.%d.%d";
694         fstring fname;
695         int fnum;
696         int retries=4;
697
698         srandom(getpid());
699
700         while (open_connection(&cli) != 0 && retries--) msleep(random() % 2000);
701
702         if (retries <= 0) {
703                 DEBUG(0,("failed to connect\n"));
704                 return;
705         }
706
707         cli_sockopt(&cli, sockops);
708
709         DEBUG(0,("starting maxfid test\n"));
710
711         fnum = 0;
712         while (1) {
713                 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
714                 if (cli_open(&cli, fname, 
715                              O_RDWR|O_CREAT|O_TRUNC, DENY_NONE) ==
716                     -1) {
717                         DEBUG(0,("open of %s failed (%s)\n", 
718                                fname, cli_errstr(&cli)));
719                         DEBUG(0,("maximum fnum is %d\n", fnum));
720                         break;
721                 }
722                 fnum++;
723         }
724
725         DEBUG(0,("cleaning up\n"));
726         while (fnum > n) {
727                 fnum--;
728                 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
729                 if (cli_unlink(&cli, fname)) {
730                         DEBUG(0,("unlink of %s failed (%s)\n", 
731                                fname, cli_errstr(&cli)));
732                 }
733         }
734
735         DEBUG(0,("maxfid test finished\n"));
736         close_connection(&cli);
737 }
738
739 /* generate a random buffer */
740 static void rand_buf(char *buf, int len)
741 {
742         while (len--) {
743                 *buf = sys_random();
744                 buf++;
745         }
746 }
747
748 /* send random IPC commands */
749 static void run_randomipc(int numops)
750 {
751         char *rparam = NULL;
752         char *rdata = NULL;
753         int rdrcnt,rprcnt;
754         char param[BUFFER_SIZE];
755         int api, param_len, i;
756         int reconnect_count = 50;
757         static struct cli_state cli;
758
759         DEBUG(0,("starting random ipc test\n"));
760
761         while (reconnect_count > 0 && open_connection(&cli) != 0)
762         {
763                 DEBUG(0,("connection failed: retrying %d\n", reconnect_count));
764                 msleep(sys_random() % 1000);
765                 reconnect_count--;
766         }
767
768         if (reconnect_count == 0)
769         {
770                 return;
771         }
772
773         for (i=0;i<numops * 100;i++)
774         {
775                 api = sys_random() % 500;
776                 if ((sys_random() % 10) == 0)
777                 {
778                         param_len = (sys_random() % BUFFER_SIZE);
779                 }
780                 else
781                 {
782                         param_len = (sys_random() % 64);
783                 }
784
785                 rand_buf(param, param_len);
786   
787                 SSVAL(param,0,api); 
788
789                 cli_api(&cli,
790                         param, param_len, 8,  
791                         NULL, 0, BUFFER_SIZE, 
792                         &rparam, &rprcnt,
793                         &rdata, &rdrcnt);
794         }
795
796         close_connection(&cli);
797
798         DEBUG(0,("finished random ipc test\n"));
799 }
800
801 /* send random IPC commands */
802 static void run_randomipc_nowait(int numops)
803 {
804         char param[BUFFER_SIZE];
805         int api, param_len, i;
806         int reconnect_count = 50;
807         static struct cli_state cli;
808
809         DEBUG(0,("start random ipc test no waiting for SMBtrans response\n"));
810
811         while (reconnect_count > 0 && open_connection(&cli) != 0)
812         {
813                 DEBUG(0,("connection failed: retrying %d\n", reconnect_count));
814                 msleep(sys_random() % 1000);
815                 reconnect_count--;
816         }
817
818         if (reconnect_count == 0)
819         {
820                 return;
821         }
822
823         for (i=0;i<numops * 100;i++)
824         {
825                 api = sys_random() % 500;
826                 if ((sys_random() % 10) == 0)
827                 {
828                         param_len = (sys_random() % BUFFER_SIZE);
829                 }
830                 else
831                 {
832                         param_len = (sys_random() % 64);
833                 }
834
835                 rand_buf(param, param_len);
836   
837                 SSVAL(param,0,api); 
838
839                 cli_send_trans(&cli,SMBtrans,
840                         PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
841                         0,0,                             /* fid, flags */
842                         NULL,0,0,                /* Setup, length, max */
843
844                         param, param_len, 8,  
845                         NULL, 0, BUFFER_SIZE);
846         }
847
848         close_connection(&cli);
849
850         DEBUG(0,("finished random ipc test\n"));
851 }
852
853
854
855 static void browse_callback(const char *sname, uint32 stype, 
856                             const char *comment)
857 {
858         DEBUG(0,("\t%20.20s %08x %s\n", sname, stype, comment));
859 }
860
861
862
863 /*
864   This test checks the browse list code
865
866 */
867 static void run_browsetest(void)
868 {
869         static struct cli_state cli;
870
871         DEBUG(0,("starting browse test\n"));
872
873         if (open_connection(&cli) != 0) {
874                 return;
875         }
876
877         DEBUG(0,("domain list:\n"));
878         cli_NetServerEnum(&cli, workgroup, 
879                           SV_TYPE_DOMAIN_ENUM,
880                           browse_callback);
881
882         DEBUG(0,("machine list:\n"));
883         cli_NetServerEnum(&cli, workgroup, 
884                           SV_TYPE_ALL,
885                           browse_callback);
886
887         close_connection(&cli);
888
889         DEBUG(0,("browse test finished\n"));
890 }
891
892
893 /*
894   This checks how the getatr calls works
895 */
896 static void run_attrtest(void)
897 {
898         static struct cli_state cli;
899         int fnum;
900         time_t t, t2;
901         char *fname = "\\attrib.tst";
902
903         DEBUG(0,("starting attrib test\n"));
904
905         if (open_connection(&cli) != 0) {
906                 return;
907         }
908
909         cli_unlink(&cli, fname);
910         fnum = cli_open(&cli, fname, 
911                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
912         cli_close(&cli, fnum);
913         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
914                 DEBUG(0,("getatr failed (%s)\n", cli_errstr(&cli)));
915         }
916
917         if (abs(t - time(NULL)) > 2) {
918                 DEBUG(0,("ERROR: SMBgetatr bug. time is %s",
919                        ctime(&t)));
920                 t = time(NULL);
921         }
922
923         t2 = t-60*60*24; /* 1 day ago */
924
925         if (!cli_setatr(&cli, fname, 0, t2)) {
926                 DEBUG(0,("setatr failed (%s)\n", cli_errstr(&cli)));
927         }
928
929         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
930                 DEBUG(0,("getatr failed (%s)\n", cli_errstr(&cli)));
931         }
932
933         if (t != t2) {
934                 DEBUG(0,("ERROR: getatr/setatr bug. times are\n%s",
935                        ctime(&t)));
936                 DEBUG(0,("%s", ctime(&t2)));
937         }
938
939         cli_unlink(&cli, fname);
940
941         close_connection(&cli);
942
943         DEBUG(0,("attrib test finished\n"));
944 }
945
946
947 /*
948   This checks a couple of trans2 calls
949 */
950 static void run_trans2test(void)
951 {
952         static struct cli_state cli;
953         int fnum;
954         size_t size;
955         time_t c_time, a_time, m_time, w_time, m_time2;
956         char *fname = "\\trans2.tst";
957         char *dname = "\\trans2";
958         char *fname2 = "\\trans2\\trans2.tst";
959
960         DEBUG(0,("starting trans2 test\n"));
961
962         if (open_connection(&cli) != 0) {
963                 return;
964         }
965
966         cli_unlink(&cli, fname);
967         fnum = cli_open(&cli, fname, 
968                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
969         if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time,
970                            NULL, NULL)) {
971                 DEBUG(0,("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli)));
972         }
973         cli_close(&cli, fnum);
974
975         sleep(2);
976
977         cli_unlink(&cli, fname);
978         fnum = cli_open(&cli, fname, 
979                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
980         cli_close(&cli, fnum);
981
982         if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
983                 DEBUG(0,("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli)));
984         } else {
985                 if (c_time != m_time) {
986                         DEBUG(0,("create time=%s", ctime(&c_time)));
987                         DEBUG(0,("modify time=%s", ctime(&m_time)));
988                         DEBUG(0,("This system appears to have sticky create times\n"));
989                 }
990                 if (a_time % (60*60) == 0) {
991                         DEBUG(0,("access time=%s", ctime(&a_time)));
992                         DEBUG(0,("This system appears to set a midnight access time\n"));
993                 }
994
995                 if (abs(m_time - time(NULL)) > 60*60*24*7) {
996                         DEBUG(0,("ERROR: totally incorrect times - maybe word reversed?\n"));
997                 }
998         }
999
1000
1001         cli_unlink(&cli, fname);
1002         fnum = cli_open(&cli, fname, 
1003                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1004         cli_close(&cli, fnum);
1005         if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time, 
1006                             &w_time, &size, NULL, NULL)) {
1007                 DEBUG(0,("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)));
1008         } else {
1009                 if (w_time < 60*60*24*2) {
1010                         DEBUG(0,("write time=%s", ctime(&w_time)));
1011                         DEBUG(0,("This system appears to set a initial 0 write time\n"));
1012                 }
1013         }
1014
1015         cli_unlink(&cli, fname);
1016
1017
1018         /* check if the server updates the directory modification time
1019            when creating a new file */
1020         if (!cli_mkdir(&cli, dname)) {
1021                 DEBUG(0,("ERROR: mkdir failed (%s)\n", cli_errstr(&cli)));
1022         }
1023         sleep(3);
1024         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time, 
1025                             &w_time, &size, NULL, NULL)) {
1026                 DEBUG(0,("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)));
1027         }
1028
1029         fnum = cli_open(&cli, fname2, 
1030                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1031         cli_write(&cli, fnum,  0, (char *)&fnum, 0, sizeof(fnum));
1032         cli_close(&cli, fnum);
1033         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2, 
1034                             &w_time, &size, NULL, NULL)) {
1035                 DEBUG(0,("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)));
1036         } else {
1037                 if (m_time2 == m_time)
1038                         DEBUG(0,("This system does not update directory modification times\n"));
1039         }
1040         cli_unlink(&cli, fname2);
1041         cli_rmdir(&cli, dname);
1042
1043
1044         close_connection(&cli);
1045
1046         DEBUG(0,("trans2 test finished\n"));
1047 }
1048
1049
1050 static void run_connection(int numops)
1051 {
1052         struct cli_state c;
1053         int count = 0;
1054         int failed[NUM_ERR_STATES];
1055         int i;
1056
1057         DEBUG(0,("Connection test starts:\n"));
1058
1059         for (i = 0; i < NUM_ERR_STATES; i++)
1060         {
1061                 failed[i] = 0;
1062         }
1063
1064         for (i = 0; i < numops; i++)
1065         {
1066                 int err;
1067                 DEBUG(0,("Connection test %d %d\n", i, numops));
1068                 if ((err = open_connection(&c)))
1069                 {
1070                         failed[err]++;
1071                 }
1072                 count++;
1073         }
1074
1075         {
1076                 int failtotal = 0;
1077
1078                 for (i = 0, failtotal = 0; i < NUM_ERR_STATES; i++)
1079                 {
1080                         failtotal += failed[i];
1081                 }
1082                 DEBUG(0,("Connection test results: count %d success %d\n", count, count-failtotal));
1083         }
1084         for (i = 0; i < NUM_ERR_STATES; i++)
1085         {
1086                 DEBUG(0,("%s: failed: %d\n", smb_messages[i], failed[i]));
1087         }
1088 }
1089
1090 static void create_procs(int nprocs, int numops, void (*fn)(int ))
1091 {
1092         int i, status;
1093
1094         for (i=0;i<nprocs;i++)
1095         {
1096                 if (fork() == 0)
1097                 {
1098                         int mypid = getpid();
1099                         sys_srandom(mypid ^ time(NULL));
1100
1101                         if (!dbg_interactive())
1102                         {
1103                                 slprintf(debugf, sizeof(debugf), "./log.torture.%d", mypid);
1104                                 reopen_logs();
1105                         }
1106
1107                         fn(numops);
1108                         dbgflush();
1109                         _exit(0);
1110                 }
1111         }
1112
1113         for (i=0;i<nprocs;i++)
1114         {
1115                 waitpid(0, &status, 0);
1116         }
1117 }
1118
1119
1120
1121 #define DEBUG_INTERACTIVE True
1122
1123 /****************************************************************************
1124   main program
1125 ****************************************************************************/
1126  int main(int argc,char *argv[])
1127 {
1128         int nprocs=1, numops=100;
1129         int opt;
1130         char *p;
1131         int gotpass = 0;
1132         extern char *optarg;
1133         extern int optind;
1134         extern BOOL append_log;
1135         extern BOOL timestamp_log;
1136
1137         DEBUGLEVEL = 0;
1138         pstrcpy(debugf,"./log.torture");
1139         setup_logging(argv[0], DEBUG_INTERACTIVE);
1140         append_log = True;
1141         timestamp_log = False;
1142
1143         charset_initialise();
1144
1145         if (argc < 2) {
1146                 usage();
1147         }
1148
1149         for(p = argv[1]; *p; p++)
1150           if(*p == '\\')
1151             *p = '/';
1152  
1153         if (strncmp(argv[1], "//", 2)) {
1154                 usage();
1155         }
1156
1157         fstrcpy(host, &argv[1][2]);
1158         p = strchr(&host[2],'/');
1159         if (!p) {
1160                 usage();
1161         }
1162         *p = 0;
1163         fstrcpy(share, p+1);
1164
1165         get_myname(myname,NULL);
1166
1167         if (*username == 0 && getenv("LOGNAME")) {
1168           pstrcpy(username,getenv("LOGNAME"));
1169         }
1170
1171         argc--;
1172         argv++;
1173
1174
1175         while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
1176                 switch (opt) {
1177                 case 'W':
1178                         fstrcpy(workgroup,optarg);
1179                         break;
1180                 case 'm':
1181                         max_protocol = interpret_protocol(optarg, max_protocol);
1182                         break;
1183                 case 'N':
1184                         nprocs = atoi(optarg);
1185                         break;
1186                 case 'o':
1187                         numops = atoi(optarg);
1188                         break;
1189                 case 'O':
1190                         sockops = optarg;
1191                         break;
1192                 case 'n':
1193                         fstrcpy(myname, optarg);
1194                         break;
1195                 case 'U':
1196                         pstrcpy(username,optarg);
1197                         p = strchr(username,'%');
1198                         if (p) {
1199                                 *p = 0;
1200                                 pstrcpy(password, p+1);
1201                                 gotpass = 1;
1202                         }
1203                         break;
1204                 default:
1205                         printf("Unknown option %c (%d)\n", (char)opt, opt);
1206                         usage();
1207                 }
1208         }
1209
1210
1211         while (!gotpass) {
1212                 p = getpass("Password:");
1213                 if (p) {
1214                         pstrcpy(password, p);
1215                         gotpass = 1;
1216                 }
1217         }
1218
1219         printf("host=%s share=%s user=%s myname=%s procs=%d ops=%d\n", 
1220                host, share, username, myname, nprocs, numops);
1221
1222         create_procs(nprocs, numops, run_connection);
1223 /*
1224
1225         create_procs(nprocs, numops, run_randomipc);
1226         create_procs(nprocs, numops, run_randomipc_nowait);
1227
1228         run_fdpasstest();
1229         run_locktest1();
1230         run_locktest2();
1231         run_locktest3(numops);
1232         run_unlinktest();
1233         run_browsetest();
1234         run_attrtest();
1235         run_trans2test();
1236
1237         create_procs(nprocs, numops, run_maxfidtest);
1238
1239
1240
1241         start_timer();
1242         create_procs(nprocs, numops, run_torture);
1243         printf("rw_torture: %g secs\n", end_timer());
1244 */
1245         dbgflush();
1246
1247         return(0);
1248 }
1249
1250