r14519: Put base registration in a seperate file, as well as some
[kai/samba.git] / source4 / torture / torture.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester
4    Copyright (C) Andrew Tridgell 1997-2003
5    Copyright (C) Jelmer Vernooij 2006
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 #include "includes.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "system/time.h"
26 #include "system/wait.h"
27 #include "system/filesys.h"
28 #include "libcli/raw/ioctl.h"
29 #include "libcli/libcli.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/events/events.h"
32 #include "libcli/resolve/resolve.h"
33 #include "auth/credentials/credentials.h"
34 #include "libcli/ldap/ldap_client.h"
35 #include "librpc/gen_ndr/ndr_nbt.h"
36
37 #include "torture/raw/proto.h"
38 #include "torture/smb2/proto.h"
39 #include "torture/rap/proto.h"
40 #include "torture/auth/proto.h"
41 #include "torture/local/proto.h"
42 #include "torture/nbench/proto.h"
43 #include "torture/ldap/proto.h"
44 #include "torture/com/proto.h"
45 #include "torture/nbt/proto.h"
46 #include "torture/libnet/proto.h"
47 #include "torture/torture.h"
48 #include "build.h"
49 #include "dlinklist.h"
50
51 int torture_nprocs=4;
52 _PUBLIC_ int torture_numops=10;
53 _PUBLIC_ int torture_entries=1000;
54 _PUBLIC_ int torture_failures=1;
55 _PUBLIC_ int torture_seed=0;
56 static int procnum; /* records process count number when forking */
57 static struct smbcli_state *current_cli;
58 static BOOL use_oplocks;
59 static BOOL use_level_II_oplocks;
60 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
61
62 _PUBLIC_ BOOL torture_showall = False;
63
64 BOOL torture_open_connection_share(TALLOC_CTX *mem_ctx,
65                                    struct smbcli_state **c, 
66                                    const char *hostname, 
67                                    const char *sharename,
68                                    struct event_context *ev)
69 {
70         NTSTATUS status;
71
72         status = smbcli_full_connection(mem_ctx, c, hostname, 
73                                         sharename, NULL,
74                                         cmdline_credentials, ev);
75         if (!NT_STATUS_IS_OK(status)) {
76                 printf("Failed to open connection - %s\n", nt_errstr(status));
77                 return False;
78         }
79
80         (*c)->transport->options.use_oplocks = use_oplocks;
81         (*c)->transport->options.use_level2_oplocks = use_level_II_oplocks;
82
83         return True;
84 }
85
86 _PUBLIC_ BOOL torture_open_connection(struct smbcli_state **c)
87 {
88         const char *host = lp_parm_string(-1, "torture", "host");
89         const char *share = lp_parm_string(-1, "torture", "share");
90
91         return torture_open_connection_share(NULL, c, host, share, NULL);
92 }
93
94
95
96 _PUBLIC_ BOOL torture_close_connection(struct smbcli_state *c)
97 {
98         BOOL ret = True;
99         if (!c) return True;
100         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
101                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
102                 ret = False;
103         }
104         talloc_free(c);
105         return ret;
106 }
107
108
109 /* check if the server produced the expected error code */
110 _PUBLIC_ BOOL check_error(const char *location, struct smbcli_state *c, 
111                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
112 {
113         NTSTATUS status;
114         
115         status = smbcli_nt_error(c->tree);
116         if (NT_STATUS_IS_DOS(status)) {
117                 int class, num;
118                 class = NT_STATUS_DOS_CLASS(status);
119                 num = NT_STATUS_DOS_CODE(status);
120                 if (eclass != class || ecode != num) {
121                         printf("unexpected error code %s\n", nt_errstr(status));
122                         printf(" expected %s or %s (at %s)\n", 
123                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
124                                nt_errstr(nterr), location);
125                         return False;
126                 }
127         } else {
128                 if (!NT_STATUS_EQUAL(nterr, status)) {
129                         printf("unexpected error code %s\n", nt_errstr(status));
130                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
131                         return False;
132                 }
133         }
134
135         return True;
136 }
137
138
139 static BOOL wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
140 {
141         while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
142                 if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
143         }
144         return True;
145 }
146
147
148 static BOOL rw_torture(struct smbcli_state *c)
149 {
150         const char *lockfname = "\\torture.lck";
151         char *fname;
152         int fnum;
153         int fnum2;
154         pid_t pid2, pid = getpid();
155         int i, j;
156         uint8_t buf[1024];
157         BOOL correct = True;
158
159         fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL, 
160                          DENY_NONE);
161         if (fnum2 == -1)
162                 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
163         if (fnum2 == -1) {
164                 printf("open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
165                 return False;
166         }
167
168
169         for (i=0;i<torture_numops;i++) {
170                 uint_t n = (uint_t)random()%10;
171                 if (i % 10 == 0) {
172                         printf("%d\r", i); fflush(stdout);
173                 }
174                 asprintf(&fname, "\\torture.%u", n);
175
176                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
177                         return False;
178                 }
179
180                 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
181                 if (fnum == -1) {
182                         printf("open failed (%s)\n", smbcli_errstr(c->tree));
183                         correct = False;
184                         break;
185                 }
186
187                 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
188                         printf("write failed (%s)\n", smbcli_errstr(c->tree));
189                         correct = False;
190                 }
191
192                 for (j=0;j<50;j++) {
193                         if (smbcli_write(c->tree, fnum, 0, buf, 
194                                       sizeof(pid)+(j*sizeof(buf)), 
195                                       sizeof(buf)) != sizeof(buf)) {
196                                 printf("write failed (%s)\n", smbcli_errstr(c->tree));
197                                 correct = False;
198                         }
199                 }
200
201                 pid2 = 0;
202
203                 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
204                         printf("read failed (%s)\n", smbcli_errstr(c->tree));
205                         correct = False;
206                 }
207
208                 if (pid2 != pid) {
209                         printf("data corruption!\n");
210                         correct = False;
211                 }
212
213                 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
214                         printf("close failed (%s)\n", smbcli_errstr(c->tree));
215                         correct = False;
216                 }
217
218                 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
219                         printf("unlink failed (%s)\n", smbcli_errstr(c->tree));
220                         correct = False;
221                 }
222
223                 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
224                         printf("unlock failed (%s)\n", smbcli_errstr(c->tree));
225                         correct = False;
226                 }
227                 free(fname);
228         }
229
230         smbcli_close(c->tree, fnum2);
231         smbcli_unlink(c->tree, lockfname);
232
233         printf("%d\n", i);
234
235         return correct;
236 }
237
238 static BOOL run_torture(struct smbcli_state *cli, int dummy)
239 {
240         BOOL ret;
241
242         ret = rw_torture(cli);
243         
244         if (!torture_close_connection(cli)) {
245                 ret = False;
246         }
247
248         return ret;
249 }
250
251
252 /*
253   see how many RPC pipes we can open at once
254 */
255 static BOOL run_pipe_number(void)
256 {
257         struct smbcli_state *cli1;
258         const char *pipe_name = "\\WKSSVC";
259         int fnum;
260         int num_pipes = 0;
261
262         printf("starting pipenumber test\n");
263         if (!torture_open_connection(&cli1)) {
264                 return False;
265         }
266
267         while(1) {
268                 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
269                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
270
271                 if (fnum == -1) {
272                         printf("Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
273                         break;
274                 }
275                 num_pipes++;
276                 printf("%d\r", num_pipes);
277                 fflush(stdout);
278         }
279
280         printf("pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
281         torture_close_connection(cli1);
282         return True;
283 }
284
285
286
287
288 /*
289   open N connections to the server and just hold them open
290   used for testing performance when there are N idle users
291   already connected
292  */
293  static BOOL torture_holdcon(void)
294 {
295         int i;
296         struct smbcli_state **cli;
297         int num_dead = 0;
298
299         printf("Opening %d connections\n", torture_numops);
300         
301         cli = malloc_array_p(struct smbcli_state *, torture_numops);
302
303         for (i=0;i<torture_numops;i++) {
304                 if (!torture_open_connection(&cli[i])) {
305                         return False;
306                 }
307                 printf("opened %d connections\r", i);
308                 fflush(stdout);
309         }
310
311         printf("\nStarting pings\n");
312
313         while (1) {
314                 for (i=0;i<torture_numops;i++) {
315                         NTSTATUS status;
316                         if (cli[i]) {
317                                 status = smbcli_chkpath(cli[i]->tree, "\\");
318                                 if (!NT_STATUS_IS_OK(status)) {
319                                         printf("Connection %d is dead\n", i);
320                                         cli[i] = NULL;
321                                         num_dead++;
322                                 }
323                                 usleep(100);
324                         }
325                 }
326
327                 if (num_dead == torture_numops) {
328                         printf("All connections dead - finishing\n");
329                         break;
330                 }
331
332                 printf(".");
333                 fflush(stdout);
334         }
335
336         return True;
337 }
338
339 /*
340 test how many open files this server supports on the one socket
341 */
342 static BOOL run_maxfidtest(struct smbcli_state *cli, int dummy)
343 {
344 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
345         char *fname;
346         int fnums[0x11000], i;
347         int retries=4, maxfid;
348         BOOL correct = True;
349
350         if (retries <= 0) {
351                 printf("failed to connect\n");
352                 return False;
353         }
354
355         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
356                 printf("Failed to deltree \\maxfid - %s\n",
357                        smbcli_errstr(cli->tree));
358                 return False;
359         }
360         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
361                 printf("Failed to mkdir \\maxfid, error=%s\n", 
362                        smbcli_errstr(cli->tree));
363                 return False;
364         }
365
366         printf("Testing maximum number of open files\n");
367
368         for (i=0; i<0x11000; i++) {
369                 if (i % 1000 == 0) {
370                         asprintf(&fname, "\\maxfid\\fid%d", i/1000);
371                         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
372                                 printf("Failed to mkdir %s, error=%s\n", 
373                                        fname, smbcli_errstr(cli->tree));
374                                 return False;
375                         }
376                         free(fname);
377                 }
378                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
379                 if ((fnums[i] = smbcli_open(cli->tree, fname, 
380                                         O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
381                     -1) {
382                         printf("open of %s failed (%s)\n", 
383                                fname, smbcli_errstr(cli->tree));
384                         printf("maximum fnum is %d\n", i);
385                         break;
386                 }
387                 free(fname);
388                 printf("%6d\r", i);
389         }
390         printf("%6d\n", i);
391         i--;
392
393         maxfid = i;
394
395         printf("cleaning up\n");
396         for (i=0;i<maxfid/2;i++) {
397                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
398                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
399                         printf("Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
400                 }
401                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
402                         printf("unlink of %s failed (%s)\n", 
403                                fname, smbcli_errstr(cli->tree));
404                         correct = False;
405                 }
406                 free(fname);
407
408                 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
409                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
410                         printf("Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
411                 }
412                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
413                         printf("unlink of %s failed (%s)\n", 
414                                fname, smbcli_errstr(cli->tree));
415                         correct = False;
416                 }
417                 free(fname);
418
419                 printf("%6d %6d\r", i, maxfid-i);
420         }
421         printf("%6d\n", 0);
422
423         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
424                 printf("Failed to deltree \\maxfid - %s\n",
425                        smbcli_errstr(cli->tree));
426                 return False;
427         }
428
429         printf("maxfid test finished\n");
430         if (!torture_close_connection(cli)) {
431                 correct = False;
432         }
433         return correct;
434 #undef MAXFID_TEMPLATE
435 }
436
437
438
439 /*
440   sees what IOCTLs are supported
441  */
442 BOOL torture_ioctl_test(void)
443 {
444         struct smbcli_state *cli;
445         uint16_t device, function;
446         int fnum;
447         const char *fname = "\\ioctl.dat";
448         NTSTATUS status;
449         union smb_ioctl parms;
450         TALLOC_CTX *mem_ctx;
451
452         if (!torture_open_connection(&cli)) {
453                 return False;
454         }
455
456         mem_ctx = talloc_init("ioctl_test");
457
458         printf("starting ioctl test\n");
459
460         smbcli_unlink(cli->tree, fname);
461
462         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
463         if (fnum == -1) {
464                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
465                 return False;
466         }
467
468         parms.ioctl.level = RAW_IOCTL_IOCTL;
469         parms.ioctl.in.file.fnum = fnum;
470         parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
471         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
472         printf("ioctl job info: %s\n", smbcli_errstr(cli->tree));
473
474         for (device=0;device<0x100;device++) {
475                 printf("testing device=0x%x\n", device);
476                 for (function=0;function<0x100;function++) {
477                         parms.ioctl.in.request = (device << 16) | function;
478                         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
479
480                         if (NT_STATUS_IS_OK(status)) {
481                                 printf("ioctl device=0x%x function=0x%x OK : %d bytes\n", 
482                                         device, function, (int)parms.ioctl.out.blob.length);
483                         }
484                 }
485         }
486
487         if (!torture_close_connection(cli)) {
488                 return False;
489         }
490
491         return True;
492 }
493
494
495 static void sigcont(int sig)
496 {
497 }
498
499 double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result)
500 {
501         int i, status;
502         volatile pid_t *child_status;
503         volatile BOOL *child_status_out;
504         int synccount;
505         int tries = 8;
506         double start_time_limit = 10 + (torture_nprocs * 1.5);
507         char **unc_list = NULL;
508         const char *p;
509         int num_unc_names = 0;
510         struct timeval tv;
511
512         *result = True;
513
514         synccount = 0;
515
516         signal(SIGCONT, sigcont);
517
518         child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
519         if (!child_status) {
520                 printf("Failed to setup shared memory\n");
521                 return -1;
522         }
523
524         child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*torture_nprocs);
525         if (!child_status_out) {
526                 printf("Failed to setup result status shared memory\n");
527                 return -1;
528         }
529
530         p = lp_parm_string(-1, "torture", "unclist");
531         if (p) {
532                 unc_list = file_lines_load(p, &num_unc_names, NULL);
533                 if (!unc_list || num_unc_names <= 0) {
534                         printf("Failed to load unc names list from '%s'\n", p);
535                         exit(1);
536                 }
537         }
538
539         for (i = 0; i < torture_nprocs; i++) {
540                 child_status[i] = 0;
541                 child_status_out[i] = True;
542         }
543
544         tv = timeval_current();
545
546         for (i=0;i<torture_nprocs;i++) {
547                 procnum = i;
548                 if (fork() == 0) {
549                         char *myname;
550                         char *hostname=NULL, *sharename;
551
552                         pid_t mypid = getpid();
553                         srandom(((int)mypid) ^ ((int)time(NULL)));
554
555                         asprintf(&myname, "CLIENT%d", i);
556                         lp_set_cmdline("netbios name", myname);
557                         free(myname);
558
559
560                         if (unc_list) {
561                                 if (!smbcli_parse_unc(unc_list[i % num_unc_names],
562                                                       NULL, &hostname, &sharename)) {
563                                         printf("Failed to parse UNC name %s\n",
564                                                unc_list[i % num_unc_names]);
565                                         exit(1);
566                                 }
567                         }
568
569                         while (1) {
570                                 if (hostname) {
571                                         if (torture_open_connection_share(NULL,
572                                                                           &current_cli,
573                                                                           hostname, 
574                                                                           sharename,
575                                                                           NULL)) {
576                                                 break;
577                                         }
578                                 } else if (torture_open_connection(&current_cli)) {
579                                                 break;
580                                 }
581                                 if (tries-- == 0) {
582                                         printf("pid %d failed to start\n", (int)getpid());
583                                         _exit(1);
584                                 }
585                                 msleep(100);    
586                         }
587
588                         child_status[i] = getpid();
589
590                         pause();
591
592                         if (child_status[i]) {
593                                 printf("Child %d failed to start!\n", i);
594                                 child_status_out[i] = 1;
595                                 _exit(1);
596                         }
597
598                         child_status_out[i] = fn(current_cli, i);
599                         _exit(0);
600                 }
601         }
602
603         do {
604                 synccount = 0;
605                 for (i=0;i<torture_nprocs;i++) {
606                         if (child_status[i]) synccount++;
607                 }
608                 if (synccount == torture_nprocs) break;
609                 msleep(100);
610         } while (timeval_elapsed(&tv) < start_time_limit);
611
612         if (synccount != torture_nprocs) {
613                 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
614                 *result = False;
615                 return timeval_elapsed(&tv);
616         }
617
618         printf("Starting %d clients\n", torture_nprocs);
619
620         /* start the client load */
621         tv = timeval_current();
622         for (i=0;i<torture_nprocs;i++) {
623                 child_status[i] = 0;
624         }
625
626         printf("%d clients started\n", torture_nprocs);
627
628         kill(0, SIGCONT);
629
630         for (i=0;i<torture_nprocs;i++) {
631                 int ret;
632                 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
633                 if (ret == -1 || WEXITSTATUS(status) != 0) {
634                         *result = False;
635                 }
636         }
637
638         printf("\n");
639         
640         for (i=0;i<torture_nprocs;i++) {
641                 if (!child_status_out[i]) {
642                         *result = False;
643                 }
644         }
645         return timeval_elapsed(&tv);
646 }
647
648 #define FLAG_MULTIPROC 1
649
650 static struct {
651         const char *name;
652         BOOL (*fn)(void);
653         BOOL (*multi_fn)(struct smbcli_state *, int );
654 } builtin_torture_ops[] = {
655         /* benchmarking tests */
656         {"BENCH-HOLDCON",  torture_holdcon, 0},
657         {"BENCH-NBENCH",  torture_nbench, 0},
658         {"BENCH-TORTURE", NULL, run_torture},
659         {"BENCH-NBT",     torture_bench_nbt, 0},
660         {"BENCH-WINS",    torture_bench_wins, 0},
661         {"BENCH-CLDAP",   torture_bench_cldap, 0},
662
663         /* RAW smb tests */
664         {"RAW-QFSINFO", torture_raw_qfsinfo, 0},
665         {"RAW-QFILEINFO", torture_raw_qfileinfo, 0},
666         {"RAW-SFILEINFO", torture_raw_sfileinfo, 0},
667         {"RAW-SFILEINFO-BUG", torture_raw_sfileinfo_bug, 0},
668         {"RAW-SEARCH", torture_raw_search, 0},
669         {"RAW-CLOSE", torture_raw_close, 0},
670         {"RAW-OPEN", torture_raw_open, 0},
671         {"RAW-MKDIR", torture_raw_mkdir, 0},
672         {"RAW-OPLOCK", torture_raw_oplock, 0},
673         {"RAW-NOTIFY", torture_raw_notify, 0},
674         {"RAW-MUX", torture_raw_mux, 0},
675         {"RAW-IOCTL", torture_raw_ioctl, 0},
676         {"RAW-CHKPATH", torture_raw_chkpath, 0},
677         {"RAW-UNLINK", torture_raw_unlink, 0},
678         {"RAW-READ", torture_raw_read, 0},
679         {"RAW-WRITE", torture_raw_write, 0},
680         {"RAW-LOCK", torture_raw_lock, 0},
681         {"RAW-CONTEXT", torture_raw_context, 0},
682         {"RAW-RENAME", torture_raw_rename, 0},
683         {"RAW-SEEK", torture_raw_seek, 0},
684         {"RAW-EAS", torture_raw_eas, 0},
685         {"RAW-EAMAX", torture_max_eas, 0},
686         {"RAW-STREAMS", torture_raw_streams, 0},
687         {"RAW-ACLS", torture_raw_acls, 0},
688         {"RAW-RAP", torture_raw_rap, 0},
689         {"RAW-COMPOSITE", torture_raw_composite, 0},
690
691         /* SMB2 tests */
692         {"SMB2-CONNECT", torture_smb2_connect, 0},
693         {"SMB2-SCAN", torture_smb2_scan, 0},
694         {"SMB2-SCANGETINFO", torture_smb2_getinfo_scan, 0},
695         {"SMB2-SCANSETINFO", torture_smb2_setinfo_scan, 0},
696         {"SMB2-SCANFIND", torture_smb2_find_scan, 0},
697         {"SMB2-GETINFO", torture_smb2_getinfo, 0},
698         {"SMB2-SETINFO", torture_smb2_setinfo, 0},
699         {"SMB2-FIND", torture_smb2_find, 0},
700
701         /* protocol scanners */
702         {"SCAN-MAXFID", NULL, run_maxfidtest},
703         {"SCAN-PIPE_NUMBER", run_pipe_number, 0},
704         {"SCAN-IOCTL",  torture_ioctl_test, 0},
705         {"SCAN-RAP",  torture_rap_scan, 0},
706
707         /* local (no server) testers */
708         {"LOCAL-NTLMSSP", torture_ntlmssp_self_check, 0},
709         {"LOCAL-ICONV", torture_local_iconv, 0},
710         {"LOCAL-TALLOC", torture_local_talloc, 0},
711         {"LOCAL-MESSAGING", torture_local_messaging, 0},
712         {"LOCAL-IRPC",  torture_local_irpc, 0},
713         {"LOCAL-BINDING", torture_local_binding_string, 0},
714         {"LOCAL-STRLIST", torture_local_util_strlist, 0},
715         {"LOCAL-FILE", torture_local_util_file, 0},
716         {"LOCAL-IDTREE", torture_local_idtree, 0},
717         {"LOCAL-SOCKET", torture_local_socket, 0},
718         {"LOCAL-PAC", torture_pac, 0},
719         {"LOCAL-REGISTRY", torture_registry, 0},
720         {"LOCAL-RESOLVE", torture_local_resolve, 0},
721         {"LOCAL-SDDL", torture_local_sddl, 0},
722         {"LOCAL-NDR", torture_local_ndr, 0},
723
724         /* ldap testers */
725         {"LDAP-BASIC", torture_ldap_basic, 0},
726         {"LDAP-CLDAP", torture_cldap, 0},
727
728         /* nbt tests */
729         {"NBT-REGISTER", torture_nbt_register, 0},
730         {"NBT-WINS", torture_nbt_wins, 0},
731         {"NBT-DGRAM", torture_nbt_dgram, 0},
732         {"NBT-BROWSE", torture_nbt_browse, 0},
733         {"NBT-WINSREPLICATION-SIMPLE", torture_nbt_winsreplication_simple, 0},
734         {"NBT-WINSREPLICATION-REPLICA", torture_nbt_winsreplication_replica, 0},
735         {"NBT-WINSREPLICATION-OWNED", torture_nbt_winsreplication_owned, 0},
736         
737         /* libnet tests */
738         {"NET-USERINFO", torture_userinfo, 0},
739         {"NET-USERADD", torture_useradd, 0},
740         {"NET-USERDEL", torture_userdel, 0},
741         {"NET-USERMOD", torture_usermod, 0},
742         {"NET-DOMOPEN", torture_domainopen, 0},
743         {"NET-API-LOOKUP", torture_lookup, 0},
744         {"NET-API-LOOKUPHOST", torture_lookup_host, 0},
745         {"NET-API-LOOKUPPDC", torture_lookup_pdc, 0},
746         {"NET-API-CREATEUSER", torture_createuser, 0},
747         {"NET-API-RPCCONNECT", torture_rpc_connect, 0},
748         {"NET-API-LISTSHARES", torture_listshares, 0},
749         {"NET-API-DELSHARE", torture_delshare, 0},
750
751         {NULL, NULL, 0}};
752
753 static void register_builtin_ops(void)
754 {
755         int i;
756         for (i = 0; builtin_torture_ops[i].name; i++) {
757                 register_torture_op(builtin_torture_ops[i].name, 
758                                                         builtin_torture_ops[i].fn, 
759                                                         builtin_torture_ops[i].multi_fn);
760         }
761 }
762
763
764 static struct torture_op {
765         const char *name;
766         BOOL (*fn)(void);
767         BOOL (*multi_fn)(struct smbcli_state *, int );
768         struct torture_op *prev, *next;
769 }* torture_ops = NULL;;
770
771 static struct torture_op *find_torture_op(const char *name)
772 {
773         struct torture_op *o;
774         for (o = torture_ops; o; o = o->next) {
775                 if (strcmp(name, o->name) == 0)
776                         return o;
777         }
778
779         return NULL;
780 }
781
782 _PUBLIC_ NTSTATUS register_torture_op(const char *name, BOOL (*fn)(void), BOOL (*multi_fn)(struct smbcli_state *, int ))
783 {
784         struct torture_op *op;
785         
786         /* Check for duplicates */
787         if (find_torture_op(name) != NULL) {
788                 DEBUG(0,("There already is a torture op registered with the name %s!\n", name));
789                 return NT_STATUS_OBJECT_NAME_COLLISION;
790         }
791
792         op = talloc(talloc_autofree_context(), struct torture_op);
793
794         op->name = talloc_strdup(op, name);
795         op->fn = fn;
796         op->multi_fn = multi_fn;
797
798         DLIST_ADD(torture_ops, op);
799         
800         return NT_STATUS_OK;
801 }
802
803 /****************************************************************************
804 run a specified test or "ALL"
805 ****************************************************************************/
806 static BOOL run_test(const char *name)
807 {
808         BOOL ret = True;
809         struct torture_op *o;
810         BOOL matched = False;
811
812         if (strequal(name,"ALL")) {
813                 for (o = torture_ops; o; o = o->next) {
814                         if (!run_test(o->name)) {
815                                 ret = False;
816                         }
817                 }
818                 return ret;
819         }
820
821         for (o = torture_ops; o; o = o->next) {
822                 if (gen_fnmatch(name, o->name) == 0) {
823                         double t;
824                         matched = True;
825                         init_iconv();
826                         printf("Running %s\n", o->name);
827                         if (o->multi_fn) {
828                                 BOOL result = False;
829                                 t = torture_create_procs(o->multi_fn, 
830                                                          &result);
831                                 if (!result) { 
832                                         ret = False;
833                                         printf("TEST %s FAILED!\n", o->name);
834                                 }
835                                          
836                         } else {
837                                 struct timeval tv = timeval_current();
838                                 if (!o->fn()) {
839                                         ret = False;
840                                         printf("TEST %s FAILED!\n", o->name);
841                                 }
842                                 t = timeval_elapsed(&tv);
843                         }
844                         printf("%s took %g secs\n\n", o->name, t);
845                 }
846         }
847
848         if (!matched) {
849                 printf("Unknown torture operation '%s'\n", name);
850         }
851
852         return ret;
853 }
854
855
856 static void parse_dns(const char *dns)
857 {
858         char *userdn, *basedn, *secret;
859         char *p, *d;
860
861         /* retrievieng the userdn */
862         p = strchr_m(dns, '#');
863         if (!p) {
864                 lp_set_cmdline("torture:ldap_userdn", "");
865                 lp_set_cmdline("torture:ldap_basedn", "");
866                 lp_set_cmdline("torture:ldap_secret", "");
867                 return;
868         }
869         userdn = strndup(dns, p - dns);
870         lp_set_cmdline("torture:ldap_userdn", userdn);
871
872         /* retrieve the basedn */
873         d = p + 1;
874         p = strchr_m(d, '#');
875         if (!p) {
876                 lp_set_cmdline("torture:ldap_basedn", "");
877                 lp_set_cmdline("torture:ldap_secret", "");
878                 return;
879         }
880         basedn = strndup(d, p - d);
881         lp_set_cmdline("torture:ldap_basedn", basedn);
882
883         /* retrieve the secret */
884         p = p + 1;
885         if (!p) {
886                 lp_set_cmdline("torture:ldap_secret", "");
887                 return;
888         }
889         secret = strdup(p);
890         lp_set_cmdline("torture:ldap_secret", secret);
891
892         printf ("%s - %s - %s\n", userdn, basedn, secret);
893
894 }
895
896 static void usage(poptContext pc)
897 {
898         struct torture_op *o;
899         int i;
900
901         poptPrintUsage(pc, stdout, 0);
902         printf("\n");
903
904         printf("The binding format is:\n\n");
905
906         printf("  TRANSPORT:host[flags]\n\n");
907
908         printf("  where TRANSPORT is either ncacn_np for SMB or ncacn_ip_tcp for RPC/TCP\n\n");
909
910         printf("  'host' is an IP or hostname or netbios name. If the binding string\n");
911         printf("  identifies the server side of an endpoint, 'host' may be an empty\n");
912         printf("  string.\n\n");
913
914         printf("  'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
915         printf("  a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
916         printf("  will be auto-determined.\n\n");
917
918         printf("  other recognised flags are:\n\n");
919
920         printf("    sign : enable ntlmssp signing\n");
921         printf("    seal : enable ntlmssp sealing\n");
922         printf("    connect : enable rpc connect level auth (auth, but no sign or seal)\n");
923         printf("    validate: enable the NDR validator\n");
924         printf("    print: enable debugging of the packets\n");
925         printf("    bigendian: use bigendian RPC\n");
926         printf("    padcheck: check reply data for non-zero pad bytes\n\n");
927
928         printf("  For example, these all connect to the samr pipe:\n\n");
929
930         printf("    ncacn_np:myserver\n");
931         printf("    ncacn_np:myserver[samr]\n");
932         printf("    ncacn_np:myserver[\\pipe\\samr]\n");
933         printf("    ncacn_np:myserver[/pipe/samr]\n");
934         printf("    ncacn_np:myserver[samr,sign,print]\n");
935         printf("    ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
936         printf("    ncacn_np:myserver[/pipe/samr,seal,validate]\n");
937         printf("    ncacn_np:\n");
938         printf("    ncacn_np:[/pipe/samr]\n\n");
939
940         printf("    ncacn_ip_tcp:myserver\n");
941         printf("    ncacn_ip_tcp:myserver[1024]\n");
942         printf("    ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
943
944         printf("The unc format is:\n\n");
945
946         printf("    //server/share\n\n");
947
948         printf("tests are:\n");
949
950         i = 0;
951         for (o = torture_ops; o; o = o->next) {
952                 if (i + strlen(o->name) >= MAX_COLS) {
953                         printf("\n");
954                         i = 0;
955                 }
956                 i+=printf("%s ", o->name);
957         }
958         printf("\n\n");
959
960         printf("default test is ALL\n");
961
962         exit(1);
963 }
964
965 static BOOL is_binding_string(const char *binding_string)
966 {
967         TALLOC_CTX *mem_ctx = talloc_init("is_binding_string");
968         struct dcerpc_binding *binding_struct;
969         NTSTATUS status;
970         
971         status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
972
973         talloc_free(mem_ctx);
974         return NT_STATUS_IS_OK(status);
975 }
976
977 static void max_runtime_handler(int sig)
978 {
979         DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
980         exit(1);
981 }
982
983 /****************************************************************************
984   main program
985 ****************************************************************************/
986  int main(int argc,char *argv[])
987 {
988         int opt, i;
989         char *p;
990         BOOL correct = True;
991         int max_runtime=0;
992         int argc_new;
993         char **argv_new;
994         poptContext pc;
995         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
996             OPT_DANGEROUS,OPT_SMB_PORTS};
997         init_module_fn static_init[] = STATIC_smbtorture_MODULES;
998         init_module_fn *shared_init = load_samba_modules(NULL, "torture");
999         
1000         struct poptOption long_options[] = {
1001                 POPT_AUTOHELP
1002                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
1003                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "seed",         NULL},
1004                 {"num-progs",     0, POPT_ARG_INT,  &torture_nprocs,    0,      "num progs",    NULL},
1005                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
1006                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
1007                 {"use-oplocks", 'L', POPT_ARG_NONE, &use_oplocks,       0,      "use oplocks",  NULL},
1008                 {"show-all",      0, POPT_ARG_NONE, &torture_showall,   0,      "show all",     NULL},
1009                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "loadfile",     NULL},
1010                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
1011                 {"timelimit",   't', POPT_ARG_STRING,   NULL,   OPT_TIMELIMIT,  "timelimit",    NULL},
1012                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
1013                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
1014                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,  "dangerous",    NULL},
1015                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
1016                  "set maximum time for smbtorture to live", "seconds"},
1017                 POPT_COMMON_SAMBA
1018                 POPT_COMMON_CONNECTION
1019                 POPT_COMMON_CREDENTIALS
1020                 POPT_COMMON_VERSION
1021                 POPT_TABLEEND
1022         };
1023
1024 #ifdef HAVE_SETBUFFER
1025         setbuffer(stdout, NULL, 0);
1026 #endif
1027
1028         register_builtin_ops();
1029
1030         run_init_functions(static_init);
1031         run_init_functions(shared_init);
1032
1033         talloc_free(shared_init);
1034
1035         /* we are never interested in SIGPIPE */
1036         BlockSignals(True,SIGPIPE);
1037
1038         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
1039                             POPT_CONTEXT_KEEP_FIRST);
1040
1041         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
1042
1043         while((opt = poptGetNextOpt(pc)) != -1) {
1044                 switch (opt) {
1045                 case OPT_LOADFILE:
1046                         lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
1047                         break;
1048                 case OPT_UNCLIST:
1049                         lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
1050                         break;
1051                 case OPT_TIMELIMIT:
1052                         lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
1053                         break;
1054                 case OPT_DNS:
1055                         parse_dns(poptGetOptArg(pc));
1056                         break;
1057                 case OPT_DANGEROUS:
1058                         lp_set_cmdline("torture:dangerous", "Yes");
1059                         break;
1060                 case OPT_SMB_PORTS:
1061                         lp_set_cmdline("smb ports", poptGetOptArg(pc));
1062                         break;
1063                 default:
1064                         d_printf("Invalid option %s: %s\n", 
1065                                  poptBadOption(pc, 0), poptStrerror(opt));
1066                         usage(pc);
1067                         exit(1);
1068                 }
1069         }
1070
1071         if (max_runtime) {
1072                 /* this will only work if nobody else uses alarm(),
1073                    which means it won't work for some tests, but we
1074                    can't use the event context method we use for smbd
1075                    as so many tests create their own event
1076                    context. This will at least catch most cases. */
1077                 signal(SIGALRM, max_runtime_handler);
1078                 alarm(max_runtime);
1079         }
1080
1081         ldb_global_init();
1082
1083         if (torture_seed == 0) {
1084                 torture_seed = time(NULL);
1085         } 
1086         printf("Using seed %d\n", torture_seed);
1087         srandom(torture_seed);
1088
1089         argv_new = discard_const_p(char *, poptGetArgs(pc));
1090
1091         argc_new = argc;
1092         for (i=0; i<argc; i++) {
1093                 if (argv_new[i] == NULL) {
1094                         argc_new = i;
1095                         break;
1096                 }
1097         }
1098
1099         if (argc_new < 3) {
1100                 usage(pc);
1101                 exit(1);
1102         }
1103
1104         for(p = argv_new[1]; *p; p++) {
1105                 if(*p == '\\')
1106                         *p = '/';
1107         }
1108
1109         /* see if its a RPC transport specifier */
1110         if (is_binding_string(argv_new[1])) {
1111                 lp_set_cmdline("torture:binding", argv_new[1]);
1112         } else {
1113                 char *binding = NULL;
1114                 char *host = NULL, *share = NULL;
1115
1116                 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
1117                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
1118                         usage(pc);
1119                 }
1120
1121                 lp_set_cmdline("torture:host", host);
1122                 lp_set_cmdline("torture:share", share);
1123                 asprintf(&binding, "ncacn_np:%s", host);
1124                 lp_set_cmdline("torture:binding", binding);
1125         }
1126
1127         if (argc_new == 0) {
1128                 printf("You must specify a test to run, or 'ALL'\n");
1129         } else {
1130                 for (i=2;i<argc_new;i++) {
1131                         if (!run_test(argv_new[i])) {
1132                                 correct = False;
1133                         }
1134                 }
1135         }
1136
1137         if (correct) {
1138                 return(0);
1139         } else {
1140                 return(1);
1141         }
1142 }