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("torture:ldap_userdn", "");
135 lp_set_cmdline("torture:ldap_basedn", "");
136 lp_set_cmdline("torture:ldap_secret", "");
139 userdn = strndup(dns, p - dns);
140 lp_set_cmdline("torture:ldap_userdn", userdn);
142 /* retrieve the basedn */
144 p = strchr_m(d, '#');
146 lp_set_cmdline("torture:ldap_basedn", "");
147 lp_set_cmdline("torture:ldap_secret", "");
150 basedn = strndup(d, p - d);
151 lp_set_cmdline("torture:ldap_basedn", basedn);
153 /* retrieve the secret */
156 lp_set_cmdline("torture:ldap_secret", "");
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 _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 const static struct torture_ui_ops subunit_ui_ops = {
384 .init = subunit_init,
385 .comment = subunit_comment,
386 .test_start = subunit_test_start,
387 .test_result = subunit_test_result,
388 .suite_start = subunit_suite_start
391 static void quiet_suite_start(struct torture_context *ctx,
392 struct torture_suite *suite)
396 for (i = 1; i < ctx->level; i++) putchar('\t');
397 printf("%s: ", suite->name);
401 static void quiet_suite_finish(struct torture_context *ctx,
402 struct torture_suite *suite)
407 static void quiet_test_result (struct torture_context *context,
408 enum torture_result res, const char *reason)
412 case TORTURE_OK: putchar('.'); break;
413 case TORTURE_FAIL: putchar('F'); break;
414 case TORTURE_ERROR: putchar('E'); break;
415 case TORTURE_SKIP: putchar('I'); break;
419 const static struct torture_ui_ops quiet_ui_ops = {
420 .suite_start = quiet_suite_start,
421 .suite_finish = quiet_suite_finish,
422 .test_result = quiet_test_result
425 void run_shell(struct torture_context *tctx)
433 cline = smb_readline("torture> ", NULL, NULL);
438 ret = poptParseArgvString(cline, &argc, &argv);
440 fprintf(stderr, "Error parsing line\n");
444 if (!strcmp(argv[0], "quit")) {
446 } else if (!strcmp(argv[0], "set")) {
448 fprintf(stderr, "Usage: set <variable> <value>\n");
450 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
451 lp_set_cmdline(name, argv[2]);
454 } else if (!strcmp(argv[0], "help")) {
455 fprintf(stderr, "Available commands:\n"
456 " help - This help command\n"
458 " set - Change variables\n"
460 } else if (!strcmp(argv[0], "run")) {
462 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
464 run_test(tctx, argv[1]);
470 /****************************************************************************
472 ****************************************************************************/
473 int main(int argc,char *argv[])
479 struct torture_context *torture;
480 const struct torture_ui_ops *ui_ops;
483 static const char *target = "other";
484 struct dcerpc_binding *binding_struct;
487 static const char *ui_ops_name = "simple";
488 const char *basedir = NULL;
489 const char *extra_module = NULL;
490 static int list_tests = 0;
491 char *host = NULL, *share = NULL;
492 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
493 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
495 struct poptOption long_options[] = {
497 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
498 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
499 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
500 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
501 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
502 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
503 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
504 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
505 {"list", 0, POPT_ARG_NONE, &list_tests, 0, NULL, NULL },
506 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
507 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "timelimit", NULL},
508 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
509 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
510 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
511 "run dangerous tests (eg. wiping out password database)", NULL},
512 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
513 {"shell", 0, POPT_ARG_NONE, &shell, True, "Run shell", NULL},
514 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
515 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
516 "run async tests", NULL},
517 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
518 "number of simultaneous async requests", NULL},
519 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
520 "set maximum time for smbtorture to live", "seconds"},
522 POPT_COMMON_CONNECTION
523 POPT_COMMON_CREDENTIALS
530 /* we are never interested in SIGPIPE */
531 BlockSignals(true, SIGPIPE);
533 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
534 POPT_CONTEXT_KEEP_FIRST);
536 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
538 while((opt = poptGetNextOpt(pc)) != -1) {
541 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
544 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
547 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
550 lp_set_cmdline("torture:nprocs", poptGetOptArg(pc));
553 parse_dns(poptGetOptArg(pc));
556 lp_set_cmdline("torture:dangerous", "Yes");
559 lp_set_cmdline("torture:async", "Yes");
562 lp_set_cmdline("smb ports", poptGetOptArg(pc));
567 if (strcmp(target, "samba3") == 0) {
568 lp_set_cmdline("torture:samba3", "true");
569 } else if (strcmp(target, "samba4") == 0) {
570 lp_set_cmdline("torture:samba4", "true");
574 /* this will only work if nobody else uses alarm(),
575 which means it won't work for some tests, but we
576 can't use the event context method we use for smbd
577 as so many tests create their own event
578 context. This will at least catch most cases. */
579 signal(SIGALRM, max_runtime_handler);
585 if (extra_module != NULL) {
586 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
589 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
592 if (NT_STATUS_IS_ERR(status)) {
593 d_printf("Error initializing module %s: %s\n",
594 poptGetOptArg(pc), nt_errstr(status));
606 if (torture_seed == 0) {
607 torture_seed = time(NULL);
609 printf("Using seed %d\n", torture_seed);
610 srandom(torture_seed);
612 argv_new = discard_const_p(char *, poptGetArgs(pc));
615 for (i=0; i<argc; i++) {
616 if (argv_new[i] == NULL) {
622 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
627 /* see if its a RPC transport specifier */
628 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
629 status = dcerpc_parse_binding(talloc_autofree_context(), argv_new[1], &binding_struct);
630 if (NT_STATUS_IS_ERR(status)) {
631 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
635 lp_set_cmdline("torture:host", binding_struct->host);
636 if (lp_parm_string(NULL, "torture", "share") == NULL)
637 lp_set_cmdline("torture:share", "IPC$");
638 lp_set_cmdline("torture:binding", argv_new[1]);
640 lp_set_cmdline("torture:host", host);
641 lp_set_cmdline("torture:share", share);
642 lp_set_cmdline("torture:binding", host);
645 if (!strcmp(ui_ops_name, "simple")) {
646 ui_ops = &std_ui_ops;
647 } else if (!strcmp(ui_ops_name, "subunit")) {
648 ui_ops = &subunit_ui_ops;
649 } else if (!strcmp(ui_ops_name, "quiet")) {
650 ui_ops = &quiet_ui_ops;
652 printf("Unknown output format '%s'\n", ui_ops_name);
656 torture = torture_context_init(talloc_autofree_context(), ui_ops);
657 if (basedir != NULL) {
658 if (basedir[0] != '/') {
659 fprintf(stderr, "Please specify an absolute path to --basedir\n");
662 torture->outputdir = basedir;
664 char *pwd = talloc_size(torture, PATH_MAX);
665 if (!getcwd(pwd, PATH_MAX)) {
666 fprintf(stderr, "Unable to determine current working directory\n");
669 torture->outputdir = pwd;
673 printf("You must specify a test to run, or 'ALL'\n");
677 for (i=2;i<argc_new;i++) {
678 if (!run_test(torture, argv_new[i])) {
684 if (torture->returncode && correct) {