2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006-2008
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/dynconfig.h"
33 #include "torture/smbtorture.h"
34 #include "../lib/util/dlinklist.h"
35 #include "librpc/rpc/dcerpc.h"
36 #include "param/param.h"
38 #include "auth/credentials/credentials.h"
40 static bool run_matching(struct torture_context *torture,
43 struct torture_suite *suite,
49 struct torture_suite *o;
51 for (o = torture_root->children; o; o = o->next) {
52 if (gen_fnmatch(expr, o->name) == 0) {
54 reload_charcnv(torture->lp_ctx);
55 ret &= torture_run_suite(torture, o);
59 ret &= run_matching(torture, o->name, expr, o, matched);
63 struct torture_suite *c;
64 struct torture_tcase *t;
66 for (c = suite->children; c; c = c->next) {
67 asprintf(&name, "%s-%s", prefix, c->name);
69 if (gen_fnmatch(expr, name) == 0) {
71 reload_charcnv(torture->lp_ctx);
72 torture->active_testname = talloc_strdup(torture, prefix);
73 ret &= torture_run_suite(torture, c);
78 ret &= run_matching(torture, name, expr, c, matched);
83 for (t = suite->testcases; t; t = t->next) {
84 asprintf(&name, "%s-%s", prefix, t->name);
85 if (gen_fnmatch(expr, name) == 0) {
87 reload_charcnv(torture->lp_ctx);
88 torture->active_testname = talloc_strdup(torture, prefix);
89 ret &= torture_run_tcase(torture, t);
90 talloc_free(torture->active_testname);
99 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
101 /****************************************************************************
102 run a specified test or "ALL"
103 ****************************************************************************/
104 static bool run_test(struct torture_context *torture, const char *name)
107 bool matched = false;
108 struct torture_suite *o;
110 if (strequal(name, "ALL")) {
111 for (o = torture_root->children; o; o = o->next) {
112 ret &= torture_run_suite(torture, o);
117 ret = run_matching(torture, NULL, name, NULL, &matched);
120 printf("Unknown torture operation '%s'\n", name);
127 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
129 char *host = NULL, *share = NULL;
130 struct dcerpc_binding *binding_struct;
133 /* see if its a RPC transport specifier */
134 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
135 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
136 if (NT_STATUS_IS_ERR(status)) {
137 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
140 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
141 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
142 lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
143 lp_set_cmdline(lp_ctx, "torture:binding", target);
145 lp_set_cmdline(lp_ctx, "torture:host", host);
146 lp_set_cmdline(lp_ctx, "torture:share", share);
147 lp_set_cmdline(lp_ctx, "torture:binding", host);
153 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
155 char *userdn, *basedn, *secret;
158 /* retrievieng the userdn */
159 p = strchr_m(dns, '#');
161 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
162 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
163 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
166 userdn = strndup(dns, p - dns);
167 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
169 /* retrieve the basedn */
171 p = strchr_m(d, '#');
173 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
174 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
177 basedn = strndup(d, p - d);
178 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
180 /* retrieve the secret */
183 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
187 lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
189 printf ("%s - %s - %s\n", userdn, basedn, secret);
193 static void print_test_list(void)
195 struct torture_suite *o;
196 struct torture_suite *s;
197 struct torture_tcase *t;
199 if (torture_root == NULL)
202 for (o = torture_root->children; o; o = o->next) {
203 for (s = o->children; s; s = s->next) {
204 printf("%s-%s\n", o->name, s->name);
207 for (t = o->testcases; t; t = t->next) {
208 printf("%s-%s\n", o->name, t->name);
213 _NORETURN_ static void usage(poptContext pc)
215 struct torture_suite *o;
216 struct torture_suite *s;
217 struct torture_tcase *t;
220 poptPrintUsage(pc, stdout, 0);
223 printf("The binding format is:\n\n");
225 printf(" TRANSPORT:host[flags]\n\n");
227 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
228 printf(" or ncalrpc for local connections.\n\n");
230 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
231 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
232 printf(" string.\n\n");
234 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
235 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
236 printf(" will be auto-determined.\n\n");
238 printf(" other recognised flags are:\n\n");
240 printf(" sign : enable ntlmssp signing\n");
241 printf(" seal : enable ntlmssp sealing\n");
242 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
243 printf(" validate: enable the NDR validator\n");
244 printf(" print: enable debugging of the packets\n");
245 printf(" bigendian: use bigendian RPC\n");
246 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
248 printf(" For example, these all connect to the samr pipe:\n\n");
250 printf(" ncacn_np:myserver\n");
251 printf(" ncacn_np:myserver[samr]\n");
252 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
253 printf(" ncacn_np:myserver[/pipe/samr]\n");
254 printf(" ncacn_np:myserver[samr,sign,print]\n");
255 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
256 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
257 printf(" ncacn_np:\n");
258 printf(" ncacn_np:[/pipe/samr]\n\n");
260 printf(" ncacn_ip_tcp:myserver\n");
261 printf(" ncacn_ip_tcp:myserver[1024]\n");
262 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
264 printf(" ncalrpc:\n\n");
266 printf("The UNC format is:\n\n");
268 printf(" //server/share\n\n");
270 printf("Tests are:");
272 if (torture_root == NULL) {
273 printf("NO TESTS LOADED\n");
277 for (o = torture_root->children; o; o = o->next) {
278 printf("\n%s (%s):\n ", o->description, o->name);
281 for (s = o->children; s; s = s->next) {
282 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
286 i+=printf("%s-%s ", o->name, s->name);
289 for (t = o->testcases; t; t = t->next) {
290 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
294 i+=printf("%s-%s ", o->name, t->name);
300 printf("\nThe default test is ALL.\n");
305 _NORETURN_ static void max_runtime_handler(int sig)
307 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
311 struct timeval last_suite_started;
313 static void simple_suite_start(struct torture_context *ctx,
314 struct torture_suite *suite)
316 last_suite_started = timeval_current();
317 printf("Running %s\n", suite->name);
320 static void simple_suite_finish(struct torture_context *ctx,
321 struct torture_suite *suite)
324 printf("%s took %g secs\n\n", suite->name,
325 timeval_elapsed(&last_suite_started));
328 static void simple_test_result(struct torture_context *context,
329 enum torture_result res, const char *reason)
334 printf("OK: %s\n", reason);
337 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
340 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
343 printf("SKIP: %s - %s\n", context->active_test->name, reason);
348 static void simple_comment(struct torture_context *test,
351 printf("%s", comment);
354 static void simple_warning(struct torture_context *test,
357 fprintf(stderr, "WARNING: %s\n", comment);
360 const static struct torture_ui_ops std_ui_ops = {
361 .comment = simple_comment,
362 .warning = simple_warning,
363 .suite_start = simple_suite_start,
364 .suite_finish = simple_suite_finish,
365 .test_result = simple_test_result
368 static void subunit_init(struct torture_context *ctx)
370 /* FIXME: register segv and bus handler */
373 static void subunit_suite_start(struct torture_context *ctx,
374 struct torture_suite *suite)
378 static void subunit_print_testname(struct torture_context *ctx,
379 struct torture_tcase *tcase,
380 struct torture_test *test)
382 if (!strcmp(tcase->name, test->name)) {
383 printf("%s", test->name);
385 printf("%s.%s", tcase->name, test->name);
389 static void subunit_test_start(struct torture_context *ctx,
390 struct torture_tcase *tcase,
391 struct torture_test *test)
394 subunit_print_testname(ctx, tcase, test);
398 static void subunit_test_result(struct torture_context *context,
399 enum torture_result res, const char *reason)
415 subunit_print_testname(context, context->active_tcase, context->active_test);
418 printf(" [\n%s\n]", reason);
422 static void subunit_comment(struct torture_context *test,
425 fprintf(stderr, "%s", comment);
428 static void subunit_warning(struct torture_context *test,
431 fprintf(stderr, "WARNING!: %s\n", comment);
434 const static struct torture_ui_ops subunit_ui_ops = {
435 .init = subunit_init,
436 .comment = subunit_comment,
437 .warning = subunit_warning,
438 .test_start = subunit_test_start,
439 .test_result = subunit_test_result,
440 .suite_start = subunit_suite_start
443 static void quiet_suite_start(struct torture_context *ctx,
444 struct torture_suite *suite)
448 for (i = 1; i < ctx->level; i++) putchar('\t');
449 printf("%s: ", suite->name);
453 static void quiet_suite_finish(struct torture_context *ctx,
454 struct torture_suite *suite)
459 static void quiet_test_result(struct torture_context *context,
460 enum torture_result res, const char *reason)
464 case TORTURE_OK: putchar('.'); break;
465 case TORTURE_FAIL: putchar('F'); break;
466 case TORTURE_ERROR: putchar('E'); break;
467 case TORTURE_SKIP: putchar('I'); break;
471 const static struct torture_ui_ops quiet_ui_ops = {
472 .suite_start = quiet_suite_start,
473 .suite_finish = quiet_suite_finish,
474 .test_result = quiet_test_result
477 void run_shell(struct torture_context *tctx)
485 cline = smb_readline("torture> ", NULL, NULL);
490 ret = poptParseArgvString(cline, &argc, &argv);
492 fprintf(stderr, "Error parsing line\n");
496 if (!strcmp(argv[0], "quit")) {
498 } else if (!strcmp(argv[0], "set")) {
500 fprintf(stderr, "Usage: set <variable> <value>\n");
502 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
503 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
506 } else if (!strcmp(argv[0], "help")) {
507 fprintf(stderr, "Available commands:\n"
508 " help - This help command\n"
510 " set - Change variables\n"
512 } else if (!strcmp(argv[0], "run")) {
514 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
516 run_test(tctx, argv[1]);
523 /****************************************************************************
525 ****************************************************************************/
526 int main(int argc,char *argv[])
532 struct torture_context *torture;
533 const struct torture_ui_ops *ui_ops;
536 static const char *target = "other";
539 static const char *ui_ops_name = "simple";
540 const char *basedir = NULL;
541 const char *extra_module = NULL;
542 static int list_tests = 0;
543 int num_extra_users = 0;
544 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
545 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,OPT_EXTRA_USER};
547 struct poptOption long_options[] = {
549 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
550 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
551 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
552 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
553 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
554 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
555 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
556 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
557 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
558 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
559 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
560 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
561 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
562 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
563 "run dangerous tests (eg. wiping out password database)", NULL},
564 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
565 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
566 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
567 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
568 "run async tests", NULL},
569 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
570 "number of simultaneous async requests", NULL},
571 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
572 "set maximum time for smbtorture to live", "seconds"},
573 {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
574 "extra user credentials", NULL},
576 POPT_COMMON_CONNECTION
577 POPT_COMMON_CREDENTIALS
584 /* we are never interested in SIGPIPE */
585 BlockSignals(true, SIGPIPE);
587 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
588 POPT_CONTEXT_KEEP_FIRST);
590 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
592 while((opt = poptGetNextOpt(pc)) != -1) {
595 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
598 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
601 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
604 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
607 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
610 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
613 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
616 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
620 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
622 char *value = poptGetOptArg(pc);
623 lp_set_cmdline(cmdline_lp_ctx, option, value);
630 if (strcmp(target, "samba3") == 0) {
631 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
632 } else if (strcmp(target, "samba4") == 0) {
633 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
637 /* this will only work if nobody else uses alarm(),
638 which means it won't work for some tests, but we
639 can't use the event context method we use for smbd
640 as so many tests create their own event
641 context. This will at least catch most cases. */
642 signal(SIGALRM, max_runtime_handler);
646 if (extra_module != NULL) {
647 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
650 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
653 if (NT_STATUS_IS_ERR(status)) {
654 d_printf("Error initializing module %s: %s\n",
655 poptGetOptArg(pc), nt_errstr(status));
667 if (torture_seed == 0) {
668 torture_seed = time(NULL);
670 printf("Using seed %d\n", torture_seed);
671 srandom(torture_seed);
673 argv_new = discard_const_p(char *, poptGetArgs(pc));
676 for (i=0; i<argc; i++) {
677 if (argv_new[i] == NULL) {
683 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
688 if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
693 if (!strcmp(ui_ops_name, "simple")) {
694 ui_ops = &std_ui_ops;
695 } else if (!strcmp(ui_ops_name, "subunit")) {
696 ui_ops = &subunit_ui_ops;
697 } else if (!strcmp(ui_ops_name, "quiet")) {
698 ui_ops = &quiet_ui_ops;
700 printf("Unknown output format '%s'\n", ui_ops_name);
704 torture = torture_context_init(s4_event_context_init(NULL), ui_ops);
705 if (basedir != NULL) {
706 if (basedir[0] != '/') {
707 fprintf(stderr, "Please specify an absolute path to --basedir\n");
710 torture->outputdir = basedir;
712 char *pwd = talloc_size(torture, PATH_MAX);
713 if (!getcwd(pwd, PATH_MAX)) {
714 fprintf(stderr, "Unable to determine current working directory\n");
717 torture->outputdir = pwd;
720 torture->lp_ctx = cmdline_lp_ctx;
723 printf("You must specify a test to run, or 'ALL'\n");
727 for (i=2;i<argc_new;i++) {
728 if (!run_test(torture, argv_new[i])) {
734 if (torture->returncode && correct) {