safe string error reporting functions (found a potential buffer overflow
[ira/wip.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 #define TORT_BUFFER_SIZE 1024
749
750 /* send random IPC commands */
751 static void run_randomipc(int numops)
752 {
753         char *rparam = NULL;
754         char *rdata = NULL;
755         int rdrcnt,rprcnt;
756         char param[TORT_BUFFER_SIZE];
757         int api, param_len, i;
758         int reconnect_count = 500;
759         static struct cli_state cli;
760
761         DEBUG(0,("starting random ipc test\n"));
762
763         while (reconnect_count > 0 && open_connection(&cli) != 0)
764         {
765                 DEBUG(0,("connection failed: retrying %d\n", reconnect_count));
766                 msleep(sys_random() % 5000);
767                 reconnect_count--;
768         }
769
770         if (reconnect_count == 0)
771         {
772                 return;
773         }
774
775         for (i=0;i<numops * 100;i++)
776         {
777                 api = sys_random() % 500;
778                 if ((sys_random() % 10) == 0)
779                 {
780                         param_len = (sys_random() % TORT_BUFFER_SIZE);
781                 }
782                 else
783                 {
784                         param_len = (sys_random() % 64);
785                 }
786
787                 rand_buf(param, param_len);
788   
789                 SSVAL(param,0,api); 
790
791                 cli_api(&cli,
792                         param, param_len, 8,  
793                         NULL, 0, BUFFER_SIZE, 
794                         &rparam, &rprcnt,
795                         &rdata, &rdrcnt);
796         }
797
798         close_connection(&cli);
799
800         DEBUG(0,("finished random ipc test\n"));
801 }
802
803 /* send random IPC commands */
804 static void run_randomipc_nowait(int numops)
805 {
806         char param[TORT_BUFFER_SIZE];
807         int api, param_len, i;
808         int reconnect_count = 500;
809         static struct cli_state cli;
810
811         DEBUG(0,("start random ipc test no waiting for SMBtrans response\n"));
812
813         while (reconnect_count > 0 && open_connection(&cli) != 0)
814         {
815                 DEBUG(0,("connection failed: retrying %d\n", reconnect_count));
816                 msleep(sys_random() % 5000);
817                 reconnect_count--;
818         }
819
820         if (reconnect_count == 0)
821         {
822                 return;
823         }
824
825         for (i=0;i<numops * 100;i++)
826         {
827                 api = sys_random() % 500;
828                 if ((sys_random() % 10) == 0)
829                 {
830                         param_len = (sys_random() % TORT_BUFFER_SIZE);
831                 }
832                 else
833                 {
834                         param_len = (sys_random() % 64);
835                 }
836
837                 rand_buf(param, param_len);
838   
839                 SSVAL(param,0,api); 
840
841                 cli_send_trans(&cli,SMBtrans,
842                         PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
843                         0,0,                             /* fid, flags */
844                         NULL,0,0,                /* Setup, length, max */
845
846                         param, param_len, 8,  
847                         NULL, 0, BUFFER_SIZE);
848         }
849
850         close_connection(&cli);
851
852         DEBUG(0,("finished random ipc test\n"));
853 }
854
855
856
857 static void browse_callback(const char *sname, uint32 stype, 
858                             const char *comment)
859 {
860         DEBUG(0,("\t%20.20s %08x %s\n", sname, stype, comment));
861 }
862
863
864
865 /*
866   This test checks the browse list code
867
868 */
869 static void run_browsetest(void)
870 {
871         static struct cli_state cli;
872
873         DEBUG(0,("starting browse test\n"));
874
875         if (open_connection(&cli) != 0) {
876                 return;
877         }
878
879         DEBUG(0,("domain list:\n"));
880         cli_NetServerEnum(&cli, workgroup, 
881                           SV_TYPE_DOMAIN_ENUM,
882                           browse_callback);
883
884         DEBUG(0,("machine list:\n"));
885         cli_NetServerEnum(&cli, workgroup, 
886                           SV_TYPE_ALL,
887                           browse_callback);
888
889         close_connection(&cli);
890
891         DEBUG(0,("browse test finished\n"));
892 }
893
894
895 /*
896   This checks how the getatr calls works
897 */
898 static void run_attrtest(void)
899 {
900         static struct cli_state cli;
901         int fnum;
902         time_t t, t2;
903         char *fname = "\\attrib.tst";
904
905         DEBUG(0,("starting attrib test\n"));
906
907         if (open_connection(&cli) != 0) {
908                 return;
909         }
910
911         cli_unlink(&cli, fname);
912         fnum = cli_open(&cli, fname, 
913                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
914         cli_close(&cli, fnum);
915         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
916                 DEBUG(0,("getatr failed (%s)\n", cli_errstr(&cli)));
917         }
918
919         if (abs(t - time(NULL)) > 2) {
920                 DEBUG(0,("ERROR: SMBgetatr bug. time is %s",
921                        ctime(&t)));
922                 t = time(NULL);
923         }
924
925         t2 = t-60*60*24; /* 1 day ago */
926
927         if (!cli_setatr(&cli, fname, 0, t2)) {
928                 DEBUG(0,("setatr failed (%s)\n", cli_errstr(&cli)));
929         }
930
931         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
932                 DEBUG(0,("getatr failed (%s)\n", cli_errstr(&cli)));
933         }
934
935         if (t != t2) {
936                 DEBUG(0,("ERROR: getatr/setatr bug. times are\n%s",
937                        ctime(&t)));
938                 DEBUG(0,("%s", ctime(&t2)));
939         }
940
941         cli_unlink(&cli, fname);
942
943         close_connection(&cli);
944
945         DEBUG(0,("attrib test finished\n"));
946 }
947
948
949 /*
950   This checks a couple of trans2 calls
951 */
952 static void run_trans2test(void)
953 {
954         static struct cli_state cli;
955         int fnum;
956         size_t size;
957         time_t c_time, a_time, m_time, w_time, m_time2;
958         char *fname = "\\trans2.tst";
959         char *dname = "\\trans2";
960         char *fname2 = "\\trans2\\trans2.tst";
961
962         DEBUG(0,("starting trans2 test\n"));
963
964         if (open_connection(&cli) != 0) {
965                 return;
966         }
967
968         cli_unlink(&cli, fname);
969         fnum = cli_open(&cli, fname, 
970                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
971         if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time,
972                            NULL, NULL)) {
973                 DEBUG(0,("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli)));
974         }
975         cli_close(&cli, fnum);
976
977         sleep(2);
978
979         cli_unlink(&cli, fname);
980         fnum = cli_open(&cli, fname, 
981                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
982         cli_close(&cli, fnum);
983
984         if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
985                 DEBUG(0,("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli)));
986         } else {
987                 if (c_time != m_time) {
988                         DEBUG(0,("create time=%s", ctime(&c_time)));
989                         DEBUG(0,("modify time=%s", ctime(&m_time)));
990                         DEBUG(0,("This system appears to have sticky create times\n"));
991                 }
992                 if (a_time % (60*60) == 0) {
993                         DEBUG(0,("access time=%s", ctime(&a_time)));
994                         DEBUG(0,("This system appears to set a midnight access time\n"));
995                 }
996
997                 if (abs(m_time - time(NULL)) > 60*60*24*7) {
998                         DEBUG(0,("ERROR: totally incorrect times - maybe word reversed?\n"));
999                 }
1000         }
1001
1002
1003         cli_unlink(&cli, fname);
1004         fnum = cli_open(&cli, fname, 
1005                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1006         cli_close(&cli, fnum);
1007         if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time, 
1008                             &w_time, &size, NULL, NULL)) {
1009                 DEBUG(0,("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)));
1010         } else {
1011                 if (w_time < 60*60*24*2) {
1012                         DEBUG(0,("write time=%s", ctime(&w_time)));
1013                         DEBUG(0,("This system appears to set a initial 0 write time\n"));
1014                 }
1015         }
1016
1017         cli_unlink(&cli, fname);
1018
1019
1020         /* check if the server updates the directory modification time
1021            when creating a new file */
1022         if (!cli_mkdir(&cli, dname)) {
1023                 DEBUG(0,("ERROR: mkdir failed (%s)\n", cli_errstr(&cli)));
1024         }
1025         sleep(3);
1026         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time, 
1027                             &w_time, &size, NULL, NULL)) {
1028                 DEBUG(0,("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)));
1029         }
1030
1031         fnum = cli_open(&cli, fname2, 
1032                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1033         cli_write(&cli, fnum,  0, (char *)&fnum, 0, sizeof(fnum));
1034         cli_close(&cli, fnum);
1035         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2, 
1036                             &w_time, &size, NULL, NULL)) {
1037                 DEBUG(0,("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli)));
1038         } else {
1039                 if (m_time2 == m_time)
1040                         DEBUG(0,("This system does not update directory modification times\n"));
1041         }
1042         cli_unlink(&cli, fname2);
1043         cli_rmdir(&cli, dname);
1044
1045
1046         close_connection(&cli);
1047
1048         DEBUG(0,("trans2 test finished\n"));
1049 }
1050
1051
1052 static void run_connection(int numops)
1053 {
1054         struct cli_state c;
1055         int count = 0;
1056         int failed[NUM_ERR_STATES];
1057         int i;
1058
1059         DEBUG(0,("Connection test starts:\n"));
1060
1061         for (i = 0; i < NUM_ERR_STATES; i++)
1062         {
1063                 failed[i] = 0;
1064         }
1065
1066         for (i = 0; i < numops; i++)
1067         {
1068                 int err;
1069                 DEBUG(0,("Connection test %d %d\n", i, numops));
1070                 if ((err = open_connection(&c)))
1071                 {
1072                         failed[err]++;
1073                 }
1074                 count++;
1075         }
1076
1077         {
1078                 int failtotal = 0;
1079
1080                 for (i = 0, failtotal = 0; i < NUM_ERR_STATES; i++)
1081                 {
1082                         failtotal += failed[i];
1083                 }
1084                 DEBUG(0,("Connection test results: count %d success %d\n", count, count-failtotal));
1085         }
1086         for (i = 0; i < NUM_ERR_STATES; i++)
1087         {
1088                 DEBUG(0,("%s: failed: %d\n", smb_messages[i], failed[i]));
1089         }
1090 }
1091
1092 static void create_procs(int nprocs, int numops, void (*fn)(int ))
1093 {
1094         int i, status;
1095
1096         for (i=0;i<nprocs;i++)
1097         {
1098                 if (fork() == 0)
1099                 {
1100                         int mypid = getpid();
1101                         sys_srandom(mypid ^ time(NULL));
1102
1103                         if (!dbg_interactive())
1104                         {
1105                                 slprintf(debugf, sizeof(debugf), "./log.torture.%d", mypid);
1106                                 reopen_logs();
1107                         }
1108
1109                         fn(numops);
1110                         dbgflush();
1111                         _exit(0);
1112                 }
1113         }
1114
1115         for (i=0;i<nprocs;i++)
1116         {
1117                 waitpid(0, &status, 0);
1118         }
1119 }
1120
1121
1122
1123 #define DEBUG_INTERACTIVE True
1124
1125 /****************************************************************************
1126   main program
1127 ****************************************************************************/
1128  int main(int argc,char *argv[])
1129 {
1130         int nprocs=1, numops=100;
1131         int opt;
1132         char *p;
1133         int gotpass = 0;
1134         extern char *optarg;
1135         extern int optind;
1136         extern BOOL append_log;
1137         extern BOOL timestamp_log;
1138
1139         DEBUGLEVEL = 0;
1140         pstrcpy(debugf,"./log.torture");
1141         setup_logging(argv[0], DEBUG_INTERACTIVE);
1142         append_log = True;
1143         timestamp_log = False;
1144
1145         charset_initialise();
1146
1147         if (argc < 2) {
1148                 usage();
1149         }
1150
1151         for(p = argv[1]; *p; p++)
1152           if(*p == '\\')
1153             *p = '/';
1154  
1155         if (strncmp(argv[1], "//", 2)) {
1156                 usage();
1157         }
1158
1159         fstrcpy(host, &argv[1][2]);
1160         p = strchr(&host[2],'/');
1161         if (!p) {
1162                 usage();
1163         }
1164         *p = 0;
1165         fstrcpy(share, p+1);
1166
1167         get_myname(myname,NULL);
1168
1169         if (*username == 0 && getenv("LOGNAME")) {
1170           pstrcpy(username,getenv("LOGNAME"));
1171         }
1172
1173         argc--;
1174         argv++;
1175
1176
1177         while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
1178                 switch (opt) {
1179                 case 'W':
1180                         fstrcpy(workgroup,optarg);
1181                         break;
1182                 case 'm':
1183                         max_protocol = interpret_protocol(optarg, max_protocol);
1184                         break;
1185                 case 'N':
1186                         nprocs = atoi(optarg);
1187                         break;
1188                 case 'o':
1189                         numops = atoi(optarg);
1190                         break;
1191                 case 'O':
1192                         sockops = optarg;
1193                         break;
1194                 case 'n':
1195                         fstrcpy(myname, optarg);
1196                         break;
1197                 case 'U':
1198                         pstrcpy(username,optarg);
1199                         p = strchr(username,'%');
1200                         if (p) {
1201                                 *p = 0;
1202                                 pstrcpy(password, p+1);
1203                                 gotpass = 1;
1204                         }
1205                         break;
1206                 default:
1207                         printf("Unknown option %c (%d)\n", (char)opt, opt);
1208                         usage();
1209                 }
1210         }
1211
1212
1213         while (!gotpass) {
1214                 p = getpass("Password:");
1215                 if (p) {
1216                         pstrcpy(password, p);
1217                         gotpass = 1;
1218                 }
1219         }
1220
1221         printf("host=%s share=%s user=%s myname=%s procs=%d ops=%d\n", 
1222                host, share, username, myname, nprocs, numops);
1223
1224         create_procs(nprocs, numops, run_randomipc_nowait);
1225 /*
1226         create_procs(nprocs, numops, run_randomipc);
1227
1228         create_procs(nprocs, numops, run_connection);
1229
1230         run_fdpasstest();
1231         run_locktest1();
1232         run_locktest2();
1233         run_locktest3(numops);
1234         run_unlinktest();
1235         run_browsetest();
1236         run_attrtest();
1237         run_trans2test();
1238
1239         create_procs(nprocs, numops, run_maxfidtest);
1240
1241
1242
1243         start_timer();
1244         create_procs(nprocs, numops, run_torture);
1245         printf("rw_torture: %g secs\n", end_timer());
1246 */
1247         dbgflush();
1248
1249         return(0);
1250 }
1251
1252