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