r23792: convert Samba4 to GPLv3
[metze/samba/wip.git] / source4 / torture / smbtorture.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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/filesys.h"
26 #include "system/readline.h"
27 #include "lib/smbreadline/smbreadline.h"
28 #include "libcli/libcli.h"
29 #include "lib/ldb/include/ldb.h"
30 #include "lib/events/events.h"
31 #include "dynconfig.h"
32
33 #include "torture/torture.h"
34 #include "build.h"
35 #include "lib/util/dlinklist.h"
36 #include "librpc/rpc/dcerpc.h"
37
38 static bool run_matching(struct torture_context *torture,
39                                                  const char *prefix, 
40                                                  const char *expr,
41                                                  struct torture_suite *suite,
42                                                  bool *matched)
43 {
44         bool ret = true;
45
46         if (suite == NULL) {
47                 struct torture_suite *o;
48
49                 for (o = torture_root->children; o; o = o->next) {
50                         if (gen_fnmatch(expr, o->name) == 0) {
51                                 *matched = true;
52                                 init_iconv();
53                                 ret &= torture_run_suite(torture, o);
54                                 continue;
55                         }
56
57                         ret &= run_matching(torture, o->name, expr, o, matched);
58                 }
59         } else {
60                 char *name;
61                 struct torture_suite *c;
62                 struct torture_tcase *t;
63
64                 for (c = suite->children; c; c = c->next) {
65                         asprintf(&name, "%s-%s", prefix, c->name);
66
67                         if (gen_fnmatch(expr, name) == 0) {
68                                 *matched = true;
69                                 init_iconv();
70                                 torture->active_testname = talloc_strdup(torture, prefix);
71                                 ret &= torture_run_suite(torture, c);
72                                 free(name);
73                                 continue;
74                         }
75                         
76                         ret &= run_matching(torture, name, expr, c, matched);
77
78                         free(name);
79                 }
80
81                 for (t = suite->testcases; t; t = t->next) {
82                         asprintf(&name, "%s-%s", prefix, t->name);
83                         if (gen_fnmatch(expr, name) == 0) {
84                                 *matched = true;
85                                 init_iconv();
86                                 torture->active_testname = talloc_strdup(torture, prefix);
87                                 ret &= torture_run_tcase(torture, t);
88                                 talloc_free(torture->active_testname);
89                         }
90                         free(name);
91                 }
92         }
93
94         return ret;
95 }
96
97 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
98
99 /****************************************************************************
100 run a specified test or "ALL"
101 ****************************************************************************/
102 static bool run_test(struct torture_context *torture, const char *name)
103 {
104         bool ret = true;
105         bool matched = false;
106         struct torture_suite *o;
107
108         if (strequal(name, "ALL")) {
109                 for (o = torture_root->children; o; o = o->next) {
110                         ret &= torture_run_suite(torture, o);
111                 }
112                 return ret;
113         }
114
115         ret = run_matching(torture, NULL, name, NULL, &matched);
116
117         if (!matched) {
118                 printf("Unknown torture operation '%s'\n", name);
119                 return false;
120         }
121
122         return ret;
123 }
124
125 static void parse_dns(const char *dns)
126 {
127         char *userdn, *basedn, *secret;
128         char *p, *d;
129
130         /* retrievieng the userdn */
131         p = strchr_m(dns, '#');
132         if (!p) {
133                 lp_set_cmdline("torture:ldap_userdn", "");
134                 lp_set_cmdline("torture:ldap_basedn", "");
135                 lp_set_cmdline("torture:ldap_secret", "");
136                 return;
137         }
138         userdn = strndup(dns, p - dns);
139         lp_set_cmdline("torture:ldap_userdn", userdn);
140
141         /* retrieve the basedn */
142         d = p + 1;
143         p = strchr_m(d, '#');
144         if (!p) {
145                 lp_set_cmdline("torture:ldap_basedn", "");
146                 lp_set_cmdline("torture:ldap_secret", "");
147                 return;
148         }
149         basedn = strndup(d, p - d);
150         lp_set_cmdline("torture:ldap_basedn", basedn);
151
152         /* retrieve the secret */
153         p = p + 1;
154         if (!p) {
155                 lp_set_cmdline("torture:ldap_secret", "");
156                 return;
157         }
158         secret = strdup(p);
159         lp_set_cmdline("torture:ldap_secret", secret);
160
161         printf ("%s - %s - %s\n", userdn, basedn, secret);
162
163 }
164
165 static void print_test_list(void)
166 {
167         struct torture_suite *o;
168         struct torture_suite *s;
169         struct torture_tcase *t;
170
171         for (o = torture_root->children; o; o = o->next) {
172                 for (s = o->children; s; s = s->next) {
173                         printf("%s-%s\n", o->name, s->name);
174                 }
175
176                 for (t = o->testcases; t; t = t->next) {
177                         printf("%s-%s\n", o->name, t->name);
178                 }
179         }
180 }
181
182 static void usage(poptContext pc)
183 {
184         struct torture_suite *o;
185         struct torture_suite *s;
186         struct torture_tcase *t;
187         int i;
188
189         poptPrintUsage(pc, stdout, 0);
190         printf("\n");
191
192         printf("The binding format is:\n\n");
193
194         printf("  TRANSPORT:host[flags]\n\n");
195
196         printf("  where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
197         printf("  or ncalrpc for local connections.\n\n");
198
199         printf("  'host' is an IP or hostname or netbios name. If the binding string\n");
200         printf("  identifies the server side of an endpoint, 'host' may be an empty\n");
201         printf("  string.\n\n");
202
203         printf("  'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
204         printf("  a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
205         printf("  will be auto-determined.\n\n");
206
207         printf("  other recognised flags are:\n\n");
208
209         printf("    sign : enable ntlmssp signing\n");
210         printf("    seal : enable ntlmssp sealing\n");
211         printf("    connect : enable rpc connect level auth (auth, but no sign or seal)\n");
212         printf("    validate: enable the NDR validator\n");
213         printf("    print: enable debugging of the packets\n");
214         printf("    bigendian: use bigendian RPC\n");
215         printf("    padcheck: check reply data for non-zero pad bytes\n\n");
216
217         printf("  For example, these all connect to the samr pipe:\n\n");
218
219         printf("    ncacn_np:myserver\n");
220         printf("    ncacn_np:myserver[samr]\n");
221         printf("    ncacn_np:myserver[\\pipe\\samr]\n");
222         printf("    ncacn_np:myserver[/pipe/samr]\n");
223         printf("    ncacn_np:myserver[samr,sign,print]\n");
224         printf("    ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
225         printf("    ncacn_np:myserver[/pipe/samr,seal,validate]\n");
226         printf("    ncacn_np:\n");
227         printf("    ncacn_np:[/pipe/samr]\n\n");
228
229         printf("    ncacn_ip_tcp:myserver\n");
230         printf("    ncacn_ip_tcp:myserver[1024]\n");
231         printf("    ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
232
233         printf("    ncalrpc:\n\n");
234
235         printf("The UNC format is:\n\n");
236
237         printf("  //server/share\n\n");
238
239         printf("Tests are:");
240
241         for (o = torture_root->children; o; o = o->next) {
242                 printf("\n%s (%s):\n  ", o->description, o->name);
243
244                 i = 0;
245                 for (s = o->children; s; s = s->next) {
246                         if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
247                                 printf("\n  ");
248                                 i = 0;
249                         }
250                         i+=printf("%s-%s ", o->name, s->name);
251                 }
252
253                 for (t = o->testcases; t; t = t->next) {
254                         if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
255                                 printf("\n  ");
256                                 i = 0;
257                         }
258                         i+=printf("%s-%s ", o->name, t->name);
259                 }
260
261                 if (i) printf("\n");
262         }
263
264         printf("\nThe default test is ALL.\n");
265
266         exit(1);
267 }
268
269 static void max_runtime_handler(int sig)
270 {
271         DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
272         exit(1);
273 }
274
275 struct timeval last_suite_started;
276
277 static void simple_suite_start(struct torture_context *ctx,
278                                                            struct torture_suite *suite)
279 {
280         last_suite_started = timeval_current();
281         printf("Running %s\n", suite->name);
282 }
283
284 static void simple_suite_finish(struct torture_context *ctx,
285                                                            struct torture_suite *suite)
286 {
287
288         printf("%s took %g secs\n\n", suite->name, 
289                    timeval_elapsed(&last_suite_started));
290 }
291
292 static void simple_test_result (struct torture_context *context, 
293                                                                 enum torture_result res, const char *reason)
294 {
295         switch (res) {
296         case TORTURE_OK:
297                 if (reason)
298                         printf("OK: %s\n", reason);
299                 break;
300         case TORTURE_FAIL:
301                 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
302                 break;
303         case TORTURE_ERROR:
304                 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason); 
305                 break;
306         case TORTURE_SKIP:
307                 printf("SKIP: %s - %s\n", context->active_test->name, reason);
308                 break;
309         }
310 }
311
312 static void simple_comment (struct torture_context *test, 
313                                                         const char *comment)
314 {
315         printf("%s", comment);
316 }
317
318 static void simple_warning(struct torture_context *test, 
319                                                    const char *comment)
320 {
321         fprintf(stderr, "WARNING: %s\n", comment);
322 }
323
324 const static struct torture_ui_ops std_ui_ops = {
325         .comment = simple_comment,
326         .warning = simple_warning,
327         .suite_start = simple_suite_start,
328         .suite_finish = simple_suite_finish,
329         .test_result = simple_test_result
330 };
331
332 static void subunit_init(struct torture_context *ctx) 
333 {
334         /* FIXME: register segv and bus handler */
335 }
336
337 static void subunit_suite_start(struct torture_context *ctx,
338                                                            struct torture_suite *suite)
339 {
340         printf("testsuite: %s\n", suite->name);
341 }
342
343 static void subunit_test_start (struct torture_context *ctx, 
344                                                             struct torture_tcase *tcase,
345                                                                 struct torture_test *test)
346 {
347         printf("test: %s\n", test->name);
348 }
349
350 static void subunit_test_result (struct torture_context *context, 
351                                                                  enum torture_result res, const char *reason)
352 {
353         switch (res) {
354         case TORTURE_OK:
355                 printf("success: %s", context->active_test->name);
356                 break;
357         case TORTURE_FAIL:
358                 printf("failure: %s", context->active_test->name);
359                 break;
360         case TORTURE_ERROR:
361                 printf("error: %s", context->active_test->name);
362                 break;
363         case TORTURE_SKIP:
364                 printf("skip: %s", context->active_test->name);
365                 break;
366         }
367         if (reason)
368                 printf(" [\n%s\n]", reason);
369         printf("\n");
370 }
371
372 static void subunit_comment (struct torture_context *test, 
373                                                          const char *comment)
374 {
375         fprintf(stderr, "%s", comment);
376 }
377
378 const static struct torture_ui_ops subunit_ui_ops = {
379         .init = subunit_init,
380         .comment = subunit_comment,
381         .test_start = subunit_test_start,
382         .test_result = subunit_test_result,
383         .suite_start = subunit_suite_start
384 };
385
386 static void harness_test_start (struct torture_context *ctx, 
387                                                             struct torture_tcase *tcase,
388                                                                 struct torture_test *test)
389 {
390 }
391
392 static void harness_test_result (struct torture_context *context, 
393                                                                  enum torture_result res, const char *reason)
394 {
395         switch (res) {
396         case TORTURE_OK:
397                 printf("ok %s - %s\n", context->active_test->name, reason);
398                 break;
399         case TORTURE_FAIL:
400         case TORTURE_ERROR:
401                 printf("not ok %s - %s\n", context->active_test->name, reason);
402                 break;
403         case TORTURE_SKIP:
404                 printf("skip %s - %s\n", context->active_test->name, reason);
405                 break;
406         }
407 }
408
409 static void harness_comment (struct torture_context *test, 
410                                                          const char *comment)
411 {
412         printf("# %s\n", comment);
413 }
414
415 const static struct torture_ui_ops harness_ui_ops = {
416         .comment = harness_comment,
417         .test_start = harness_test_start,
418         .test_result = harness_test_result
419 };
420
421 static void quiet_suite_start(struct torture_context *ctx,
422                                                   struct torture_suite *suite)
423 {
424         int i;
425         ctx->quiet = true;
426         for (i = 1; i < ctx->level; i++) putchar('\t');
427         printf("%s: ", suite->name);
428         fflush(stdout);
429 }
430
431 static void quiet_suite_finish(struct torture_context *ctx,
432                                                   struct torture_suite *suite)
433 {
434         putchar('\n');
435 }
436
437 static void quiet_test_result (struct torture_context *context, 
438                                                            enum torture_result res, const char *reason)
439 {
440         fflush(stdout);
441         switch (res) {
442         case TORTURE_OK: putchar('.'); break;
443         case TORTURE_FAIL: putchar('F'); break;
444         case TORTURE_ERROR: putchar('E'); break;
445         case TORTURE_SKIP: putchar('I'); break;
446         }
447 }
448
449 const static struct torture_ui_ops quiet_ui_ops = {
450         .suite_start = quiet_suite_start,
451         .suite_finish = quiet_suite_finish,
452         .test_result = quiet_test_result
453 };
454
455 void run_shell(struct torture_context *tctx)
456 {
457         char *cline;
458         int argc;
459         const char **argv;
460         int ret;
461
462         while (1) {
463                 cline = smb_readline("torture> ", NULL, NULL);
464
465                 if (cline == NULL)
466                         return;
467         
468                 ret = poptParseArgvString(cline, &argc, &argv);
469                 if (ret != 0) {
470                         fprintf(stderr, "Error parsing line\n");
471                         continue;
472                 }
473
474                 if (!strcmp(argv[0], "quit")) {
475                         return;
476                 } else if (!strcmp(argv[0], "set")) {
477                         if (argc < 3) {
478                                 fprintf(stderr, "Usage: set <variable> <value>\n");
479                         } else {
480                                 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
481                                 lp_set_cmdline(name, argv[2]);
482                                 talloc_free(name);
483                         }
484                 } else if (!strcmp(argv[0], "help")) {
485                         fprintf(stderr, "Available commands:\n"
486                                                         " help - This help command\n"
487                                                         " run - Run test\n"
488                                                         " set - Change variables\n"
489                                                         "\n");
490                 } else if (!strcmp(argv[0], "run")) {
491                         if (argc < 2) {
492                                 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
493                         } else {
494                                 run_test(tctx, argv[1]);
495                         }
496                 }
497         }
498 }
499
500 /****************************************************************************
501   main program
502 ****************************************************************************/
503 int main(int argc,char *argv[])
504 {
505         int opt, i;
506         bool correct = true;
507         int max_runtime=0;
508         int argc_new;
509         struct torture_context *torture;
510         const struct torture_ui_ops *ui_ops;
511         char **argv_new;
512         poptContext pc;
513         static const char *target = "other";
514         struct dcerpc_binding *binding_struct;
515         NTSTATUS status;
516         int shell = False;
517         static const char *ui_ops_name = "simple";
518         static int list_tests = 0;
519         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
520               OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS, OPT_BASEDIR};
521         
522         struct poptOption long_options[] = {
523                 POPT_AUTOHELP
524                 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
525                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
526                 {"basedir",       0, POPT_ARG_STRING, NULL, OPT_BASEDIR, "base directory", "BSAEDIR" },
527                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "seed",         NULL},
528                 {"num-progs",     0, POPT_ARG_INT,  NULL,       OPT_NUMPROGS,   "num progs",    NULL},
529                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
530                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
531                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "loadfile",     NULL},
532                 {"list",          0, POPT_ARG_NONE, &list_tests, 0, NULL, NULL },
533                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
534                 {"timelimit",   't', POPT_ARG_INT,      NULL,   OPT_TIMELIMIT,  "timelimit",    NULL},
535                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
536                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
537                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,
538                  "run dangerous tests (eg. wiping out password database)", NULL},
539                 {"shell",               0, POPT_ARG_NONE, &shell, True, "Run shell", NULL},
540                 {"target",              'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
541                 {"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
542                  "run async tests", NULL},
543                 {"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
544                  "number of simultaneous async requests", NULL},
545                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
546                  "set maximum time for smbtorture to live", "seconds"},
547                 POPT_COMMON_SAMBA
548                 POPT_COMMON_CONNECTION
549                 POPT_COMMON_CREDENTIALS
550                 POPT_COMMON_VERSION
551                 { NULL }
552         };
553
554         setlinebuf(stdout);
555
556         /* we are never interested in SIGPIPE */
557         BlockSignals(true, SIGPIPE);
558
559         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
560                             POPT_CONTEXT_KEEP_FIRST);
561
562         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
563
564         while((opt = poptGetNextOpt(pc)) != -1) {
565                 switch (opt) {
566                 case OPT_LOADFILE:
567                         lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
568                         break;
569                 case OPT_UNCLIST:
570                         lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
571                         break;
572                 case OPT_TIMELIMIT:
573                         lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
574                         break;
575                 case OPT_NUMPROGS:
576                         lp_set_cmdline("torture:nprocs", poptGetOptArg(pc));
577                         break;
578                 case OPT_BASEDIR:
579                         lp_set_cmdline("torture:basedir", poptGetOptArg(pc));
580                         break;
581                 case OPT_DNS:
582                         parse_dns(poptGetOptArg(pc));
583                         break;
584                 case OPT_DANGEROUS:
585                         lp_set_cmdline("torture:dangerous", "Yes");
586                         break;
587                 case OPT_ASYNC:
588                         lp_set_cmdline("torture:async", "Yes");
589                         break;
590                 case OPT_SMB_PORTS:
591                         lp_set_cmdline("smb ports", poptGetOptArg(pc));
592                         break;
593                 }
594         }
595
596         if (strcmp(target, "samba3") == 0) {
597                 lp_set_cmdline("torture:samba3", "true");
598         } else if (strcmp(target, "samba4") == 0) {
599                 lp_set_cmdline("torture:samba4", "true");
600         }
601
602         if (max_runtime) {
603                 /* this will only work if nobody else uses alarm(),
604                    which means it won't work for some tests, but we
605                    can't use the event context method we use for smbd
606                    as so many tests create their own event
607                    context. This will at least catch most cases. */
608                 signal(SIGALRM, max_runtime_handler);
609                 alarm(max_runtime);
610         }
611
612         torture_init();
613         ldb_global_init();
614
615         if (list_tests) {
616                 print_test_list();
617                 return 0;
618         }
619
620         if (torture_seed == 0) {
621                 torture_seed = time(NULL);
622         } 
623         printf("Using seed %d\n", torture_seed);
624         srandom(torture_seed);
625
626         argv_new = discard_const_p(char *, poptGetArgs(pc));
627
628         argc_new = argc;
629         for (i=0; i<argc; i++) {
630                 if (argv_new[i] == NULL) {
631                         argc_new = i;
632                         break;
633                 }
634         }
635
636         if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
637                 usage(pc);
638                 exit(1);
639         }
640
641         /* see if its a RPC transport specifier */
642         status = dcerpc_parse_binding(talloc_autofree_context(), argv_new[1], &binding_struct);
643         if (NT_STATUS_IS_OK(status)) {
644                 lp_set_cmdline("torture:host", binding_struct->host);
645                 lp_set_cmdline("torture:share", "IPC$");
646                 lp_set_cmdline("torture:binding", argv_new[1]);
647         } else {
648                 char *binding = NULL;
649                 char *host = NULL, *share = NULL;
650
651                 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
652                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
653                         usage(pc);
654                 }
655
656                 lp_set_cmdline("torture:host", host);
657                 lp_set_cmdline("torture:share", share);
658                 asprintf(&binding, "ncacn_np:%s", host);
659                 lp_set_cmdline("torture:binding", binding);
660         }
661
662         if (!strcmp(ui_ops_name, "simple")) {
663                 ui_ops = &std_ui_ops;
664         } else if (!strcmp(ui_ops_name, "subunit")) {
665                 ui_ops = &subunit_ui_ops;
666         } else if (!strcmp(ui_ops_name, "harness")) {
667                 ui_ops = &harness_ui_ops;
668         } else if (!strcmp(ui_ops_name, "quiet")) {
669                 ui_ops = &quiet_ui_ops;
670         } else {
671                 printf("Unknown output format '%s'\n", ui_ops_name);
672                 exit(1);
673         }
674
675         torture = torture_context_init(talloc_autofree_context(), ui_ops);
676
677         if (argc_new == 0) {
678                 printf("You must specify a test to run, or 'ALL'\n");
679         } else if (shell) {
680                 run_shell(torture);
681         } else {
682                 for (i=2;i<argc_new;i++) {
683                         if (!run_test(torture, argv_new[i])) {
684                                 correct = false;
685                         }
686                 }
687         }
688
689         if (torture->returncode) {
690                 return(0);
691         } else {
692                 return(1);
693         }
694 }