2 Unix SMB/CIFS implementation.
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 3 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, see <http://www.gnu.org/licenses/>.
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"
33 #include "torture/torture.h"
35 #include "lib/util/dlinklist.h"
36 #include "librpc/rpc/dcerpc.h"
38 static bool run_matching(struct torture_context *torture,
41 struct torture_suite *suite,
47 struct torture_suite *o;
49 for (o = torture_root->children; o; o = o->next) {
50 if (gen_fnmatch(expr, o->name) == 0) {
53 ret &= torture_run_suite(torture, o);
57 ret &= run_matching(torture, o->name, expr, o, matched);
61 struct torture_suite *c;
62 struct torture_tcase *t;
64 for (c = suite->children; c; c = c->next) {
65 asprintf(&name, "%s-%s", prefix, c->name);
67 if (gen_fnmatch(expr, name) == 0) {
70 torture->active_testname = talloc_strdup(torture, prefix);
71 ret &= torture_run_suite(torture, c);
76 ret &= run_matching(torture, name, expr, c, matched);
81 for (t = suite->testcases; t; t = t->next) {
82 asprintf(&name, "%s-%s", prefix, t->name);
83 if (gen_fnmatch(expr, name) == 0) {
86 torture->active_testname = talloc_strdup(torture, prefix);
87 ret &= torture_run_tcase(torture, t);
88 talloc_free(torture->active_testname);
97 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
99 /****************************************************************************
100 run a specified test or "ALL"
101 ****************************************************************************/
102 static bool run_test(struct torture_context *torture, const char *name)
105 bool matched = false;
106 struct torture_suite *o;
108 if (strequal(name, "ALL")) {
109 for (o = torture_root->children; o; o = o->next) {
110 ret &= torture_run_suite(torture, o);
115 ret = run_matching(torture, NULL, name, NULL, &matched);
118 printf("Unknown torture operation '%s'\n", name);
125 static void parse_dns(const char *dns)
127 char *userdn, *basedn, *secret;
130 /* retrievieng the userdn */
131 p = strchr_m(dns, '#');
133 lp_set_cmdline("torture:ldap_userdn", "");
134 lp_set_cmdline("torture:ldap_basedn", "");
135 lp_set_cmdline("torture:ldap_secret", "");
138 userdn = strndup(dns, p - dns);
139 lp_set_cmdline("torture:ldap_userdn", userdn);
141 /* retrieve the basedn */
143 p = strchr_m(d, '#');
145 lp_set_cmdline("torture:ldap_basedn", "");
146 lp_set_cmdline("torture:ldap_secret", "");
149 basedn = strndup(d, p - d);
150 lp_set_cmdline("torture:ldap_basedn", basedn);
152 /* retrieve the secret */
155 lp_set_cmdline("torture:ldap_secret", "");
159 lp_set_cmdline("torture:ldap_secret", secret);
161 printf ("%s - %s - %s\n", userdn, basedn, secret);
165 static void print_test_list(void)
167 struct torture_suite *o;
168 struct torture_suite *s;
169 struct torture_tcase *t;
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);
176 for (t = o->testcases; t; t = t->next) {
177 printf("%s-%s\n", o->name, t->name);
182 _NORETURN_ static void usage(poptContext pc)
184 struct torture_suite *o;
185 struct torture_suite *s;
186 struct torture_tcase *t;
189 poptPrintUsage(pc, stdout, 0);
192 printf("The binding format is:\n\n");
194 printf(" TRANSPORT:host[flags]\n\n");
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");
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");
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");
207 printf(" other recognised flags are:\n\n");
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");
217 printf(" For example, these all connect to the samr pipe:\n\n");
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");
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");
233 printf(" ncalrpc:\n\n");
235 printf("The UNC format is:\n\n");
237 printf(" //server/share\n\n");
239 printf("Tests are:");
241 if (torture_root == NULL) {
242 printf("NO TESTS LOADED\n");
246 for (o = torture_root->children; o; o = o->next) {
247 printf("\n%s (%s):\n ", o->description, o->name);
250 for (s = o->children; s; s = s->next) {
251 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
255 i+=printf("%s-%s ", o->name, s->name);
258 for (t = o->testcases; t; t = t->next) {
259 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
263 i+=printf("%s-%s ", o->name, t->name);
269 printf("\nThe default test is ALL.\n");
274 _NORETURN_ static void max_runtime_handler(int sig)
276 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
280 struct timeval last_suite_started;
282 static void simple_suite_start(struct torture_context *ctx,
283 struct torture_suite *suite)
285 last_suite_started = timeval_current();
286 printf("Running %s\n", suite->name);
289 static void simple_suite_finish(struct torture_context *ctx,
290 struct torture_suite *suite)
293 printf("%s took %g secs\n\n", suite->name,
294 timeval_elapsed(&last_suite_started));
297 static void simple_test_result (struct torture_context *context,
298 enum torture_result res, const char *reason)
303 printf("OK: %s\n", reason);
306 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
309 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
312 printf("SKIP: %s - %s\n", context->active_test->name, reason);
317 static void simple_comment (struct torture_context *test,
320 printf("%s", comment);
323 static void simple_warning(struct torture_context *test,
326 fprintf(stderr, "WARNING: %s\n", comment);
329 const static struct torture_ui_ops std_ui_ops = {
330 .comment = simple_comment,
331 .warning = simple_warning,
332 .suite_start = simple_suite_start,
333 .suite_finish = simple_suite_finish,
334 .test_result = simple_test_result
337 static void subunit_init(struct torture_context *ctx)
339 /* FIXME: register segv and bus handler */
342 static void subunit_suite_start(struct torture_context *ctx,
343 struct torture_suite *suite)
347 static void subunit_test_start (struct torture_context *ctx,
348 struct torture_tcase *tcase,
349 struct torture_test *test)
351 printf("test: %s\n", test->name);
354 static void subunit_test_result (struct torture_context *context,
355 enum torture_result res, const char *reason)
359 printf("success: %s", context->active_test->name);
362 printf("failure: %s", context->active_test->name);
365 printf("error: %s", context->active_test->name);
368 printf("skip: %s", context->active_test->name);
372 printf(" [\n%s\n]", reason);
376 static void subunit_comment (struct torture_context *test,
379 fprintf(stderr, "%s", comment);
382 const static struct torture_ui_ops subunit_ui_ops = {
383 .init = subunit_init,
384 .comment = subunit_comment,
385 .test_start = subunit_test_start,
386 .test_result = subunit_test_result,
387 .suite_start = subunit_suite_start
390 static void quiet_suite_start(struct torture_context *ctx,
391 struct torture_suite *suite)
395 for (i = 1; i < ctx->level; i++) putchar('\t');
396 printf("%s: ", suite->name);
400 static void quiet_suite_finish(struct torture_context *ctx,
401 struct torture_suite *suite)
406 static void quiet_test_result (struct torture_context *context,
407 enum torture_result res, const char *reason)
411 case TORTURE_OK: putchar('.'); break;
412 case TORTURE_FAIL: putchar('F'); break;
413 case TORTURE_ERROR: putchar('E'); break;
414 case TORTURE_SKIP: putchar('I'); break;
418 const static struct torture_ui_ops quiet_ui_ops = {
419 .suite_start = quiet_suite_start,
420 .suite_finish = quiet_suite_finish,
421 .test_result = quiet_test_result
424 void run_shell(struct torture_context *tctx)
432 cline = smb_readline("torture> ", NULL, NULL);
437 ret = poptParseArgvString(cline, &argc, &argv);
439 fprintf(stderr, "Error parsing line\n");
443 if (!strcmp(argv[0], "quit")) {
445 } else if (!strcmp(argv[0], "set")) {
447 fprintf(stderr, "Usage: set <variable> <value>\n");
449 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
450 lp_set_cmdline(name, argv[2]);
453 } else if (!strcmp(argv[0], "help")) {
454 fprintf(stderr, "Available commands:\n"
455 " help - This help command\n"
457 " set - Change variables\n"
459 } else if (!strcmp(argv[0], "run")) {
461 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
463 run_test(tctx, argv[1]);
469 /****************************************************************************
471 ****************************************************************************/
472 int main(int argc,char *argv[])
478 struct torture_context *torture;
479 const struct torture_ui_ops *ui_ops;
482 static const char *target = "other";
483 struct dcerpc_binding *binding_struct;
486 static const char *ui_ops_name = "simple";
487 const char *basedir = NULL;
488 const char *extra_module = NULL;
489 static int list_tests = 0;
490 char *host = NULL, *share = NULL;
491 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
492 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
494 struct poptOption long_options[] = {
496 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
497 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
498 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
499 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
500 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
501 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
502 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
503 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
504 {"list", 0, POPT_ARG_NONE, &list_tests, 0, NULL, NULL },
505 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
506 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "timelimit", NULL},
507 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
508 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
509 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
510 "run dangerous tests (eg. wiping out password database)", NULL},
511 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
512 {"shell", 0, POPT_ARG_NONE, &shell, True, "Run shell", NULL},
513 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
514 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
515 "run async tests", NULL},
516 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
517 "number of simultaneous async requests", NULL},
518 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
519 "set maximum time for smbtorture to live", "seconds"},
521 POPT_COMMON_CONNECTION
522 POPT_COMMON_CREDENTIALS
529 /* we are never interested in SIGPIPE */
530 BlockSignals(true, SIGPIPE);
532 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
533 POPT_CONTEXT_KEEP_FIRST);
535 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
537 while((opt = poptGetNextOpt(pc)) != -1) {
540 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
543 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
546 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
549 lp_set_cmdline("torture:nprocs", poptGetOptArg(pc));
552 parse_dns(poptGetOptArg(pc));
555 lp_set_cmdline("torture:dangerous", "Yes");
558 lp_set_cmdline("torture:async", "Yes");
561 lp_set_cmdline("smb ports", poptGetOptArg(pc));
566 if (strcmp(target, "samba3") == 0) {
567 lp_set_cmdline("torture:samba3", "true");
568 } else if (strcmp(target, "samba4") == 0) {
569 lp_set_cmdline("torture:samba4", "true");
573 /* this will only work if nobody else uses alarm(),
574 which means it won't work for some tests, but we
575 can't use the event context method we use for smbd
576 as so many tests create their own event
577 context. This will at least catch most cases. */
578 signal(SIGALRM, max_runtime_handler);
584 if (extra_module != NULL) {
585 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
588 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
591 if (NT_STATUS_IS_ERR(status)) {
592 d_printf("Error initializing module %s: %s\n",
593 poptGetOptArg(pc), nt_errstr(status));
605 if (torture_seed == 0) {
606 torture_seed = time(NULL);
608 printf("Using seed %d\n", torture_seed);
609 srandom(torture_seed);
611 argv_new = discard_const_p(char *, poptGetArgs(pc));
614 for (i=0; i<argc; i++) {
615 if (argv_new[i] == NULL) {
621 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
626 /* see if its a RPC transport specifier */
627 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
628 status = dcerpc_parse_binding(talloc_autofree_context(), argv_new[1], &binding_struct);
629 if (NT_STATUS_IS_ERR(status)) {
630 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
634 lp_set_cmdline("torture:host", binding_struct->host);
635 lp_set_cmdline("torture:share", "IPC$");
636 lp_set_cmdline("torture:binding", argv_new[1]);
638 lp_set_cmdline("torture:host", host);
639 lp_set_cmdline("torture:share", share);
640 lp_set_cmdline("torture:binding", host);
643 if (!strcmp(ui_ops_name, "simple")) {
644 ui_ops = &std_ui_ops;
645 } else if (!strcmp(ui_ops_name, "subunit")) {
646 ui_ops = &subunit_ui_ops;
647 } else if (!strcmp(ui_ops_name, "quiet")) {
648 ui_ops = &quiet_ui_ops;
650 printf("Unknown output format '%s'\n", ui_ops_name);
654 torture = torture_context_init(talloc_autofree_context(), ui_ops);
655 if (basedir != NULL) {
656 if (basedir[0] != '/') {
657 fprintf(stderr, "Please specify an absolute path to --basedir\n");
660 torture->outputdir = basedir;
662 char *pwd = talloc_size(torture, PATH_MAX);
663 if (!getcwd(pwd, PATH_MAX)) {
664 fprintf(stderr, "Unable to determine current working directory\n");
667 torture->outputdir = pwd;
671 printf("You must specify a test to run, or 'ALL'\n");
675 for (i=2;i<argc_new;i++) {
676 if (!run_test(torture, argv_new[i])) {
682 if (torture->returncode && correct) {