r22788: fix typo
[Samba.git] / source / torture / smbtorture.c
blob5247abc14b092d6f02a03d1ba20ed34dc74819f1
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006
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.
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.
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.
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 "system/readline.h"
28 #include "lib/smbreadline/smbreadline.h"
29 #include "libcli/libcli.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/events/events.h"
32 #include "dynconfig.h"
34 #include "torture/torture.h"
35 #include "build.h"
36 #include "lib/util/dlinklist.h"
37 #include "librpc/rpc/dcerpc.h"
39 static bool run_matching(struct torture_context *torture,
40 const char *prefix,
41 const char *expr,
42 struct torture_suite *suite,
43 bool *matched)
45 bool ret = true;
47 if (suite == NULL) {
48 struct torture_suite *o;
50 for (o = torture_root->children; o; o = o->next) {
51 if (gen_fnmatch(expr, o->name) == 0) {
52 *matched = true;
53 init_iconv();
54 ret &= torture_run_suite(torture, o);
55 continue;
58 ret &= run_matching(torture, o->name, expr, o, matched);
60 } else {
61 char *name;
62 struct torture_suite *c;
63 struct torture_tcase *t;
65 for (c = suite->children; c; c = c->next) {
66 asprintf(&name, "%s-%s", prefix, c->name);
68 if (gen_fnmatch(expr, name) == 0) {
69 *matched = true;
70 init_iconv();
71 torture->active_testname = talloc_strdup(torture, prefix);
72 ret &= torture_run_suite(torture, c);
73 free(name);
74 continue;
77 ret &= run_matching(torture, name, expr, c, matched);
79 free(name);
82 for (t = suite->testcases; t; t = t->next) {
83 asprintf(&name, "%s-%s", prefix, t->name);
84 if (gen_fnmatch(expr, name) == 0) {
85 *matched = true;
86 init_iconv();
87 torture->active_testname = talloc_strdup(torture, prefix);
88 ret &= torture_run_tcase(torture, t);
89 talloc_free(torture->active_testname);
91 free(name);
95 return ret;
98 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
100 /****************************************************************************
101 run a specified test or "ALL"
102 ****************************************************************************/
103 static bool run_test(struct torture_context *torture, const char *name)
105 bool ret = true;
106 bool matched = false;
107 struct torture_suite *o;
109 if (strequal(name, "ALL")) {
110 for (o = torture_root->children; o; o = o->next) {
111 ret &= torture_run_suite(torture, o);
113 return ret;
116 ret = run_matching(torture, NULL, name, NULL, &matched);
118 if (!matched) {
119 printf("Unknown torture operation '%s'\n", name);
120 return false;
123 return ret;
126 static void parse_dns(const char *dns)
128 char *userdn, *basedn, *secret;
129 char *p, *d;
131 /* retrievieng the userdn */
132 p = strchr_m(dns, '#');
133 if (!p) {
134 lp_set_cmdline("torture:ldap_userdn", "");
135 lp_set_cmdline("torture:ldap_basedn", "");
136 lp_set_cmdline("torture:ldap_secret", "");
137 return;
139 userdn = strndup(dns, p - dns);
140 lp_set_cmdline("torture:ldap_userdn", userdn);
142 /* retrieve the basedn */
143 d = p + 1;
144 p = strchr_m(d, '#');
145 if (!p) {
146 lp_set_cmdline("torture:ldap_basedn", "");
147 lp_set_cmdline("torture:ldap_secret", "");
148 return;
150 basedn = strndup(d, p - d);
151 lp_set_cmdline("torture:ldap_basedn", basedn);
153 /* retrieve the secret */
154 p = p + 1;
155 if (!p) {
156 lp_set_cmdline("torture:ldap_secret", "");
157 return;
159 secret = strdup(p);
160 lp_set_cmdline("torture:ldap_secret", secret);
162 printf ("%s - %s - %s\n", userdn, basedn, secret);
166 static void print_test_list(void)
168 struct torture_suite *o;
169 struct torture_suite *s;
170 struct torture_tcase *t;
172 for (o = torture_root->children; o; o = o->next) {
173 for (s = o->children; s; s = s->next) {
174 printf("%s-%s\n", o->name, s->name);
177 for (t = o->testcases; t; t = t->next) {
178 printf("%s-%s\n", o->name, t->name);
183 static void usage(poptContext pc)
185 struct torture_suite *o;
186 struct torture_suite *s;
187 struct torture_tcase *t;
188 int i;
190 poptPrintUsage(pc, stdout, 0);
191 printf("\n");
193 printf("The binding format is:\n\n");
195 printf(" TRANSPORT:host[flags]\n\n");
197 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
198 printf(" or ncalrpc for local connections.\n\n");
200 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
201 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
202 printf(" string.\n\n");
204 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
205 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
206 printf(" will be auto-determined.\n\n");
208 printf(" other recognised flags are:\n\n");
210 printf(" sign : enable ntlmssp signing\n");
211 printf(" seal : enable ntlmssp sealing\n");
212 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
213 printf(" validate: enable the NDR validator\n");
214 printf(" print: enable debugging of the packets\n");
215 printf(" bigendian: use bigendian RPC\n");
216 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
218 printf(" For example, these all connect to the samr pipe:\n\n");
220 printf(" ncacn_np:myserver\n");
221 printf(" ncacn_np:myserver[samr]\n");
222 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
223 printf(" ncacn_np:myserver[/pipe/samr]\n");
224 printf(" ncacn_np:myserver[samr,sign,print]\n");
225 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
226 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
227 printf(" ncacn_np:\n");
228 printf(" ncacn_np:[/pipe/samr]\n\n");
230 printf(" ncacn_ip_tcp:myserver\n");
231 printf(" ncacn_ip_tcp:myserver[1024]\n");
232 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
234 printf(" ncalrpc:\n\n");
236 printf("The UNC format is:\n\n");
238 printf(" //server/share\n\n");
240 printf("Tests are:");
242 for (o = torture_root->children; o; o = o->next) {
243 printf("\n%s (%s):\n ", o->description, o->name);
245 i = 0;
246 for (s = o->children; s; s = s->next) {
247 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
248 printf("\n ");
249 i = 0;
251 i+=printf("%s-%s ", o->name, s->name);
254 for (t = o->testcases; t; t = t->next) {
255 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
256 printf("\n ");
257 i = 0;
259 i+=printf("%s-%s ", o->name, t->name);
262 if (i) printf("\n");
265 printf("\nThe default test is ALL.\n");
267 exit(1);
270 static void max_runtime_handler(int sig)
272 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
273 exit(1);
276 struct timeval last_suite_started;
278 static void simple_suite_start(struct torture_context *ctx,
279 struct torture_suite *suite)
281 last_suite_started = timeval_current();
282 printf("Running %s\n", suite->name);
285 static void simple_suite_finish(struct torture_context *ctx,
286 struct torture_suite *suite)
289 printf("%s took %g secs\n\n", suite->name,
290 timeval_elapsed(&last_suite_started));
293 static void simple_test_result (struct torture_context *context,
294 enum torture_result res, const char *reason)
296 switch (res) {
297 case TORTURE_OK:
298 if (reason)
299 printf("OK: %s\n", reason);
300 break;
301 case TORTURE_FAIL:
302 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
303 break;
304 case TORTURE_ERROR:
305 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
306 break;
307 case TORTURE_SKIP:
308 printf("SKIP: %s - %s\n", context->active_test->name, reason);
309 break;
313 static void simple_comment (struct torture_context *test,
314 const char *comment)
316 printf("%s", comment);
319 static void simple_warning(struct torture_context *test,
320 const char *comment)
322 fprintf(stderr, "WARNING: %s\n", comment);
325 const static struct torture_ui_ops std_ui_ops = {
326 .comment = simple_comment,
327 .warning = simple_warning,
328 .suite_start = simple_suite_start,
329 .suite_finish = simple_suite_finish,
330 .test_result = simple_test_result
333 static void subunit_init(struct torture_context *ctx)
335 /* FIXME: register segv and bus handler */
338 static void subunit_suite_start(struct torture_context *ctx,
339 struct torture_suite *suite)
341 printf("testsuite: %s\n", suite->name);
344 static void subunit_test_start (struct torture_context *ctx,
345 struct torture_tcase *tcase,
346 struct torture_test *test)
348 printf("test: %s\n", test->name);
351 static void subunit_test_result (struct torture_context *context,
352 enum torture_result res, const char *reason)
354 switch (res) {
355 case TORTURE_OK:
356 printf("success: %s", context->active_test->name);
357 break;
358 case TORTURE_FAIL:
359 printf("failure: %s", context->active_test->name);
360 break;
361 case TORTURE_ERROR:
362 printf("error: %s", context->active_test->name);
363 break;
364 case TORTURE_SKIP:
365 printf("skip: %s", context->active_test->name);
366 break;
368 if (reason)
369 printf(" [\n%s\n]", reason);
370 printf("\n");
373 static void subunit_comment (struct torture_context *test,
374 const char *comment)
376 fprintf(stderr, "%s", comment);
379 const static struct torture_ui_ops subunit_ui_ops = {
380 .init = subunit_init,
381 .comment = subunit_comment,
382 .test_start = subunit_test_start,
383 .test_result = subunit_test_result,
384 .suite_start = subunit_suite_start
387 static void harness_test_start (struct torture_context *ctx,
388 struct torture_tcase *tcase,
389 struct torture_test *test)
393 static void harness_test_result (struct torture_context *context,
394 enum torture_result res, const char *reason)
396 switch (res) {
397 case TORTURE_OK:
398 printf("ok %s - %s\n", context->active_test->name, reason);
399 break;
400 case TORTURE_FAIL:
401 case TORTURE_ERROR:
402 printf("not ok %s - %s\n", context->active_test->name, reason);
403 break;
404 case TORTURE_SKIP:
405 printf("skip %s - %s\n", context->active_test->name, reason);
406 break;
410 static void harness_comment (struct torture_context *test,
411 const char *comment)
413 printf("# %s\n", comment);
416 const static struct torture_ui_ops harness_ui_ops = {
417 .comment = harness_comment,
418 .test_start = harness_test_start,
419 .test_result = harness_test_result
422 static void quiet_suite_start(struct torture_context *ctx,
423 struct torture_suite *suite)
425 int i;
426 ctx->quiet = true;
427 for (i = 1; i < ctx->level; i++) putchar('\t');
428 printf("%s: ", suite->name);
429 fflush(stdout);
432 static void quiet_suite_finish(struct torture_context *ctx,
433 struct torture_suite *suite)
435 putchar('\n');
438 static void quiet_test_result (struct torture_context *context,
439 enum torture_result res, const char *reason)
441 fflush(stdout);
442 switch (res) {
443 case TORTURE_OK: putchar('.'); break;
444 case TORTURE_FAIL: putchar('F'); break;
445 case TORTURE_ERROR: putchar('E'); break;
446 case TORTURE_SKIP: putchar('I'); break;
450 const static struct torture_ui_ops quiet_ui_ops = {
451 .suite_start = quiet_suite_start,
452 .suite_finish = quiet_suite_finish,
453 .test_result = quiet_test_result
456 void run_shell(struct torture_context *tctx)
458 char *cline;
459 int argc;
460 const char **argv;
461 int ret;
463 while (1) {
464 cline = smb_readline("torture> ", NULL, NULL);
466 if (cline == NULL)
467 return;
469 ret = poptParseArgvString(cline, &argc, &argv);
470 if (ret != 0) {
471 fprintf(stderr, "Error parsing line\n");
472 continue;
475 if (!strcmp(argv[0], "quit")) {
476 return;
477 } else if (!strcmp(argv[0], "set")) {
478 if (argc < 3) {
479 fprintf(stderr, "Usage: set <variable> <value>\n");
480 } else {
481 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
482 lp_set_cmdline(name, argv[2]);
483 talloc_free(name);
485 } else if (!strcmp(argv[0], "help")) {
486 fprintf(stderr, "Available commands:\n"
487 " help - This help command\n"
488 " run - Run test\n"
489 " set - Change variables\n"
490 "\n");
491 } else if (!strcmp(argv[0], "run")) {
492 if (argc < 2) {
493 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
494 } else {
495 run_test(tctx, argv[1]);
501 /****************************************************************************
502 main program
503 ****************************************************************************/
504 int main(int argc,char *argv[])
506 int opt, i;
507 bool correct = true;
508 int max_runtime=0;
509 int argc_new;
510 struct torture_context *torture;
511 const struct torture_ui_ops *ui_ops;
512 char **argv_new;
513 poptContext pc;
514 static const char *target = "other";
515 struct dcerpc_binding *binding_struct;
516 NTSTATUS status;
517 int shell = False;
518 static const char *ui_ops_name = "simple";
519 static int list_tests = 0;
520 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
521 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS, OPT_BASEDIR};
523 struct poptOption long_options[] = {
524 POPT_AUTOHELP
525 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
526 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
527 {"basedir", 0, POPT_ARG_STRING, NULL, OPT_BASEDIR, "base directory", "BSAEDIR" },
528 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
529 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
530 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
531 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
532 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
533 {"list", 0, POPT_ARG_NONE, &list_tests, 0, NULL, NULL },
534 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
535 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "timelimit", NULL},
536 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
537 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
538 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
539 "run dangerous tests (eg. wiping out password database)", NULL},
540 {"shell", 0, POPT_ARG_NONE, &shell, True, "Run shell", NULL},
541 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
542 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
543 "run async tests", NULL},
544 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
545 "number of simultaneous async requests", NULL},
546 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
547 "set maximum time for smbtorture to live", "seconds"},
548 POPT_COMMON_SAMBA
549 POPT_COMMON_CONNECTION
550 POPT_COMMON_CREDENTIALS
551 POPT_COMMON_VERSION
552 { NULL }
555 setlinebuf(stdout);
557 /* we are never interested in SIGPIPE */
558 BlockSignals(true, SIGPIPE);
560 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
561 POPT_CONTEXT_KEEP_FIRST);
563 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
565 while((opt = poptGetNextOpt(pc)) != -1) {
566 switch (opt) {
567 case OPT_LOADFILE:
568 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
569 break;
570 case OPT_UNCLIST:
571 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
572 break;
573 case OPT_TIMELIMIT:
574 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
575 break;
576 case OPT_NUMPROGS:
577 lp_set_cmdline("torture:nprocs", poptGetOptArg(pc));
578 break;
579 case OPT_BASEDIR:
580 lp_set_cmdline("torture:basedir", poptGetOptArg(pc));
581 break;
582 case OPT_DNS:
583 parse_dns(poptGetOptArg(pc));
584 break;
585 case OPT_DANGEROUS:
586 lp_set_cmdline("torture:dangerous", "Yes");
587 break;
588 case OPT_ASYNC:
589 lp_set_cmdline("torture:async", "Yes");
590 break;
591 case OPT_SMB_PORTS:
592 lp_set_cmdline("smb ports", poptGetOptArg(pc));
593 break;
597 if (strcmp(target, "samba3") == 0) {
598 lp_set_cmdline("torture:samba3", "true");
599 } else if (strcmp(target, "samba4") == 0) {
600 lp_set_cmdline("torture:samba4", "true");
603 if (max_runtime) {
604 /* this will only work if nobody else uses alarm(),
605 which means it won't work for some tests, but we
606 can't use the event context method we use for smbd
607 as so many tests create their own event
608 context. This will at least catch most cases. */
609 signal(SIGALRM, max_runtime_handler);
610 alarm(max_runtime);
613 torture_init();
614 ldb_global_init();
616 if (list_tests) {
617 print_test_list();
618 return 0;
621 if (torture_seed == 0) {
622 torture_seed = time(NULL);
624 printf("Using seed %d\n", torture_seed);
625 srandom(torture_seed);
627 argv_new = discard_const_p(char *, poptGetArgs(pc));
629 argc_new = argc;
630 for (i=0; i<argc; i++) {
631 if (argv_new[i] == NULL) {
632 argc_new = i;
633 break;
637 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
638 usage(pc);
639 exit(1);
642 /* see if its a RPC transport specifier */
643 status = dcerpc_parse_binding(talloc_autofree_context(), argv_new[1], &binding_struct);
644 if (NT_STATUS_IS_OK(status)) {
645 lp_set_cmdline("torture:host", binding_struct->host);
646 lp_set_cmdline("torture:share", "IPC$");
647 lp_set_cmdline("torture:binding", argv_new[1]);
648 } else {
649 char *binding = NULL;
650 char *host = NULL, *share = NULL;
652 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
653 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
654 usage(pc);
657 lp_set_cmdline("torture:host", host);
658 lp_set_cmdline("torture:share", share);
659 asprintf(&binding, "ncacn_np:%s", host);
660 lp_set_cmdline("torture:binding", binding);
663 if (!strcmp(ui_ops_name, "simple")) {
664 ui_ops = &std_ui_ops;
665 } else if (!strcmp(ui_ops_name, "subunit")) {
666 ui_ops = &subunit_ui_ops;
667 } else if (!strcmp(ui_ops_name, "harness")) {
668 ui_ops = &harness_ui_ops;
669 } else if (!strcmp(ui_ops_name, "quiet")) {
670 ui_ops = &quiet_ui_ops;
671 } else {
672 printf("Unknown output format '%s'\n", ui_ops_name);
673 exit(1);
676 torture = torture_context_init(talloc_autofree_context(), ui_ops);
678 if (argc_new == 0) {
679 printf("You must specify a test to run, or 'ALL'\n");
680 } else if (shell) {
681 run_shell(torture);
682 } else {
683 for (i=2;i<argc_new;i++) {
684 if (!run_test(torture, argv_new[i])) {
685 correct = false;
690 if (torture->returncode) {
691 return(0);
692 } else {
693 return(1);