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"
37 #include "param/param.h"
39 static bool run_matching(struct torture_context *torture,
42 struct torture_suite *suite,
48 struct torture_suite *o;
50 for (o = torture_root->children; o; o = o->next) {
51 if (gen_fnmatch(expr, o->name) == 0) {
53 reload_charcnv(torture->lp_ctx);
54 ret &= torture_run_suite(torture, o);
58 ret &= run_matching(torture, o->name, expr, o, matched);
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) {
70 reload_charcnv(torture->lp_ctx);
71 torture->active_testname = talloc_strdup(torture, prefix);
72 ret &= torture_run_suite(torture, c);
77 ret &= run_matching(torture, name, expr, c, matched);
82 for (t = suite->testcases; t; t = t->next) {
83 asprintf(&name, "%s-%s", prefix, t->name);
84 if (gen_fnmatch(expr, name) == 0) {
86 reload_charcnv(torture->lp_ctx);
87 torture->active_testname = talloc_strdup(torture, prefix);
88 ret &= torture_run_tcase(torture, t);
89 talloc_free(torture->active_testname);
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)
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);
116 ret = run_matching(torture, NULL, name, NULL, &matched);
119 printf("Unknown torture operation '%s'\n", name);
126 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
128 char *host = NULL, *share = NULL;
129 struct dcerpc_binding *binding_struct;
132 /* see if its a RPC transport specifier */
133 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
134 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
135 if (NT_STATUS_IS_ERR(status)) {
136 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
139 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
140 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
141 lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
142 lp_set_cmdline(lp_ctx, "torture:binding", target);
144 lp_set_cmdline(lp_ctx, "torture:host", host);
145 lp_set_cmdline(lp_ctx, "torture:share", share);
146 lp_set_cmdline(lp_ctx, "torture:binding", host);
152 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
154 char *userdn, *basedn, *secret;
157 /* retrievieng the userdn */
158 p = strchr_m(dns, '#');
160 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
161 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
162 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
165 userdn = strndup(dns, p - dns);
166 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
168 /* retrieve the basedn */
170 p = strchr_m(d, '#');
172 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
173 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
176 basedn = strndup(d, p - d);
177 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
179 /* retrieve the secret */
182 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
186 lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
188 printf ("%s - %s - %s\n", userdn, basedn, secret);
192 static void print_test_list(void)
194 struct torture_suite *o;
195 struct torture_suite *s;
196 struct torture_tcase *t;
198 if (torture_root == NULL)
201 for (o = torture_root->children; o; o = o->next) {
202 for (s = o->children; s; s = s->next) {
203 printf("%s-%s\n", o->name, s->name);
206 for (t = o->testcases; t; t = t->next) {
207 printf("%s-%s\n", o->name, t->name);
212 _NORETURN_ static void usage(poptContext pc)
214 struct torture_suite *o;
215 struct torture_suite *s;
216 struct torture_tcase *t;
219 poptPrintUsage(pc, stdout, 0);
222 printf("The binding format is:\n\n");
224 printf(" TRANSPORT:host[flags]\n\n");
226 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
227 printf(" or ncalrpc for local connections.\n\n");
229 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
230 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
231 printf(" string.\n\n");
233 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
234 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
235 printf(" will be auto-determined.\n\n");
237 printf(" other recognised flags are:\n\n");
239 printf(" sign : enable ntlmssp signing\n");
240 printf(" seal : enable ntlmssp sealing\n");
241 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
242 printf(" validate: enable the NDR validator\n");
243 printf(" print: enable debugging of the packets\n");
244 printf(" bigendian: use bigendian RPC\n");
245 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
247 printf(" For example, these all connect to the samr pipe:\n\n");
249 printf(" ncacn_np:myserver\n");
250 printf(" ncacn_np:myserver[samr]\n");
251 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
252 printf(" ncacn_np:myserver[/pipe/samr]\n");
253 printf(" ncacn_np:myserver[samr,sign,print]\n");
254 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
255 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
256 printf(" ncacn_np:\n");
257 printf(" ncacn_np:[/pipe/samr]\n\n");
259 printf(" ncacn_ip_tcp:myserver\n");
260 printf(" ncacn_ip_tcp:myserver[1024]\n");
261 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
263 printf(" ncalrpc:\n\n");
265 printf("The UNC format is:\n\n");
267 printf(" //server/share\n\n");
269 printf("Tests are:");
271 if (torture_root == NULL) {
272 printf("NO TESTS LOADED\n");
276 for (o = torture_root->children; o; o = o->next) {
277 printf("\n%s (%s):\n ", o->description, o->name);
280 for (s = o->children; s; s = s->next) {
281 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
285 i+=printf("%s-%s ", o->name, s->name);
288 for (t = o->testcases; t; t = t->next) {
289 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
293 i+=printf("%s-%s ", o->name, t->name);
299 printf("\nThe default test is ALL.\n");
304 _NORETURN_ static void max_runtime_handler(int sig)
306 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
310 struct timeval last_suite_started;
312 static void simple_suite_start(struct torture_context *ctx,
313 struct torture_suite *suite)
315 last_suite_started = timeval_current();
316 printf("Running %s\n", suite->name);
319 static void simple_suite_finish(struct torture_context *ctx,
320 struct torture_suite *suite)
323 printf("%s took %g secs\n\n", suite->name,
324 timeval_elapsed(&last_suite_started));
327 static void simple_test_result(struct torture_context *context,
328 enum torture_result res, const char *reason)
333 printf("OK: %s\n", reason);
336 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
339 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
342 printf("SKIP: %s - %s\n", context->active_test->name, reason);
347 static void simple_comment(struct torture_context *test,
350 printf("%s", comment);
353 static void simple_warning(struct torture_context *test,
356 fprintf(stderr, "WARNING: %s\n", comment);
359 const static struct torture_ui_ops std_ui_ops = {
360 .comment = simple_comment,
361 .warning = simple_warning,
362 .suite_start = simple_suite_start,
363 .suite_finish = simple_suite_finish,
364 .test_result = simple_test_result
367 static void subunit_init(struct torture_context *ctx)
369 /* FIXME: register segv and bus handler */
372 static void subunit_suite_start(struct torture_context *ctx,
373 struct torture_suite *suite)
377 static void subunit_test_start(struct torture_context *ctx,
378 struct torture_tcase *tcase,
379 struct torture_test *test)
381 printf("test: %s\n", test->name);
384 static void subunit_test_result(struct torture_context *context,
385 enum torture_result res, const char *reason)
389 printf("success: %s", context->active_test->name);
392 printf("failure: %s", context->active_test->name);
395 printf("error: %s", context->active_test->name);
398 printf("skip: %s", context->active_test->name);
402 printf(" [\n%s\n]", reason);
406 static void subunit_comment(struct torture_context *test,
409 fprintf(stderr, "%s", comment);
412 static void subunit_warning(struct torture_context *test,
415 fprintf(stderr, "WARNING!: %s\n", comment);
418 const static struct torture_ui_ops subunit_ui_ops = {
419 .init = subunit_init,
420 .comment = subunit_comment,
421 .warning = subunit_warning,
422 .test_start = subunit_test_start,
423 .test_result = subunit_test_result,
424 .suite_start = subunit_suite_start
427 static void quiet_suite_start(struct torture_context *ctx,
428 struct torture_suite *suite)
432 for (i = 1; i < ctx->level; i++) putchar('\t');
433 printf("%s: ", suite->name);
437 static void quiet_suite_finish(struct torture_context *ctx,
438 struct torture_suite *suite)
443 static void quiet_test_result(struct torture_context *context,
444 enum torture_result res, const char *reason)
448 case TORTURE_OK: putchar('.'); break;
449 case TORTURE_FAIL: putchar('F'); break;
450 case TORTURE_ERROR: putchar('E'); break;
451 case TORTURE_SKIP: putchar('I'); break;
455 const static struct torture_ui_ops quiet_ui_ops = {
456 .suite_start = quiet_suite_start,
457 .suite_finish = quiet_suite_finish,
458 .test_result = quiet_test_result
461 void run_shell(struct torture_context *tctx)
469 cline = smb_readline("torture> ", NULL, NULL);
474 ret = poptParseArgvString(cline, &argc, &argv);
476 fprintf(stderr, "Error parsing line\n");
480 if (!strcmp(argv[0], "quit")) {
482 } else if (!strcmp(argv[0], "set")) {
484 fprintf(stderr, "Usage: set <variable> <value>\n");
486 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
487 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
490 } else if (!strcmp(argv[0], "help")) {
491 fprintf(stderr, "Available commands:\n"
492 " help - This help command\n"
494 " set - Change variables\n"
496 } else if (!strcmp(argv[0], "run")) {
498 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
500 run_test(tctx, argv[1]);
507 /****************************************************************************
509 ****************************************************************************/
510 int main(int argc,char *argv[])
516 struct torture_context *torture;
517 const struct torture_ui_ops *ui_ops;
520 const char *target = "other";
523 const char *ui_ops_name = "simple";
524 const char *basedir = NULL;
525 const char *extra_module = NULL;
527 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
528 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
530 struct poptOption long_options[] = {
532 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
533 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
534 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
535 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
536 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
537 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
538 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
539 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
540 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
541 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
542 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
543 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
544 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
545 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
546 "run dangerous tests (eg. wiping out password database)", NULL},
547 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
548 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
549 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
550 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
551 "run async tests", NULL},
552 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
553 "number of simultaneous async requests", NULL},
554 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
555 "set maximum time for smbtorture to live", "seconds"},
557 POPT_COMMON_CONNECTION
558 POPT_COMMON_CREDENTIALS
565 /* we are never interested in SIGPIPE */
566 BlockSignals(true, SIGPIPE);
568 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
569 POPT_CONTEXT_KEEP_FIRST);
571 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
573 while((opt = poptGetNextOpt(pc)) != -1) {
576 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
579 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
582 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
585 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
588 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
591 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
594 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
597 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
602 if (strcmp(target, "samba3") == 0) {
603 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
604 } else if (strcmp(target, "samba4") == 0) {
605 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
609 /* this will only work if nobody else uses alarm(),
610 which means it won't work for some tests, but we
611 can't use the event context method we use for smbd
612 as so many tests create their own event
613 context. This will at least catch most cases. */
614 signal(SIGALRM, max_runtime_handler);
620 if (extra_module != NULL) {
621 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
624 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
627 if (NT_STATUS_IS_ERR(status)) {
628 d_printf("Error initializing module %s: %s\n",
629 poptGetOptArg(pc), nt_errstr(status));
641 if (torture_seed == 0) {
642 torture_seed = time(NULL);
644 printf("Using seed %d\n", torture_seed);
645 srandom(torture_seed);
647 argv_new = discard_const_p(char *, poptGetArgs(pc));
650 for (i=0; i<argc; i++) {
651 if (argv_new[i] == NULL) {
657 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
662 if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
667 if (!strcmp(ui_ops_name, "simple")) {
668 ui_ops = &std_ui_ops;
669 } else if (!strcmp(ui_ops_name, "subunit")) {
670 ui_ops = &subunit_ui_ops;
671 } else if (!strcmp(ui_ops_name, "quiet")) {
672 ui_ops = &quiet_ui_ops;
674 printf("Unknown output format '%s'\n", ui_ops_name);
678 torture = torture_context_init(talloc_autofree_context(), ui_ops);
679 if (basedir != NULL) {
680 if (basedir[0] != '/') {
681 fprintf(stderr, "Please specify an absolute path to --basedir\n");
684 torture->outputdir = basedir;
686 char *pwd = talloc_size(torture, PATH_MAX);
687 if (!getcwd(pwd, PATH_MAX)) {
688 fprintf(stderr, "Unable to determine current working directory\n");
691 torture->outputdir = pwd;
694 torture->lp_ctx = cmdline_lp_ctx;
697 printf("You must specify a test to run, or 'ALL'\n");
701 for (i=2;i<argc_new;i++) {
702 if (!run_test(torture, argv_new[i])) {
708 if (torture->returncode && correct) {