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/smbtorture.h"
35 #include "lib/util/dlinklist.h"
36 #include "librpc/rpc/dcerpc.h"
37 #include "param/param.h"
39 #include "auth/credentials/credentials.h"
41 static bool run_matching(struct torture_context *torture,
44 struct torture_suite *suite,
50 struct torture_suite *o;
52 for (o = torture_root->children; o; o = o->next) {
53 if (gen_fnmatch(expr, o->name) == 0) {
55 reload_charcnv(torture->lp_ctx);
56 ret &= torture_run_suite(torture, o);
60 ret &= run_matching(torture, o->name, expr, o, matched);
64 struct torture_suite *c;
65 struct torture_tcase *t;
67 for (c = suite->children; c; c = c->next) {
68 asprintf(&name, "%s-%s", prefix, c->name);
70 if (gen_fnmatch(expr, name) == 0) {
72 reload_charcnv(torture->lp_ctx);
73 torture->active_testname = talloc_strdup(torture, prefix);
74 ret &= torture_run_suite(torture, c);
79 ret &= run_matching(torture, name, expr, c, matched);
84 for (t = suite->testcases; t; t = t->next) {
85 asprintf(&name, "%s-%s", prefix, t->name);
86 if (gen_fnmatch(expr, name) == 0) {
88 reload_charcnv(torture->lp_ctx);
89 torture->active_testname = talloc_strdup(torture, prefix);
90 ret &= torture_run_tcase(torture, t);
91 talloc_free(torture->active_testname);
100 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
102 /****************************************************************************
103 run a specified test or "ALL"
104 ****************************************************************************/
105 static bool run_test(struct torture_context *torture, const char *name)
108 bool matched = false;
109 struct torture_suite *o;
111 if (strequal(name, "ALL")) {
112 for (o = torture_root->children; o; o = o->next) {
113 ret &= torture_run_suite(torture, o);
118 ret = run_matching(torture, NULL, name, NULL, &matched);
121 printf("Unknown torture operation '%s'\n", name);
128 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
130 char *host = NULL, *share = NULL;
131 struct dcerpc_binding *binding_struct;
134 /* see if its a RPC transport specifier */
135 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
136 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
137 if (NT_STATUS_IS_ERR(status)) {
138 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
141 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
142 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
143 lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
144 lp_set_cmdline(lp_ctx, "torture:binding", target);
146 lp_set_cmdline(lp_ctx, "torture:host", host);
147 lp_set_cmdline(lp_ctx, "torture:share", share);
148 lp_set_cmdline(lp_ctx, "torture:binding", host);
154 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
156 char *userdn, *basedn, *secret;
159 /* retrievieng the userdn */
160 p = strchr_m(dns, '#');
162 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
163 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
164 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
167 userdn = strndup(dns, p - dns);
168 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
170 /* retrieve the basedn */
172 p = strchr_m(d, '#');
174 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
175 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
178 basedn = strndup(d, p - d);
179 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
181 /* retrieve the secret */
184 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
188 lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
190 printf ("%s - %s - %s\n", userdn, basedn, secret);
194 static void print_test_list(void)
196 struct torture_suite *o;
197 struct torture_suite *s;
198 struct torture_tcase *t;
200 if (torture_root == NULL)
203 for (o = torture_root->children; o; o = o->next) {
204 for (s = o->children; s; s = s->next) {
205 printf("%s-%s\n", o->name, s->name);
208 for (t = o->testcases; t; t = t->next) {
209 printf("%s-%s\n", o->name, t->name);
214 _NORETURN_ static void usage(poptContext pc)
216 struct torture_suite *o;
217 struct torture_suite *s;
218 struct torture_tcase *t;
221 poptPrintUsage(pc, stdout, 0);
224 printf("The binding format is:\n\n");
226 printf(" TRANSPORT:host[flags]\n\n");
228 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
229 printf(" or ncalrpc for local connections.\n\n");
231 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
232 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
233 printf(" string.\n\n");
235 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
236 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
237 printf(" will be auto-determined.\n\n");
239 printf(" other recognised flags are:\n\n");
241 printf(" sign : enable ntlmssp signing\n");
242 printf(" seal : enable ntlmssp sealing\n");
243 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
244 printf(" validate: enable the NDR validator\n");
245 printf(" print: enable debugging of the packets\n");
246 printf(" bigendian: use bigendian RPC\n");
247 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
249 printf(" For example, these all connect to the samr pipe:\n\n");
251 printf(" ncacn_np:myserver\n");
252 printf(" ncacn_np:myserver[samr]\n");
253 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
254 printf(" ncacn_np:myserver[/pipe/samr]\n");
255 printf(" ncacn_np:myserver[samr,sign,print]\n");
256 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
257 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
258 printf(" ncacn_np:\n");
259 printf(" ncacn_np:[/pipe/samr]\n\n");
261 printf(" ncacn_ip_tcp:myserver\n");
262 printf(" ncacn_ip_tcp:myserver[1024]\n");
263 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
265 printf(" ncalrpc:\n\n");
267 printf("The UNC format is:\n\n");
269 printf(" //server/share\n\n");
271 printf("Tests are:");
273 if (torture_root == NULL) {
274 printf("NO TESTS LOADED\n");
278 for (o = torture_root->children; o; o = o->next) {
279 printf("\n%s (%s):\n ", o->description, o->name);
282 for (s = o->children; s; s = s->next) {
283 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
287 i+=printf("%s-%s ", o->name, s->name);
290 for (t = o->testcases; t; t = t->next) {
291 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
295 i+=printf("%s-%s ", o->name, t->name);
301 printf("\nThe default test is ALL.\n");
306 _NORETURN_ static void max_runtime_handler(int sig)
308 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
312 struct timeval last_suite_started;
314 static void simple_suite_start(struct torture_context *ctx,
315 struct torture_suite *suite)
317 last_suite_started = timeval_current();
318 printf("Running %s\n", suite->name);
321 static void simple_suite_finish(struct torture_context *ctx,
322 struct torture_suite *suite)
325 printf("%s took %g secs\n\n", suite->name,
326 timeval_elapsed(&last_suite_started));
329 static void simple_test_result(struct torture_context *context,
330 enum torture_result res, const char *reason)
335 printf("OK: %s\n", reason);
338 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
341 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
344 printf("SKIP: %s - %s\n", context->active_test->name, reason);
349 static void simple_comment(struct torture_context *test,
352 printf("%s", comment);
355 static void simple_warning(struct torture_context *test,
358 fprintf(stderr, "WARNING: %s\n", comment);
361 const static struct torture_ui_ops std_ui_ops = {
362 .comment = simple_comment,
363 .warning = simple_warning,
364 .suite_start = simple_suite_start,
365 .suite_finish = simple_suite_finish,
366 .test_result = simple_test_result
369 static void subunit_init(struct torture_context *ctx)
371 /* FIXME: register segv and bus handler */
374 static void subunit_suite_start(struct torture_context *ctx,
375 struct torture_suite *suite)
379 static void subunit_test_start(struct torture_context *ctx,
380 struct torture_tcase *tcase,
381 struct torture_test *test)
383 printf("test: %s\n", test->name);
386 static void subunit_test_result(struct torture_context *context,
387 enum torture_result res, const char *reason)
391 printf("success: %s", context->active_test->name);
394 printf("failure: %s", context->active_test->name);
397 printf("error: %s", context->active_test->name);
400 printf("skip: %s", context->active_test->name);
404 printf(" [\n%s\n]", reason);
408 static void subunit_comment(struct torture_context *test,
411 fprintf(stderr, "%s", comment);
414 static void subunit_warning(struct torture_context *test,
417 fprintf(stderr, "WARNING!: %s\n", comment);
420 const static struct torture_ui_ops subunit_ui_ops = {
421 .init = subunit_init,
422 .comment = subunit_comment,
423 .warning = subunit_warning,
424 .test_start = subunit_test_start,
425 .test_result = subunit_test_result,
426 .suite_start = subunit_suite_start
429 static void quiet_suite_start(struct torture_context *ctx,
430 struct torture_suite *suite)
434 for (i = 1; i < ctx->level; i++) putchar('\t');
435 printf("%s: ", suite->name);
439 static void quiet_suite_finish(struct torture_context *ctx,
440 struct torture_suite *suite)
445 static void quiet_test_result(struct torture_context *context,
446 enum torture_result res, const char *reason)
450 case TORTURE_OK: putchar('.'); break;
451 case TORTURE_FAIL: putchar('F'); break;
452 case TORTURE_ERROR: putchar('E'); break;
453 case TORTURE_SKIP: putchar('I'); break;
457 const static struct torture_ui_ops quiet_ui_ops = {
458 .suite_start = quiet_suite_start,
459 .suite_finish = quiet_suite_finish,
460 .test_result = quiet_test_result
463 void run_shell(struct torture_context *tctx)
471 cline = smb_readline("torture> ", NULL, NULL);
476 ret = poptParseArgvString(cline, &argc, &argv);
478 fprintf(stderr, "Error parsing line\n");
482 if (!strcmp(argv[0], "quit")) {
484 } else if (!strcmp(argv[0], "set")) {
486 fprintf(stderr, "Usage: set <variable> <value>\n");
488 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
489 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
492 } else if (!strcmp(argv[0], "help")) {
493 fprintf(stderr, "Available commands:\n"
494 " help - This help command\n"
496 " set - Change variables\n"
498 } else if (!strcmp(argv[0], "run")) {
500 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
502 run_test(tctx, argv[1]);
509 /****************************************************************************
511 ****************************************************************************/
512 int main(int argc,char *argv[])
518 struct torture_context *torture;
519 const struct torture_ui_ops *ui_ops;
522 static const char *target = "other";
525 static const char *ui_ops_name = "simple";
526 const char *basedir = NULL;
527 const char *extra_module = NULL;
528 static int list_tests = 0;
529 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
530 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
532 struct poptOption long_options[] = {
534 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
535 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
536 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
537 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
538 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
539 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
540 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
541 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
542 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
543 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
544 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
545 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
546 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
547 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
548 "run dangerous tests (eg. wiping out password database)", NULL},
549 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
550 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
551 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
552 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
553 "run async tests", NULL},
554 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
555 "number of simultaneous async requests", NULL},
556 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
557 "set maximum time for smbtorture to live", "seconds"},
559 POPT_COMMON_CONNECTION
560 POPT_COMMON_CREDENTIALS
567 /* we are never interested in SIGPIPE */
568 BlockSignals(true, SIGPIPE);
570 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
571 POPT_CONTEXT_KEEP_FIRST);
573 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
575 while((opt = poptGetNextOpt(pc)) != -1) {
578 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
581 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
584 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
587 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
590 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
593 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
596 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
599 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
604 if (strcmp(target, "samba3") == 0) {
605 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
606 } else if (strcmp(target, "samba4") == 0) {
607 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
611 /* this will only work if nobody else uses alarm(),
612 which means it won't work for some tests, but we
613 can't use the event context method we use for smbd
614 as so many tests create their own event
615 context. This will at least catch most cases. */
616 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(event_context_init(NULL), 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) {