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 if (torture_root == NULL)
175 for (o = torture_root->children; o; o = o->next) {
176 for (s = o->children; s; s = s->next) {
177 printf("%s-%s\n", o->name, s->name);
180 for (t = o->testcases; t; t = t->next) {
181 printf("%s-%s\n", o->name, t->name);
186 _NORETURN_ static void usage(poptContext pc)
188 struct torture_suite *o;
189 struct torture_suite *s;
190 struct torture_tcase *t;
193 poptPrintUsage(pc, stdout, 0);
196 printf("The binding format is:\n\n");
198 printf(" TRANSPORT:host[flags]\n\n");
200 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
201 printf(" or ncalrpc for local connections.\n\n");
203 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
204 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
205 printf(" string.\n\n");
207 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
208 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
209 printf(" will be auto-determined.\n\n");
211 printf(" other recognised flags are:\n\n");
213 printf(" sign : enable ntlmssp signing\n");
214 printf(" seal : enable ntlmssp sealing\n");
215 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
216 printf(" validate: enable the NDR validator\n");
217 printf(" print: enable debugging of the packets\n");
218 printf(" bigendian: use bigendian RPC\n");
219 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
221 printf(" For example, these all connect to the samr pipe:\n\n");
223 printf(" ncacn_np:myserver\n");
224 printf(" ncacn_np:myserver[samr]\n");
225 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
226 printf(" ncacn_np:myserver[/pipe/samr]\n");
227 printf(" ncacn_np:myserver[samr,sign,print]\n");
228 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
229 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
230 printf(" ncacn_np:\n");
231 printf(" ncacn_np:[/pipe/samr]\n\n");
233 printf(" ncacn_ip_tcp:myserver\n");
234 printf(" ncacn_ip_tcp:myserver[1024]\n");
235 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
237 printf(" ncalrpc:\n\n");
239 printf("The UNC format is:\n\n");
241 printf(" //server/share\n\n");
243 printf("Tests are:");
245 if (torture_root == NULL) {
246 printf("NO TESTS LOADED\n");
250 for (o = torture_root->children; o; o = o->next) {
251 printf("\n%s (%s):\n ", o->description, o->name);
254 for (s = o->children; s; s = s->next) {
255 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
259 i+=printf("%s-%s ", o->name, s->name);
262 for (t = o->testcases; t; t = t->next) {
263 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
267 i+=printf("%s-%s ", o->name, t->name);
273 printf("\nThe default test is ALL.\n");
278 _NORETURN_ static void max_runtime_handler(int sig)
280 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
284 struct timeval last_suite_started;
286 static void simple_suite_start(struct torture_context *ctx,
287 struct torture_suite *suite)
289 last_suite_started = timeval_current();
290 printf("Running %s\n", suite->name);
293 static void simple_suite_finish(struct torture_context *ctx,
294 struct torture_suite *suite)
297 printf("%s took %g secs\n\n", suite->name,
298 timeval_elapsed(&last_suite_started));
301 static void simple_test_result(struct torture_context *context,
302 enum torture_result res, const char *reason)
307 printf("OK: %s\n", reason);
310 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
313 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
316 printf("SKIP: %s - %s\n", context->active_test->name, reason);
321 static void simple_comment(struct torture_context *test,
324 printf("%s", comment);
327 static void simple_warning(struct torture_context *test,
330 fprintf(stderr, "WARNING: %s\n", comment);
333 const static struct torture_ui_ops std_ui_ops = {
334 .comment = simple_comment,
335 .warning = simple_warning,
336 .suite_start = simple_suite_start,
337 .suite_finish = simple_suite_finish,
338 .test_result = simple_test_result
341 static void subunit_init(struct torture_context *ctx)
343 /* FIXME: register segv and bus handler */
346 static void subunit_suite_start(struct torture_context *ctx,
347 struct torture_suite *suite)
351 static void subunit_test_start(struct torture_context *ctx,
352 struct torture_tcase *tcase,
353 struct torture_test *test)
355 printf("test: %s\n", test->name);
358 static void subunit_test_result(struct torture_context *context,
359 enum torture_result res, const char *reason)
363 printf("success: %s", context->active_test->name);
366 printf("failure: %s", context->active_test->name);
369 printf("error: %s", context->active_test->name);
372 printf("skip: %s", context->active_test->name);
376 printf(" [\n%s\n]", reason);
380 static void subunit_comment(struct torture_context *test,
383 fprintf(stderr, "%s", comment);
386 static void subunit_warning(struct torture_context *test,
389 fprintf(stderr, "WARNING!: %s\n", comment);
392 const static struct torture_ui_ops subunit_ui_ops = {
393 .init = subunit_init,
394 .comment = subunit_comment,
395 .warning = subunit_warning,
396 .test_start = subunit_test_start,
397 .test_result = subunit_test_result,
398 .suite_start = subunit_suite_start
401 static void quiet_suite_start(struct torture_context *ctx,
402 struct torture_suite *suite)
406 for (i = 1; i < ctx->level; i++) putchar('\t');
407 printf("%s: ", suite->name);
411 static void quiet_suite_finish(struct torture_context *ctx,
412 struct torture_suite *suite)
417 static void quiet_test_result(struct torture_context *context,
418 enum torture_result res, const char *reason)
422 case TORTURE_OK: putchar('.'); break;
423 case TORTURE_FAIL: putchar('F'); break;
424 case TORTURE_ERROR: putchar('E'); break;
425 case TORTURE_SKIP: putchar('I'); break;
429 const static struct torture_ui_ops quiet_ui_ops = {
430 .suite_start = quiet_suite_start,
431 .suite_finish = quiet_suite_finish,
432 .test_result = quiet_test_result
435 void run_shell(struct torture_context *tctx)
443 cline = smb_readline("torture> ", NULL, NULL);
448 ret = poptParseArgvString(cline, &argc, &argv);
450 fprintf(stderr, "Error parsing line\n");
454 if (!strcmp(argv[0], "quit")) {
456 } else if (!strcmp(argv[0], "set")) {
458 fprintf(stderr, "Usage: set <variable> <value>\n");
460 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
461 lp_set_cmdline(global_loadparm, name, argv[2]);
464 } else if (!strcmp(argv[0], "help")) {
465 fprintf(stderr, "Available commands:\n"
466 " help - This help command\n"
468 " set - Change variables\n"
470 } else if (!strcmp(argv[0], "run")) {
472 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
474 run_test(tctx, argv[1]);
480 /****************************************************************************
482 ****************************************************************************/
483 int main(int argc,char *argv[])
489 struct torture_context *torture;
490 const struct torture_ui_ops *ui_ops;
493 static const char *target = "other";
494 struct dcerpc_binding *binding_struct;
497 static const char *ui_ops_name = "simple";
498 const char *basedir = NULL;
499 const char *extra_module = NULL;
500 static int list_tests = 0;
501 char *host = NULL, *share = NULL;
502 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
503 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
505 struct poptOption long_options[] = {
507 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
508 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
509 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
510 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
511 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
512 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
513 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
514 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
515 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
516 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
517 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
518 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
519 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
520 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
521 "run dangerous tests (eg. wiping out password database)", NULL},
522 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
523 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
524 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
525 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
526 "run async tests", NULL},
527 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
528 "number of simultaneous async requests", NULL},
529 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
530 "set maximum time for smbtorture to live", "seconds"},
532 POPT_COMMON_CONNECTION
533 POPT_COMMON_CREDENTIALS
540 /* we are never interested in SIGPIPE */
541 BlockSignals(true, SIGPIPE);
543 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
544 POPT_CONTEXT_KEEP_FIRST);
546 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
548 while((opt = poptGetNextOpt(pc)) != -1) {
551 lp_set_cmdline(global_loadparm, "torture:loadfile", poptGetOptArg(pc));
554 lp_set_cmdline(global_loadparm, "torture:unclist", poptGetOptArg(pc));
557 lp_set_cmdline(global_loadparm, "torture:timelimit", poptGetOptArg(pc));
560 lp_set_cmdline(global_loadparm, "torture:nprocs", poptGetOptArg(pc));
563 parse_dns(poptGetOptArg(pc));
566 lp_set_cmdline(global_loadparm, "torture:dangerous", "Yes");
569 lp_set_cmdline(global_loadparm, "torture:async", "Yes");
572 lp_set_cmdline(global_loadparm, "smb ports", poptGetOptArg(pc));
577 if (strcmp(target, "samba3") == 0) {
578 lp_set_cmdline(global_loadparm, "torture:samba3", "true");
579 } else if (strcmp(target, "samba4") == 0) {
580 lp_set_cmdline(global_loadparm, "torture:samba4", "true");
584 /* this will only work if nobody else uses alarm(),
585 which means it won't work for some tests, but we
586 can't use the event context method we use for smbd
587 as so many tests create their own event
588 context. This will at least catch most cases. */
589 signal(SIGALRM, max_runtime_handler);
595 if (extra_module != NULL) {
596 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
599 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
602 if (NT_STATUS_IS_ERR(status)) {
603 d_printf("Error initializing module %s: %s\n",
604 poptGetOptArg(pc), nt_errstr(status));
616 if (torture_seed == 0) {
617 torture_seed = time(NULL);
619 printf("Using seed %d\n", torture_seed);
620 srandom(torture_seed);
622 argv_new = discard_const_p(char *, poptGetArgs(pc));
625 for (i=0; i<argc; i++) {
626 if (argv_new[i] == NULL) {
632 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
637 /* see if its a RPC transport specifier */
638 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
639 status = dcerpc_parse_binding(talloc_autofree_context(), argv_new[1], &binding_struct);
640 if (NT_STATUS_IS_ERR(status)) {
641 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
645 lp_set_cmdline(global_loadparm, "torture:host", binding_struct->host);
646 if (lp_parm_string(global_loadparm, NULL, "torture", "share") == NULL)
647 lp_set_cmdline(global_loadparm, "torture:share", "IPC$");
648 lp_set_cmdline(global_loadparm, "torture:binding", argv_new[1]);
650 lp_set_cmdline(global_loadparm, "torture:host", host);
651 lp_set_cmdline(global_loadparm, "torture:share", share);
652 lp_set_cmdline(global_loadparm, "torture:binding", host);
655 if (!strcmp(ui_ops_name, "simple")) {
656 ui_ops = &std_ui_ops;
657 } else if (!strcmp(ui_ops_name, "subunit")) {
658 ui_ops = &subunit_ui_ops;
659 } else if (!strcmp(ui_ops_name, "quiet")) {
660 ui_ops = &quiet_ui_ops;
662 printf("Unknown output format '%s'\n", ui_ops_name);
666 torture = torture_context_init(talloc_autofree_context(), ui_ops);
667 if (basedir != NULL) {
668 if (basedir[0] != '/') {
669 fprintf(stderr, "Please specify an absolute path to --basedir\n");
672 torture->outputdir = basedir;
674 char *pwd = talloc_size(torture, PATH_MAX);
675 if (!getcwd(pwd, PATH_MAX)) {
676 fprintf(stderr, "Unable to determine current working directory\n");
679 torture->outputdir = pwd;
683 printf("You must specify a test to run, or 'ALL'\n");
687 for (i=2;i<argc_new;i++) {
688 if (!run_test(torture, argv_new[i])) {
694 if (torture->returncode && correct) {