5740829d7d5e886ebf83c384b01ad183b6f18eed
[kai/samba.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 *o;
47
48                 for (o = torture_root->children; o; o = o->next) {
49                         if (gen_fnmatch(expr, o->name) == 0) {
50                                 *matched = true;
51                                 init_iconv();
52                                 ret &= torture_run_suite(torture, o);
53                                 continue;
54                         }
55
56                         ret &= run_matching(torture, 
57                                                                 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                         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 *o;
103
104         if (strequal(name, "ALL")) {
105                 for (o = torture_root->children; o; o = o->next) {
106                         ret &= torture_run_suite(torture, o);
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 *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_root->children; o; o = o->next) {
221                 printf("\n%s (%s):\n  ", o->description, o->name);
222
223                 i = 0;
224                 for (s = o->children; s; s = s->next) {
225                         if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
226                                 printf("\n  ");
227                                 i = 0;
228                         }
229                         i+=printf("%s-%s ", o->name, s->name);
230                 }
231
232                 for (t = o->testcases; t; t = t->next) {
233                         if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
234                                 printf("\n  ");
235                                 i = 0;
236                         }
237                         i+=printf("%s-%s ", o->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_ERROR:
295                 printf("ERROR IN TEST %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 static void simple_comment (struct torture_context *test, 
304                                                         const char *comment)
305 {
306         printf("%s", comment);
307 }
308
309 const static struct torture_ui_ops std_ui_ops = {
310         .comment = simple_comment,
311         .suite_start = simple_suite_start,
312         .suite_finish = simple_suite_finish,
313         .test_result = simple_test_result
314 };
315
316
317 static void subunit_test_start (struct torture_context *ctx, 
318                                                             struct torture_tcase *tcase,
319                                                                 struct torture_test *test)
320 {
321         printf("test: %s\n", test->name);
322 }
323
324 static void subunit_test_result (struct torture_context *context, 
325                                                                  enum torture_result res, const char *reason)
326 {
327         switch (res) {
328         case TORTURE_OK:
329                 printf("success: %s", context->active_test->name);
330                 break;
331         case TORTURE_FAIL:
332                 printf("failure: %s", context->active_test->name);
333                 break;
334         case TORTURE_ERROR:
335                 printf("error: %s", context->active_test->name);
336                 break;
337         case TORTURE_SKIP:
338                 printf("skip: %s", context->active_test->name);
339                 break;
340         }
341         if (reason)
342                 printf(" [ %s ]", reason);
343         printf("\n");
344 }
345
346 static void subunit_comment (struct torture_context *test, 
347                                                          const char *comment)
348 {
349         fprintf(stderr, "%s", comment);
350 }
351
352 const static struct torture_ui_ops subunit_ui_ops = {
353         .comment = subunit_comment,
354         .test_start = subunit_test_start,
355         .test_result = subunit_test_result
356 };
357
358 static void harness_test_start (struct torture_context *ctx, 
359                                                             struct torture_tcase *tcase,
360                                                                 struct torture_test *test)
361 {
362 }
363
364 static void harness_test_result (struct torture_context *context, 
365                                                                  enum torture_result res, const char *reason)
366 {
367         switch (res) {
368         case TORTURE_OK:
369                 printf("ok %s - %s\n", context->active_test->name, reason);
370                 break;
371         case TORTURE_FAIL:
372         case TORTURE_ERROR:
373                 printf("not ok %s - %s\n", context->active_test->name, reason);
374                 break;
375         case TORTURE_SKIP:
376                 printf("skip %s - %s\n", context->active_test->name, reason);
377                 break;
378         }
379 }
380
381 static void harness_comment (struct torture_context *test, 
382                                                          const char *comment)
383 {
384         printf("# %s\n", comment);
385 }
386
387 const static struct torture_ui_ops harness_ui_ops = {
388         .comment = harness_comment,
389         .test_start = harness_test_start,
390         .test_result = harness_test_result
391 };
392
393 static void quiet_suite_start(struct torture_context *ctx,
394                                                   struct torture_suite *suite)
395 {
396         int i;
397         ctx->quiet = true;
398         for (i = 1; i < ctx->level; i++) putchar('\t');
399         printf("%s: ", suite->name);
400         fflush(stdout);
401 }
402
403 static void quiet_suite_finish(struct torture_context *ctx,
404                                                   struct torture_suite *suite)
405 {
406         putchar('\n');
407 }
408
409 static void quiet_test_result (struct torture_context *context, 
410                                                            enum torture_result res, const char *reason)
411 {
412         fflush(stdout);
413         switch (res) {
414         case TORTURE_OK: putchar('.'); break;
415         case TORTURE_FAIL: putchar('F'); break;
416         case TORTURE_ERROR: putchar('E'); break;
417         case TORTURE_SKIP: putchar('I'); break;
418         }
419 }
420
421 const static struct torture_ui_ops quiet_ui_ops = {
422         .suite_start = quiet_suite_start,
423         .suite_finish = quiet_suite_finish,
424         .test_result = quiet_test_result
425 };
426
427
428 /****************************************************************************
429   main program
430 ****************************************************************************/
431  int main(int argc,char *argv[])
432 {
433         int opt, i;
434         bool correct = true;
435         int max_runtime=0;
436         int argc_new;
437         struct torture_context *torture;
438         char **argv_new;
439         poptContext pc;
440         static const char *target = "other";
441         const char **subunit_dir;
442         static const char *ui_ops_name = "simple";
443         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
444               OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC};
445         
446         struct poptOption long_options[] = {
447                 POPT_AUTOHELP
448                 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
449                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
450                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "seed",         NULL},
451                 {"num-progs",     0, POPT_ARG_INT,  &torture_nprocs,    0,      "num progs",    NULL},
452                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
453                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
454                 {"show-all",      0, POPT_ARG_NONE, &torture_showall,   0,      "show all",     NULL},
455                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "loadfile",     NULL},
456                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
457                 {"timelimit",   't', POPT_ARG_STRING,   NULL,   OPT_TIMELIMIT,  "timelimit",    NULL},
458                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
459                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
460                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,
461                  "run dangerous tests (eg. wiping out password database)", NULL},
462                 {"target",              'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
463                 {"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
464                  "run async tests", NULL},
465                 {"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
466                  "number of simultaneous async requests", NULL},
467                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
468                  "set maximum time for smbtorture to live", "seconds"},
469                 POPT_COMMON_SAMBA
470                 POPT_COMMON_CONNECTION
471                 POPT_COMMON_CREDENTIALS
472                 POPT_COMMON_VERSION
473                 { NULL }
474         };
475
476         setlinebuf(stdout);
477
478         /* we are never interested in SIGPIPE */
479         BlockSignals(true,SIGPIPE);
480
481         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
482                             POPT_CONTEXT_KEEP_FIRST);
483
484         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
485
486         while((opt = poptGetNextOpt(pc)) != -1) {
487                 switch (opt) {
488                 case OPT_LOADFILE:
489                         lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
490                         break;
491                 case OPT_UNCLIST:
492                         lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
493                         break;
494                 case OPT_TIMELIMIT:
495                         lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
496                         break;
497                 case OPT_DNS:
498                         parse_dns(poptGetOptArg(pc));
499                         break;
500                 case OPT_DANGEROUS:
501                         lp_set_cmdline("torture:dangerous", "Yes");
502                         break;
503                 case OPT_ASYNC:
504                         lp_set_cmdline("torture:async", "Yes");
505                         break;
506                 case OPT_SMB_PORTS:
507                         lp_set_cmdline("smb ports", poptGetOptArg(pc));
508                         break;
509                 default:
510                         d_printf("Invalid option %s: %s\n", 
511                                  poptBadOption(pc, 0), poptStrerror(opt));
512                         torture_init();
513                         usage(pc);
514                         exit(1);
515                 }
516         }
517
518         if (strcmp(target, "samba3") == 0) {
519                 lp_set_cmdline("target:samba3", "true");
520         } else if (strcmp(target, "samba4") == 0) {
521                 lp_set_cmdline("target:samba4", "true");
522         }
523
524         if (max_runtime) {
525                 /* this will only work if nobody else uses alarm(),
526                    which means it won't work for some tests, but we
527                    can't use the event context method we use for smbd
528                    as so many tests create their own event
529                    context. This will at least catch most cases. */
530                 signal(SIGALRM, max_runtime_handler);
531                 alarm(max_runtime);
532         }
533
534         torture_init();
535         ldb_global_init();
536
537         subunit_dir = lp_parm_string_list(-1, "torture", "subunitdir", ":");
538         if (subunit_dir == NULL) 
539                 torture_subunit_load_testsuites(dyn_TORTUREDIR, true, NULL);
540         else {
541                 for (i = 0; subunit_dir[i]; i++)
542                         torture_subunit_load_testsuites(subunit_dir[i], true, NULL);
543         }
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         /* see if its a RPC transport specifier */
567         if (is_binding_string(argv_new[1])) {
568                 lp_set_cmdline("torture:binding", argv_new[1]);
569         } else {
570                 char *binding = NULL;
571                 char *host = NULL, *share = NULL;
572
573                 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
574                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
575                         usage(pc);
576                 }
577
578                 lp_set_cmdline("torture:host", host);
579                 lp_set_cmdline("torture:share", share);
580                 asprintf(&binding, "ncacn_np:%s", host);
581                 lp_set_cmdline("torture:binding", binding);
582         }
583
584         torture = talloc_zero(talloc_autofree_context(), struct torture_context);
585         if (!strcmp(ui_ops_name, "simple")) {
586                 torture->ui_ops = &std_ui_ops;
587         } else if (!strcmp(ui_ops_name, "subunit")) {
588                 torture->ui_ops = &subunit_ui_ops;
589         } else if (!strcmp(ui_ops_name, "harness")) {
590                 torture->ui_ops = &harness_ui_ops;
591         } else if (!strcmp(ui_ops_name, "quiet")) {
592                 torture->ui_ops = &quiet_ui_ops;
593         } else {
594                 printf("Unknown output format '%s'\n", ui_ops_name);
595                 exit(1);
596         }
597
598         if (argc_new == 0) {
599                 printf("You must specify a test to run, or 'ALL'\n");
600         } else {
601                 int total;
602                 double rate;
603                 for (i=2;i<argc_new;i++) {
604                         if (!run_test(torture, argv_new[i])) {
605                                 correct = false;
606                         }
607                 }
608
609                 total = torture->skipped+torture->success+torture->failed;
610                 if (total == 0) {
611                         printf("No tests run.\n");
612                 } else {
613                         rate = ((total - torture->failed) * (100.0 / total));
614                         printf("Tests: %d, Errors: %d, Skipped: %d. Success rate: %.2f%%\n",
615                            total, torture->failed, torture->skipped,
616                            rate);
617                 }
618         }
619
620         talloc_free(torture);
621
622         if (correct) {
623                 return(0);
624         } else {
625                 return(1);
626         }
627 }