first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[nivanova/samba-autobuild/.git] / source / 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 static fstring host, workgroup, share, password, username, myname;
27 static int max_protocol = PROTOCOL_NT1;
28 static char *sockops="TCP_NODELAY";
29 static int nprocs=1, numops=100;
30 static struct cli_state current_cli;
31
32 static double create_procs(void (*fn)(int));
33
34
35 static struct timeval tp1,tp2;
36
37 static void start_timer(void)
38 {
39         gettimeofday(&tp1,NULL);
40 }
41
42 static double end_timer(void)
43 {
44         gettimeofday(&tp2,NULL);
45         return((tp2.tv_sec - tp1.tv_sec) + 
46                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
47 }
48
49
50 /* return a pointer to a anonymous shared memory segment of size "size"
51    which will persist across fork() but will disappear when all processes
52    exit 
53
54    The memory is not zeroed 
55
56    This function uses system5 shared memory. It takes advantage of a property
57    that the memory is not destroyed if it is attached when the id is removed
58    */
59 static void *shm_setup(int size)
60 {
61         int shmid;
62         void *ret;
63
64         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
65         if (shmid == -1) {
66                 printf("can't get shared memory\n");
67                 exit(1);
68         }
69         ret = (void *)shmat(shmid, 0, 0);
70         if (!ret || ret == (void *)-1) {
71                 printf("can't attach to shared memory\n");
72                 return NULL;
73         }
74         /* the following releases the ipc, but note that this process
75            and all its children will still have access to the memory, its
76            just that the shmid is no longer valid for other shm calls. This
77            means we don't leave behind lots of shm segments after we exit 
78
79            See Stevens "advanced programming in unix env" for details
80            */
81         shmctl(shmid, IPC_RMID, 0);
82         
83         return ret;
84 }
85
86
87 static BOOL open_connection(struct cli_state *c)
88 {
89         struct nmb_name called, calling;
90         struct in_addr ip;
91         extern struct in_addr ipzero;
92
93         ZERO_STRUCTP(c);
94
95         make_nmb_name(&calling, myname, 0x0, "");
96         make_nmb_name(&called , host, 0x20, "");
97
98         ip = ipzero;
99
100         if (!cli_initialise(c) || !cli_connect(c, host, &ip)) {
101                 printf("Failed to connect with %s\n", host);
102                 return False;
103         }
104
105         c->timeout = 120000; /* set a really long timeout (2 minutes) */
106
107         if (!cli_session_request(c, &calling, &called)) {
108                 printf("%s rejected the session\n",host);
109                 cli_shutdown(c);
110                 return False;
111         }
112
113         if (!cli_negprot(c)) {
114                 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
115                 cli_shutdown(c);
116                 return False;
117         }
118
119         if (!cli_session_setup(c, username, 
120                                password, strlen(password),
121                                password, strlen(password),
122                                workgroup)) {
123                 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
124                 cli_shutdown(c);
125                 return False;
126         }
127
128         if (!cli_send_tconX(c, share, "?????",
129                             password, strlen(password)+1)) {
130                 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
131                 cli_shutdown(c);
132                 return False;
133         }
134
135         return True;
136 }
137
138
139
140 static void close_connection(struct cli_state *c)
141 {
142         if (!cli_tdis(c)) {
143                 printf("tdis failed (%s)\n", cli_errstr(c));
144         }
145
146         cli_shutdown(c);
147 }
148
149
150 /* check if the server produced the expected error code */
151 static BOOL check_error(struct cli_state *c, 
152                         uint8 eclass, uint32 ecode, uint32 nterr)
153 {
154         uint8 class;
155         uint32 num;
156         (void)cli_error(c, &class, &num, NULL);
157         if ((eclass != class || ecode != num) &&
158             num != (nterr&0xFFFFFF)) {
159                 printf("unexpected error code class=%d code=%d\n", 
160                          (int)class, (int)num);
161                 printf(" expected %d/%d %d\n", 
162                        (int)eclass, (int)ecode, (int)nterr);
163                 return False;
164         }
165         return True;
166 }
167
168
169 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
170 {
171         while (!cli_lock(c, fnum, offset, len, -1)) {
172                 if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
173         }
174         return True;
175 }
176
177
178 static BOOL rw_torture(struct cli_state *c)
179 {
180         char *lockfname = "\\torture.lck";
181         fstring fname;
182         int fnum;
183         int fnum2;
184         pid_t pid2, pid = getpid();
185         int i, j;
186         char buf[1024];
187
188         fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
189                          DENY_NONE);
190         if (fnum2 == -1)
191                 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
192         if (fnum2 == -1) {
193                 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
194                 return False;
195         }
196
197
198         for (i=0;i<numops;i++) {
199                 unsigned n = (unsigned)sys_random()%10;
200                 if (i % 10 == 0) {
201                         printf("%d\r", i); fflush(stdout);
202                 }
203                 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
204
205                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
206                         return False;
207                 }
208
209                 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
210                 if (fnum == -1) {
211                         printf("open failed (%s)\n", cli_errstr(c));
212                         break;
213                 }
214
215                 if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
216                         printf("write failed (%s)\n", cli_errstr(c));
217                 }
218
219                 for (j=0;j<50;j++) {
220                         if (cli_write(c, fnum, 0, (char *)buf, 
221                                       sizeof(pid)+(j*sizeof(buf)), 
222                                       sizeof(buf)) != sizeof(buf)) {
223                                 printf("write failed (%s)\n", cli_errstr(c));
224                         }
225                 }
226
227                 pid2 = 0;
228
229                 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
230                         printf("read failed (%s)\n", cli_errstr(c));
231                 }
232
233                 if (pid2 != pid) {
234                         printf("data corruption!\n");
235                 }
236
237                 if (!cli_close(c, fnum)) {
238                         printf("close failed (%s)\n", cli_errstr(c));
239                 }
240
241                 if (!cli_unlink(c, fname)) {
242                         printf("unlink failed (%s)\n", cli_errstr(c));
243                 }
244
245                 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
246                         printf("unlock failed (%s)\n", cli_errstr(c));
247                 }
248         }
249
250         cli_close(c, fnum2);
251         cli_unlink(c, lockfname);
252
253         printf("%d\n", i);
254
255         return True;
256 }
257
258 static void run_torture(int dummy)
259 {
260         struct cli_state cli;
261
262         cli = current_cli;
263
264         cli_sockopt(&cli, sockops);
265
266         rw_torture(&cli);
267         
268         close_connection(&cli);
269 }
270
271 int line_count = 0;
272
273 /* run a test that simulates an approximate netbench client load */
274 static void run_netbench(int client)
275 {
276         struct cli_state cli;
277         int i;
278         fstring fname;
279         pstring line;
280         char cname[20];
281         FILE *f;
282         char *params[20];
283
284         cli = current_cli;
285
286         cli_sockopt(&cli, sockops);
287
288         nb_setup(&cli);
289
290         slprintf(cname,sizeof(fname), "CLIENT%d", client);
291
292         f = fopen("client.txt", "r");
293
294         if (!f) {
295                 perror("client.txt");
296                 return;
297         }
298
299         while (fgets(line, sizeof(line)-1, f)) {
300                 line_count++;
301
302                 line[strlen(line)-1] = 0;
303
304                 /* printf("[%d] %s\n", line_count, line); */
305
306                 all_string_sub(line,"CLIENT1", cname, sizeof(line));
307                 
308                 for (i=0;i<20;i++) params[i] = "";
309
310                 /* parse the command parameters */
311                 params[0] = strtok(line," ");
312                 i = 0;
313                 while (params[i]) params[++i] = strtok(NULL," ");
314
315                 params[i] = "";
316
317                 if (i < 2) continue;
318
319                 if (strcmp(params[1],"REQUEST") == 0) {
320                         if (!strcmp(params[0],"SMBopenX")) {
321                                 fstrcpy(fname, params[5]);
322                         } else if (!strcmp(params[0],"SMBclose")) {
323                                 nb_close(atoi(params[3]));
324                         } else if (!strcmp(params[0],"SMBmkdir")) {
325                                 nb_mkdir(params[3]);
326                         } else if (!strcmp(params[0],"CREATE")) {
327                                 nb_create(params[3], atoi(params[5]));
328                         } else if (!strcmp(params[0],"SMBrmdir")) {
329                                 nb_rmdir(params[3]);
330                         } else if (!strcmp(params[0],"SMBunlink")) {
331                                 fstrcpy(fname, params[3]);
332                         } else if (!strcmp(params[0],"SMBmv")) {
333                                 nb_rename(params[3], params[5]);
334                         } else if (!strcmp(params[0],"SMBgetatr")) {
335                                 fstrcpy(fname, params[3]);
336                         } else if (!strcmp(params[0],"SMBwrite")) {
337                                 nb_write(atoi(params[3]), 
338                                          atoi(params[5]), atoi(params[7]));
339                         } else if (!strcmp(params[0],"SMBwritebraw")) {
340                                 nb_write(atoi(params[3]), 
341                                          atoi(params[7]), atoi(params[5]));
342                         } else if (!strcmp(params[0],"SMBreadbraw")) {
343                                 nb_read(atoi(params[3]), 
344                                          atoi(params[7]), atoi(params[5]));
345                         } else if (!strcmp(params[0],"SMBread")) {
346                                 nb_read(atoi(params[3]), 
347                                          atoi(params[5]), atoi(params[7]));
348                         }
349                 } else {
350                         if (!strcmp(params[0],"SMBopenX")) {
351                                 if (!strncmp(params[2], "ERR", 3)) continue;
352                                 nb_open(fname, atoi(params[3]), atoi(params[5]));
353                         } else if (!strcmp(params[0],"SMBgetatr")) {
354                                 if (!strncmp(params[2], "ERR", 3)) continue;
355                                 nb_stat(fname, atoi(params[3]));
356                         } else if (!strcmp(params[0],"SMBunlink")) {
357                                 if (!strncmp(params[2], "ERR", 3)) continue;
358                                 nb_unlink(fname);
359                         }
360                 }
361         }
362         fclose(f);
363
364         slprintf(fname,sizeof(fname), "CLIENTS/CLIENT%d", client);
365         rmdir(fname);
366         rmdir("CLIENTS");
367
368         printf("+");    
369
370         close_connection(&cli);
371 }
372
373
374 /* run a test that simulates an approximate netbench w9X client load */
375 static void run_nbw95(int dummy)
376 {
377         double t;
378         t = create_procs(run_netbench);
379         /* to produce a netbench result we scale accoding to the
380            netbench measured throughput for the run that produced the
381            sniff that was used to produce client.txt. That run used 2
382            clients and ran for 660 seconds to produce a result of
383            4MBit/sec. */
384         printf("Throughput %g MB/sec (NB=%g MB/sec  %g MBit/sec)\n", 
385                132*nprocs/t, 0.5*0.5*nprocs*660/t, 2*nprocs*660/t);
386 }
387
388 /* run a test that simulates an approximate netbench wNT client load */
389 static void run_nbwnt(int dummy)
390 {
391         double t;
392         t = create_procs(run_netbench);
393         printf("Throughput %g MB/sec (NB=%g MB/sec  %g MBit/sec)\n", 
394                132*nprocs/t, 0.5*0.5*nprocs*660/t, 2*nprocs*660/t);
395 }
396
397
398
399 /*
400   This test checks for two things:
401
402   1) correct support for retaining locks over a close (ie. the server
403      must not use posix semantics)
404   2) support for lock timeouts
405  */
406 static void run_locktest1(int dummy)
407 {
408         static struct cli_state cli1, cli2;
409         char *fname = "\\lockt1.lck";
410         int fnum1, fnum2, fnum3;
411         time_t t1, t2;
412
413         if (!open_connection(&cli1) || !open_connection(&cli2)) {
414                 return;
415         }
416         cli_sockopt(&cli1, sockops);
417         cli_sockopt(&cli2, sockops);
418
419         printf("starting locktest1\n");
420
421         cli_unlink(&cli1, fname);
422
423         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
424         if (fnum1 == -1) {
425                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
426                 return;
427         }
428         fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
429         if (fnum2 == -1) {
430                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
431                 return;
432         }
433         fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
434         if (fnum3 == -1) {
435                 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
436                 return;
437         }
438
439         if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
440                 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
441                 return;
442         }
443
444
445         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
446                 printf("lock2 succeeded! This is a locking bug\n");
447                 return;
448         } else {
449                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
450         }
451
452
453         printf("Testing lock timeouts\n");
454         t1 = time(NULL);
455         if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
456                 printf("lock3 succeeded! This is a locking bug\n");
457                 return;
458         } else {
459                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
460         }
461         t2 = time(NULL);
462
463         if (t2 - t1 < 5) {
464                 printf("error: This server appears not to support timed lock requests\n");
465         }
466
467         if (!cli_close(&cli1, fnum2)) {
468                 printf("close1 failed (%s)\n", cli_errstr(&cli1));
469                 return;
470         }
471
472         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
473                 printf("lock4 succeeded! This is a locking bug\n");
474                 return;
475         } else {
476                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
477         }
478
479         if (!cli_close(&cli1, fnum1)) {
480                 printf("close2 failed (%s)\n", cli_errstr(&cli1));
481                 return;
482         }
483
484         if (!cli_close(&cli2, fnum3)) {
485                 printf("close3 failed (%s)\n", cli_errstr(&cli2));
486                 return;
487         }
488
489         if (!cli_unlink(&cli1, fname)) {
490                 printf("unlink failed (%s)\n", cli_errstr(&cli1));
491                 return;
492         }
493
494
495         close_connection(&cli1);
496         close_connection(&cli2);
497
498         printf("Passed locktest1\n");
499 }
500
501
502 /*
503   This test checks that 
504
505   1) the server supports multiple locking contexts on the one SMB
506   connection, distinguished by PID.  
507
508   2) the server correctly fails overlapping locks made by the same PID (this
509      goes against POSIX behaviour, which is why it is tricky to implement)
510
511   3) the server denies unlock requests by an incorrect client PID
512 */
513 static void run_locktest2(int dummy)
514 {
515         static struct cli_state cli;
516         char *fname = "\\lockt2.lck";
517         int fnum1, fnum2, fnum3;
518
519         if (!open_connection(&cli)) {
520                 return;
521         }
522
523         cli_sockopt(&cli, sockops);
524
525         printf("starting locktest2\n");
526
527         cli_unlink(&cli, fname);
528
529         cli_setpid(&cli, 1);
530
531         fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
532         if (fnum1 == -1) {
533                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
534                 return;
535         }
536
537         fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
538         if (fnum2 == -1) {
539                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
540                 return;
541         }
542
543         cli_setpid(&cli, 2);
544
545         fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
546         if (fnum3 == -1) {
547                 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
548                 return;
549         }
550
551         cli_setpid(&cli, 1);
552
553         if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
554                 printf("lock1 failed (%s)\n", cli_errstr(&cli));
555                 return;
556         }
557
558         if (cli_lock(&cli, fnum2, 0, 4, 0)) {
559                 printf("lock2 succeeded! This is a locking bug\n");
560         } else {
561                 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
562         }
563
564         cli_setpid(&cli, 2);
565
566         if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
567                 printf("unlock1 succeeded! This is a locking bug\n");
568         }
569
570         if (cli_lock(&cli, fnum3, 0, 4, 0)) {
571                 printf("lock3 succeeded! This is a locking bug\n");
572         } else {
573                 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
574         }
575
576         cli_setpid(&cli, 1);
577
578         if (!cli_close(&cli, fnum1)) {
579                 printf("close1 failed (%s)\n", cli_errstr(&cli));
580                 return;
581         }
582
583         if (!cli_close(&cli, fnum2)) {
584                 printf("close2 failed (%s)\n", cli_errstr(&cli));
585                 return;
586         }
587
588         if (!cli_close(&cli, fnum3)) {
589                 printf("close3 failed (%s)\n", cli_errstr(&cli));
590                 return;
591         }
592
593         close_connection(&cli);
594
595         printf("locktest2 finished\n");
596 }
597
598
599 /*
600   This test checks that 
601
602   1) the server supports the full offset range in lock requests
603 */
604 static void run_locktest3(int dummy)
605 {
606         static struct cli_state cli1, cli2;
607         char *fname = "\\lockt3.lck";
608         int fnum1, fnum2, i;
609         uint32 offset;
610
611 #define NEXT_OFFSET offset += (~(uint32)0) / numops
612
613         if (!open_connection(&cli1) || !open_connection(&cli2)) {
614                 return;
615         }
616         cli_sockopt(&cli1, sockops);
617         cli_sockopt(&cli2, sockops);
618
619         printf("starting locktest3\n");
620
621         cli_unlink(&cli1, fname);
622
623         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
624         if (fnum1 == -1) {
625                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
626                 return;
627         }
628         fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
629         if (fnum2 == -1) {
630                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
631                 return;
632         }
633
634         for (offset=i=0;i<numops;i++) {
635                 NEXT_OFFSET;
636                 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
637                         printf("lock1 %d failed (%s)\n", 
638                                i,
639                                cli_errstr(&cli1));
640                         return;
641                 }
642
643                 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
644                         printf("lock2 %d failed (%s)\n", 
645                                i,
646                                cli_errstr(&cli1));
647                         return;
648                 }
649         }
650
651         for (offset=i=0;i<numops;i++) {
652                 NEXT_OFFSET;
653
654                 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
655                         printf("error: lock1 %d succeeded!\n", i);
656                         return;
657                 }
658
659                 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
660                         printf("error: lock2 %d succeeded!\n", i);
661                         return;
662                 }
663
664                 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
665                         printf("error: lock3 %d succeeded!\n", i);
666                         return;
667                 }
668
669                 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
670                         printf("error: lock4 %d succeeded!\n", i);
671                         return;
672                 }
673         }
674
675         for (offset=i=0;i<numops;i++) {
676                 NEXT_OFFSET;
677
678                 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
679                         printf("unlock1 %d failed (%s)\n", 
680                                i,
681                                cli_errstr(&cli1));
682                         return;
683                 }
684
685                 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
686                         printf("unlock2 %d failed (%s)\n", 
687                                i,
688                                cli_errstr(&cli1));
689                         return;
690                 }
691         }
692
693         if (!cli_close(&cli1, fnum1)) {
694                 printf("close1 failed (%s)\n", cli_errstr(&cli1));
695         }
696
697         if (!cli_close(&cli2, fnum2)) {
698                 printf("close2 failed (%s)\n", cli_errstr(&cli2));
699         }
700
701         if (!cli_unlink(&cli1, fname)) {
702                 printf("unlink failed (%s)\n", cli_errstr(&cli1));
703                 return;
704         }
705
706         close_connection(&cli1);
707         close_connection(&cli2);
708
709         printf("finished locktest3\n");
710 }
711
712
713 /*
714 test whether fnums and tids open on one VC are available on another (a major
715 security hole)
716 */
717 static void run_fdpasstest(int dummy)
718 {
719         static struct cli_state cli1, cli2;
720         char *fname = "\\fdpass.tst";
721         int fnum1;
722         pstring buf;
723
724         if (!open_connection(&cli1) || !open_connection(&cli2)) {
725                 return;
726         }
727         cli_sockopt(&cli1, sockops);
728         cli_sockopt(&cli2, sockops);
729
730         printf("starting fdpasstest\n");
731
732         cli_unlink(&cli1, fname);
733
734         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
735         if (fnum1 == -1) {
736                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
737                 return;
738         }
739
740         if (cli_write(&cli1, fnum1, 0, "hello world\n", 0, 13) != 13) {
741                 printf("write failed (%s)\n", cli_errstr(&cli1));
742                 return;
743         }
744
745         cli2.vuid = cli1.vuid;
746         cli2.cnum = cli1.cnum;
747         cli2.pid = cli1.pid;
748
749
750         if (cli_read(&cli2, fnum1, buf, 0, 13) == 13) {
751                 printf("read succeeded! nasty security hole [%s]\n",
752                        buf);
753                 return;
754         }
755
756         cli_close(&cli1, fnum1);
757         cli_unlink(&cli1, fname);
758
759         close_connection(&cli1);
760         close_connection(&cli2);
761
762         printf("finished fdpasstest\n");
763 }
764
765
766 /*
767   This test checks that 
768
769   1) the server does not allow an unlink on a file that is open
770 */
771 static void run_unlinktest(int dummy)
772 {
773         static struct cli_state cli;
774         char *fname = "\\unlink.tst";
775         int fnum;
776
777         if (!open_connection(&cli)) {
778                 return;
779         }
780
781         cli_sockopt(&cli, sockops);
782
783         printf("starting unlink test\n");
784
785         cli_unlink(&cli, fname);
786
787         cli_setpid(&cli, 1);
788
789         fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
790         if (fnum == -1) {
791                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
792                 return;
793         }
794
795         if (cli_unlink(&cli, fname)) {
796                 printf("error: server allowed unlink on an open file\n");
797         }
798
799         cli_close(&cli, fnum);
800         cli_unlink(&cli, fname);
801
802         close_connection(&cli);
803
804         printf("unlink test finished\n");
805 }
806
807
808 /*
809 test how many open files this server supports on the one socket
810 */
811 static void run_maxfidtest(int dummy)
812 {
813         static struct cli_state cli;
814         char *template = "\\maxfid.%d.%d";
815         fstring fname;
816         int fnum;
817         int retries=4;
818         int n = numops;
819
820         cli = current_cli;
821
822         if (retries <= 0) {
823                 printf("failed to connect\n");
824                 return;
825         }
826
827         cli_sockopt(&cli, sockops);
828
829         fnum = 0;
830         while (1) {
831                 slprintf(fname,sizeof(fname)-1,template, fnum,(int)getpid());
832                 if (cli_open(&cli, fname, 
833                              O_RDWR|O_CREAT|O_TRUNC, DENY_NONE) ==
834                     -1) {
835                         printf("open of %s failed (%s)\n", 
836                                fname, cli_errstr(&cli));
837                         printf("maximum fnum is %d\n", fnum);
838                         break;
839                 }
840                 fnum++;
841         }
842
843         printf("cleaning up\n");
844         while (fnum > n) {
845                 fnum--;
846                 slprintf(fname,sizeof(fname)-1,template, fnum,(int)getpid());
847                 if (cli_unlink(&cli, fname)) {
848                         printf("unlink of %s failed (%s)\n", 
849                                fname, cli_errstr(&cli));
850                 }
851         }
852
853         printf("maxfid test finished\n");
854         close_connection(&cli);
855 }
856
857 /* generate a random buffer */
858 static void rand_buf(char *buf, int len)
859 {
860         while (len--) {
861                 *buf = (char)sys_random();
862                 buf++;
863         }
864 }
865
866 /* send random IPC commands */
867 static void run_randomipc(int dummy)
868 {
869         char *rparam = NULL;
870         char *rdata = NULL;
871         int rdrcnt,rprcnt;
872         pstring param;
873         int api, param_len, i;
874         static struct cli_state cli;
875
876         printf("starting random ipc test\n");
877
878         if (!open_connection(&cli)) {
879                 return;
880         }
881
882         for (i=0;i<50000;i++) {
883                 api = sys_random() % 500;
884                 param_len = (sys_random() % 64);
885
886                 rand_buf(param, param_len);
887   
888                 SSVAL(param,0,api); 
889
890                 cli_api(&cli, 
891                         param, param_len, 8,  
892                         NULL, 0, BUFFER_SIZE, 
893                         &rparam, &rprcnt,     
894                         &rdata, &rdrcnt);
895         }
896
897         close_connection(&cli);
898
899         printf("finished random ipc test\n");
900 }
901
902
903
904 static void browse_callback(const char *sname, uint32 stype, 
905                             const char *comment)
906 {
907         printf("\t%20.20s %08x %s\n", sname, stype, comment);
908 }
909
910
911
912 /*
913   This test checks the browse list code
914
915 */
916 static void run_browsetest(int dummy)
917 {
918         static struct cli_state cli;
919
920         printf("starting browse test\n");
921
922         if (!open_connection(&cli)) {
923                 return;
924         }
925
926         printf("domain list:\n");
927         cli_NetServerEnum(&cli, cli.server_domain, 
928                           SV_TYPE_DOMAIN_ENUM,
929                           browse_callback);
930
931         printf("machine list:\n");
932         cli_NetServerEnum(&cli, cli.server_domain, 
933                           SV_TYPE_ALL,
934                           browse_callback);
935
936         close_connection(&cli);
937
938         printf("browse test finished\n");
939 }
940
941
942 /*
943   This checks how the getatr calls works
944 */
945 static void run_attrtest(int dummy)
946 {
947         static struct cli_state cli;
948         int fnum;
949         time_t t, t2;
950         char *fname = "\\attrib.tst";
951
952         printf("starting attrib test\n");
953
954         if (!open_connection(&cli)) {
955                 return;
956         }
957
958         cli_unlink(&cli, fname);
959         fnum = cli_open(&cli, fname, 
960                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
961         cli_close(&cli, fnum);
962         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
963                 printf("getatr failed (%s)\n", cli_errstr(&cli));
964         }
965
966         if (abs(t - time(NULL)) > 2) {
967                 printf("ERROR: SMBgetatr bug. time is %s",
968                        ctime(&t));
969                 t = time(NULL);
970         }
971
972         t2 = t-60*60*24; /* 1 day ago */
973
974         if (!cli_setatr(&cli, fname, 0, t2)) {
975                 printf("setatr failed (%s)\n", cli_errstr(&cli));
976         }
977
978         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
979                 printf("getatr failed (%s)\n", cli_errstr(&cli));
980         }
981
982         if (t != t2) {
983                 printf("ERROR: getatr/setatr bug. times are\n%s",
984                        ctime(&t));
985                 printf("%s", ctime(&t2));
986         }
987
988         cli_unlink(&cli, fname);
989
990         close_connection(&cli);
991
992         printf("attrib test finished\n");
993 }
994
995
996 /*
997   This checks a couple of trans2 calls
998 */
999 static void run_trans2test(int dummy)
1000 {
1001         static struct cli_state cli;
1002         int fnum;
1003         size_t size;
1004         time_t c_time, a_time, m_time, w_time, m_time2;
1005         char *fname = "\\trans2.tst";
1006         char *dname = "\\trans2";
1007         char *fname2 = "\\trans2\\trans2.tst";
1008
1009         printf("starting trans2 test\n");
1010
1011         if (!open_connection(&cli)) {
1012                 return;
1013         }
1014
1015         cli_unlink(&cli, fname);
1016         fnum = cli_open(&cli, fname, 
1017                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1018         if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time,
1019                            NULL, NULL)) {
1020                 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
1021         }
1022         cli_close(&cli, fnum);
1023
1024         sleep(2);
1025
1026         cli_unlink(&cli, fname);
1027         fnum = cli_open(&cli, fname, 
1028                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1029         cli_close(&cli, fnum);
1030
1031         if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
1032                 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
1033         } else {
1034                 if (c_time != m_time) {
1035                         printf("create time=%s", ctime(&c_time));
1036                         printf("modify time=%s", ctime(&m_time));
1037                         printf("This system appears to have sticky create times\n");
1038                 }
1039                 if (a_time % (60*60) == 0) {
1040                         printf("access time=%s", ctime(&a_time));
1041                         printf("This system appears to set a midnight access time\n");
1042                 }
1043
1044                 if (abs(m_time - time(NULL)) > 60*60*24*7) {
1045                         printf("ERROR: totally incorrect times - maybe word reversed?\n");
1046                 }
1047         }
1048
1049
1050         cli_unlink(&cli, fname);
1051         fnum = cli_open(&cli, fname, 
1052                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1053         cli_close(&cli, fnum);
1054         if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time, 
1055                             &w_time, &size, NULL, NULL)) {
1056                 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
1057         } else {
1058                 if (w_time < 60*60*24*2) {
1059                         printf("write time=%s", ctime(&w_time));
1060                         printf("This system appears to set a initial 0 write time\n");
1061                 }
1062         }
1063
1064         cli_unlink(&cli, fname);
1065
1066
1067         /* check if the server updates the directory modification time
1068            when creating a new file */
1069         if (!cli_mkdir(&cli, dname)) {
1070                 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
1071         }
1072         sleep(3);
1073         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time, 
1074                             &w_time, &size, NULL, NULL)) {
1075                 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
1076         }
1077
1078         fnum = cli_open(&cli, fname2, 
1079                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1080         cli_write(&cli, fnum,  0, (char *)&fnum, 0, sizeof(fnum));
1081         cli_close(&cli, fnum);
1082         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2, 
1083                             &w_time, &size, NULL, NULL)) {
1084                 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
1085         } else {
1086                 if (m_time2 == m_time)
1087                         printf("This system does not update directory modification times\n");
1088         }
1089         cli_unlink(&cli, fname2);
1090         cli_rmdir(&cli, dname);
1091
1092
1093         close_connection(&cli);
1094
1095         printf("trans2 test finished\n");
1096 }
1097
1098
1099 /*
1100   this is a harness for some oplock tests
1101  */
1102 static void run_oplock(int dummy)
1103 {
1104         static struct cli_state cli1, cli2;
1105         char *fname = "\\lockt1.lck";
1106         char *fname2 = "\\lockt2.lck";
1107         int fnum1, fnum2;
1108
1109         printf("starting oplock test\n");
1110
1111         if (!open_connection(&cli1)) {
1112                 return;
1113         }
1114
1115         cli_unlink(&cli1, fname);
1116
1117         cli_sockopt(&cli1, sockops);
1118
1119         cli1.use_oplocks = True;
1120
1121         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
1122         if (fnum1 == -1) {
1123                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
1124                 return;
1125         }
1126
1127         cli1.use_oplocks = False;
1128
1129         cli_unlink(&cli1, fname);
1130         cli_unlink(&cli1, fname);
1131
1132         if (!cli_close(&cli1, fnum1)) {
1133                 printf("close2 failed (%s)\n", cli_errstr(&cli1));
1134                 return;
1135         }
1136
1137         if (!cli_unlink(&cli1, fname)) {
1138                 printf("unlink failed (%s)\n", cli_errstr(&cli1));
1139                 return;
1140         }
1141
1142
1143         close_connection(&cli1);
1144
1145         printf("finished oplock test\n");
1146 }
1147
1148
1149 static void list_fn(file_info *finfo, const char *name)
1150 {
1151         
1152 }
1153
1154 /*
1155   test directory listing speed
1156  */
1157 static void run_dirtest(int dummy)
1158 {
1159         int i;
1160         static struct cli_state cli;
1161         int fnum;
1162         double t1;
1163
1164         printf("starting directory test\n");
1165
1166         if (!open_connection(&cli)) {
1167                 return;
1168         }
1169
1170         cli_sockopt(&cli, sockops);
1171
1172         srandom(0);
1173         for (i=0;i<numops;i++) {
1174                 fstring fname;
1175                 slprintf(fname, sizeof(fname), "%x", random());
1176                 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT, DENY_NONE);
1177                 if (fnum == -1) {
1178                         fprintf(stderr,"Failed to open %s\n", fname);
1179                         return;
1180                 }
1181                 cli_close(&cli, fnum);
1182         }
1183
1184         t1 = end_timer();
1185
1186         printf("Matched %d\n", cli_list(&cli, "a*.*", 0, list_fn));
1187         printf("Matched %d\n", cli_list(&cli, "b*.*", 0, list_fn));
1188         printf("Matched %d\n", cli_list(&cli, "xyzabc", 0, list_fn));
1189
1190         printf("dirtest core %g seconds\n", end_timer() - t1);
1191
1192         srandom(0);
1193         for (i=0;i<numops;i++) {
1194                 fstring fname;
1195                 slprintf(fname, sizeof(fname), "%x", random());
1196                 cli_unlink(&cli, fname);
1197         }
1198
1199         close_connection(&cli);
1200
1201         printf("finished dirtest\n");
1202 }
1203
1204
1205
1206 static double create_procs(void (*fn)(int))
1207 {
1208         int i, status;
1209         volatile int *child_status;
1210         int synccount;
1211         int tries = 8;
1212
1213         start_timer();
1214
1215         synccount = 0;
1216
1217         child_status = (volatile int *)shm_setup(sizeof(int)*nprocs);
1218         if (!child_status) {
1219                 printf("Failed to setup shared memory\n");
1220                 return end_timer();
1221         }
1222
1223         memset((char *)child_status, 0, sizeof(int)*nprocs);
1224
1225         for (i=0;i<nprocs;i++) {
1226                 if (fork() == 0) {
1227                         pid_t mypid = getpid();
1228                         sys_srandom(((int)mypid) ^ ((int)time(NULL)));
1229
1230                         slprintf(myname,sizeof(myname),"CLIENT%d", i);
1231
1232                         while (1) {
1233                                 memset(&current_cli, 0, sizeof(current_cli));
1234                                 if (open_connection(&current_cli)) break;
1235                                 if (tries-- == 0) {
1236                                         printf("pid %d failed to start\n", (int)getpid());
1237                                         _exit(1);
1238                                 }
1239                                 msleep(10);
1240                         }
1241
1242                         child_status[i] = getpid();
1243
1244                         while (child_status[i]) msleep(2);
1245
1246                         fn(i);
1247                         _exit(0);
1248                 }
1249         }
1250
1251         do {
1252                 synccount = 0;
1253                 for (i=0;i<nprocs;i++) {
1254                         if (child_status[i]) synccount++;
1255                 }
1256                 if (synccount == nprocs) break;
1257                 msleep(10);
1258         } while (end_timer() < 30);
1259
1260         if (synccount != nprocs) {
1261                 printf("FAILED TO START %d CLIENTS (started %d)\n", nprocs, synccount);
1262                 return end_timer();
1263         }
1264
1265         /* start the client load */
1266         start_timer();
1267
1268         for (i=0;i<nprocs;i++) {
1269                 child_status[i] = 0;
1270         }
1271
1272         printf("%d clients started\n", nprocs);
1273
1274         for (i=0;i<nprocs;i++) {
1275                 waitpid(0, &status, 0);
1276                 printf("*");
1277         }
1278         printf("\n");
1279         return end_timer();
1280 }
1281
1282
1283 #define FLAG_MULTIPROC 1
1284
1285 static struct {
1286         char *name;
1287         void (*fn)(int);
1288         unsigned flags;
1289 } torture_ops[] = {
1290         {"FDPASS", run_fdpasstest, 0},
1291         {"LOCK1",  run_locktest1,  0},
1292         {"LOCK2",  run_locktest2,  0},
1293         {"LOCK3",  run_locktest3,  0},
1294         {"UNLINK", run_unlinktest, 0},
1295         {"BROWSE", run_browsetest, 0},
1296         {"ATTR",   run_attrtest,   0},
1297         {"TRANS2", run_trans2test, 0},
1298         {"MAXFID", run_maxfidtest, FLAG_MULTIPROC},
1299         {"TORTURE",run_torture,    FLAG_MULTIPROC},
1300         {"RANDOMIPC", run_randomipc, 0},
1301         {"NBW95",  run_nbw95, 0},
1302         {"NBWNT",  run_nbwnt, 0},
1303         {"OPLOCK",  run_oplock, 0},
1304         {"DIR",  run_dirtest, 0},
1305         {NULL, NULL, 0}};
1306
1307
1308 /****************************************************************************
1309 run a specified test or "ALL"
1310 ****************************************************************************/
1311 static void run_test(char *name)
1312 {
1313         int i;
1314         if (strequal(name,"ALL")) {
1315                 for (i=0;torture_ops[i].name;i++) {
1316                         run_test(torture_ops[i].name);
1317                 }
1318         }
1319         
1320         for (i=0;torture_ops[i].name;i++) {
1321                 if (strequal(name, torture_ops[i].name)) {
1322                         start_timer();
1323                         printf("Running %s\n", name);
1324                         if (torture_ops[i].flags & FLAG_MULTIPROC) {
1325                                 create_procs(torture_ops[i].fn);
1326                         } else {
1327                                 torture_ops[i].fn(0);
1328                         }
1329                         printf("%s took %g secs\n\n", name, end_timer());
1330                 }
1331         }
1332 }
1333
1334
1335 static void usage(void)
1336 {
1337         int i;
1338
1339         printf("Usage: smbtorture //server/share <options> TEST1 TEST2 ...\n");
1340
1341         printf("\t-U user%%pass\n");
1342         printf("\t-N numprocs\n");
1343         printf("\t-n my_netbios_name\n");
1344         printf("\t-W workgroup\n");
1345         printf("\t-o num_operations\n");
1346         printf("\t-O socket_options\n");
1347         printf("\t-m maximum protocol\n");
1348         printf("\n\n");
1349
1350         printf("tests are:");
1351         for (i=0;torture_ops[i].name;i++) {
1352                 printf(" %s", torture_ops[i].name);
1353         }
1354         printf("\n");
1355
1356         printf("default test is ALL\n");
1357         
1358         exit(1);
1359 }
1360
1361
1362
1363
1364
1365 /****************************************************************************
1366   main program
1367 ****************************************************************************/
1368  int main(int argc,char *argv[])
1369 {
1370         int opt, i;
1371         char *p;
1372         int gotpass = 0;
1373         extern char *optarg;
1374         extern int optind;
1375         extern FILE *dbf;
1376         static pstring servicesf = CONFIGFILE;
1377
1378         dbf = stdout;
1379
1380         setbuffer(stdout, NULL, 0);
1381
1382         charset_initialise();
1383
1384         lp_load(servicesf,True,False,False);
1385         load_interfaces();
1386
1387         if (argc < 2) {
1388                 usage();
1389         }
1390
1391         for(p = argv[1]; *p; p++)
1392           if(*p == '\\')
1393             *p = '/';
1394  
1395         if (strncmp(argv[1], "//", 2)) {
1396                 usage();
1397         }
1398
1399         fstrcpy(host, &argv[1][2]);
1400         p = strchr(&host[2],'/');
1401         if (!p) {
1402                 usage();
1403         }
1404         *p = 0;
1405         fstrcpy(share, p+1);
1406
1407         get_myname(myname);
1408
1409         if (*username == 0 && getenv("LOGNAME")) {
1410           pstrcpy(username,getenv("LOGNAME"));
1411         }
1412
1413         argc--;
1414         argv++;
1415
1416
1417         fstrcpy(workgroup, lp_workgroup());
1418
1419         while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
1420                 switch (opt) {
1421                 case 'W':
1422                         fstrcpy(workgroup,optarg);
1423                         break;
1424                 case 'm':
1425                         max_protocol = interpret_protocol(optarg, max_protocol);
1426                         break;
1427                 case 'N':
1428                         nprocs = atoi(optarg);
1429                         break;
1430                 case 'o':
1431                         numops = atoi(optarg);
1432                         break;
1433                 case 'O':
1434                         sockops = optarg;
1435                         break;
1436                 case 'n':
1437                         fstrcpy(myname, optarg);
1438                         break;
1439                 case 'U':
1440                         pstrcpy(username,optarg);
1441                         p = strchr(username,'%');
1442                         if (p) {
1443                                 *p = 0;
1444                                 pstrcpy(password, p+1);
1445                                 gotpass = 1;
1446                         }
1447                         break;
1448                 default:
1449                         printf("Unknown option %c (%d)\n", (char)opt, opt);
1450                         usage();
1451                 }
1452         }
1453
1454
1455         while (!gotpass) {
1456                 p = getpass("Password:");
1457                 if (p) {
1458                         pstrcpy(password, p);
1459                         gotpass = 1;
1460                 }
1461         }
1462
1463         printf("host=%s share=%s user=%s myname=%s\n", 
1464                host, share, username, myname);
1465
1466         if (argc == 1) {
1467                 run_test("ALL");
1468         } else {
1469                 for (i=1;i<argc;i++) {
1470                         run_test(argv[i]);
1471                 }
1472         }
1473
1474         return(0);
1475 }