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) {
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) {
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) {
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 void parse_dns(const char *dns)
128 char *userdn, *basedn, *secret;
131 /* retrievieng the userdn */
132 p = strchr_m(dns, '#');
134 lp_set_cmdline(global_loadparm, "torture:ldap_userdn", "");
135 lp_set_cmdline(global_loadparm, "torture:ldap_basedn", "");
136 lp_set_cmdline(global_loadparm, "torture:ldap_secret", "");
139 userdn = strndup(dns, p - dns);
140 lp_set_cmdline(global_loadparm, "torture:ldap_userdn", userdn);
142 /* retrieve the basedn */
144 p = strchr_m(d, '#');
146 lp_set_cmdline(global_loadparm, "torture:ldap_basedn", "");
147 lp_set_cmdline(global_loadparm, "torture:ldap_secret", "");
150 basedn = strndup(d, p - d);
151 lp_set_cmdline(global_loadparm, "torture:ldap_basedn", basedn);
153 /* retrieve the secret */
156 lp_set_cmdline(global_loadparm, "torture:ldap_secret", "");
160 lp_set_cmdline(global_loadparm, "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 _NORETURN_ static void usage(poptContext pc)
185 struct torture_suite *o;
186 struct torture_suite *s;
187 struct torture_tcase *t;
190 poptPrintUsage(pc, stdout, 0);
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 if (torture_root == NULL) {
243 printf("NO TESTS LOADED\n");
247 for (o = torture_root->children; o; o = o->next) {
248 printf("\n%s (%s):\n ", o->description, o->name);
251 for (s = o->children; s; s = s->next) {
252 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
256 i+=printf("%s-%s ", o->name, s->name);
259 for (t = o->testcases; t; t = t->next) {
260 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
264 i+=printf("%s-%s ", o->name, t->name);
270 printf("\nThe default test is ALL.\n");
275 _NORETURN_ static void max_runtime_handler(int sig)
277 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
281 struct timeval last_suite_started;
283 static void simple_suite_start(struct torture_context *ctx,
284 struct torture_suite *suite)
286 last_suite_started = timeval_current();
287 printf("Running %s\n", suite->name);
290 static void simple_suite_finish(struct torture_context *ctx,
291 struct torture_suite *suite)
294 printf("%s took %g secs\n\n", suite->name,
295 timeval_elapsed(&last_suite_started));
298 static void simple_test_result(struct torture_context *context,
299 enum torture_result res, const char *reason)
304 printf("OK: %s\n", reason);
307 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
310 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
313 printf("SKIP: %s - %s\n", context->active_test->name, reason);
318 static void simple_comment(struct torture_context *test,
321 printf("%s", comment);
324 static void simple_warning(struct torture_context *test,
327 fprintf(stderr, "WARNING: %s\n", comment);
330 const static struct torture_ui_ops std_ui_ops = {
331 .comment = simple_comment,
332 .warning = simple_warning,
333 .suite_start = simple_suite_start,
334 .suite_finish = simple_suite_finish,
335 .test_result = simple_test_result
338 static void subunit_init(struct torture_context *ctx)
340 /* FIXME: register segv and bus handler */
343 static void subunit_suite_start(struct torture_context *ctx,
344 struct torture_suite *suite)
348 static void subunit_test_start(struct torture_context *ctx,
349 struct torture_tcase *tcase,
350 struct torture_test *test)
352 printf("test: %s\n", test->name);
355 static void subunit_test_result(struct torture_context *context,
356 enum torture_result res, const char *reason)
360 printf("success: %s", context->active_test->name);
363 printf("failure: %s", context->active_test->name);
366 printf("error: %s", context->active_test->name);
369 printf("skip: %s", context->active_test->name);
373 printf(" [\n%s\n]", reason);
377 static void subunit_comment(struct torture_context *test,
380 fprintf(stderr, "%s", comment);
383 static void subunit_warning(struct torture_context *test,
386 fprintf(stderr, "WARNING!: %s\n", comment);
389 const static struct torture_ui_ops subunit_ui_ops = {
390 .init = subunit_init,
391 .comment = subunit_comment,
392 .warning = subunit_warning,
393 .test_start = subunit_test_start,
394 .test_result = subunit_test_result,
395 .suite_start = subunit_suite_start
398 static void quiet_suite_start(struct torture_context *ctx,
399 struct torture_suite *suite)
403 for (i = 1; i < ctx->level; i++) putchar('\t');
404 printf("%s: ", suite->name);
408 static void quiet_suite_finish(struct torture_context *ctx,
409 struct torture_suite *suite)
414 static void quiet_test_result(struct torture_context *context,
415 enum torture_result res, const char *reason)
419 case TORTURE_OK: putchar('.'); break;
420 case TORTURE_FAIL: putchar('F'); break;
421 case TORTURE_ERROR: putchar('E'); break;
422 case TORTURE_SKIP: putchar('I'); break;
426 const static struct torture_ui_ops quiet_ui_ops = {
427 .suite_start = quiet_suite_start,
428 .suite_finish = quiet_suite_finish,
429 .test_result = quiet_test_result
432 void run_shell(struct torture_context *tctx)
440 cline = smb_readline("torture> ", NULL, NULL);
445 ret = poptParseArgvString(cline, &argc, &argv);
447 fprintf(stderr, "Error parsing line\n");
451 if (!strcmp(argv[0], "quit")) {
453 } else if (!strcmp(argv[0], "set")) {
455 fprintf(stderr, "Usage: set <variable> <value>\n");
457 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
458 lp_set_cmdline(global_loadparm, name, argv[2]);
461 } else if (!strcmp(argv[0], "help")) {
462 fprintf(stderr, "Available commands:\n"
463 " help - This help command\n"
465 " set - Change variables\n"
467 } else if (!strcmp(argv[0], "run")) {
469 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
471 run_test(tctx, argv[1]);
477 /****************************************************************************
479 ****************************************************************************/
480 int main(int argc,char *argv[])
486 struct torture_context *torture;
487 const struct torture_ui_ops *ui_ops;
490 static const char *target = "other";
491 struct dcerpc_binding *binding_struct;
494 static const char *ui_ops_name = "simple";
495 const char *basedir = NULL;
496 const char *extra_module = NULL;
497 static int list_tests = 0;
498 char *host = NULL, *share = NULL;
499 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
500 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
502 struct poptOption long_options[] = {
504 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
505 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
506 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
507 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
508 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
509 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
510 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
511 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
512 {"list", 0, POPT_ARG_NONE, &list_tests, 0, NULL, NULL },
513 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
514 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "timelimit", NULL},
515 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
516 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
517 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
518 "run dangerous tests (eg. wiping out password database)", NULL},
519 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
520 {"shell", 0, POPT_ARG_NONE, &shell, True, "Run shell", NULL},
521 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
522 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
523 "run async tests", NULL},
524 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
525 "number of simultaneous async requests", NULL},
526 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
527 "set maximum time for smbtorture to live", "seconds"},
529 POPT_COMMON_CONNECTION
530 POPT_COMMON_CREDENTIALS
537 /* we are never interested in SIGPIPE */
538 BlockSignals(true, SIGPIPE);
540 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
541 POPT_CONTEXT_KEEP_FIRST);
543 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
545 while((opt = poptGetNextOpt(pc)) != -1) {
548 lp_set_cmdline(global_loadparm, "torture:loadfile", poptGetOptArg(pc));
551 lp_set_cmdline(global_loadparm, "torture:unclist", poptGetOptArg(pc));
554 lp_set_cmdline(global_loadparm, "torture:timelimit", poptGetOptArg(pc));
557 lp_set_cmdline(global_loadparm, "torture:nprocs", poptGetOptArg(pc));
560 parse_dns(poptGetOptArg(pc));
563 lp_set_cmdline(global_loadparm, "torture:dangerous", "Yes");
566 lp_set_cmdline(global_loadparm, "torture:async", "Yes");
569 lp_set_cmdline(global_loadparm, "smb ports", poptGetOptArg(pc));
574 if (strcmp(target, "samba3") == 0) {
575 lp_set_cmdline(global_loadparm, "torture:samba3", "true");
576 } else if (strcmp(target, "samba4") == 0) {
577 lp_set_cmdline(global_loadparm, "torture:samba4", "true");
581 /* this will only work if nobody else uses alarm(),
582 which means it won't work for some tests, but we
583 can't use the event context method we use for smbd
584 as so many tests create their own event
585 context. This will at least catch most cases. */
586 signal(SIGALRM, max_runtime_handler);
592 if (extra_module != NULL) {
593 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
596 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
599 if (NT_STATUS_IS_ERR(status)) {
600 d_printf("Error initializing module %s: %s\n",
601 poptGetOptArg(pc), nt_errstr(status));
613 if (torture_seed == 0) {
614 torture_seed = time(NULL);
616 printf("Using seed %d\n", torture_seed);
617 srandom(torture_seed);
619 argv_new = discard_const_p(char *, poptGetArgs(pc));
622 for (i=0; i<argc; i++) {
623 if (argv_new[i] == NULL) {
629 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
634 /* see if its a RPC transport specifier */
635 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
636 status = dcerpc_parse_binding(talloc_autofree_context(), argv_new[1], &binding_struct);
637 if (NT_STATUS_IS_ERR(status)) {
638 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
642 lp_set_cmdline(global_loadparm, "torture:host", binding_struct->host);
643 if (lp_parm_string(global_loadparm, NULL, "torture", "share") == NULL)
644 lp_set_cmdline(global_loadparm, "torture:share", "IPC$");
645 lp_set_cmdline(global_loadparm, "torture:binding", argv_new[1]);
647 lp_set_cmdline(global_loadparm, "torture:host", host);
648 lp_set_cmdline(global_loadparm, "torture:share", share);
649 lp_set_cmdline(global_loadparm, "torture:binding", host);
652 if (!strcmp(ui_ops_name, "simple")) {
653 ui_ops = &std_ui_ops;
654 } else if (!strcmp(ui_ops_name, "subunit")) {
655 ui_ops = &subunit_ui_ops;
656 } else if (!strcmp(ui_ops_name, "quiet")) {
657 ui_ops = &quiet_ui_ops;
659 printf("Unknown output format '%s'\n", ui_ops_name);
663 torture = torture_context_init(talloc_autofree_context(), ui_ops);
664 if (basedir != NULL) {
665 if (basedir[0] != '/') {
666 fprintf(stderr, "Please specify an absolute path to --basedir\n");
669 torture->outputdir = basedir;
671 char *pwd = talloc_size(torture, PATH_MAX);
672 if (!getcwd(pwd, PATH_MAX)) {
673 fprintf(stderr, "Unable to determine current working directory\n");
676 torture->outputdir = pwd;
680 printf("You must specify a test to run, or 'ALL'\n");
684 for (i=2;i<argc_new;i++) {
685 if (!run_test(torture, argv_new[i])) {
691 if (torture->returncode && correct) {