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"
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_test_start(struct torture_context *ctx,
379 struct torture_tcase *tcase,
380 struct torture_test *test)
382 printf("test: %s\n", test->name);
385 static void subunit_test_result(struct torture_context *context,
386 enum torture_result res, const char *reason)
390 printf("success: %s", context->active_test->name);
393 printf("failure: %s", context->active_test->name);
396 printf("error: %s", context->active_test->name);
399 printf("skip: %s", context->active_test->name);
403 printf(" [\n%s\n]", reason);
407 static void subunit_comment(struct torture_context *test,
410 fprintf(stderr, "%s", comment);
413 static void subunit_warning(struct torture_context *test,
416 fprintf(stderr, "WARNING!: %s\n", comment);
419 const static struct torture_ui_ops subunit_ui_ops = {
420 .init = subunit_init,
421 .comment = subunit_comment,
422 .warning = subunit_warning,
423 .test_start = subunit_test_start,
424 .test_result = subunit_test_result,
425 .suite_start = subunit_suite_start
428 static void quiet_suite_start(struct torture_context *ctx,
429 struct torture_suite *suite)
433 for (i = 1; i < ctx->level; i++) putchar('\t');
434 printf("%s: ", suite->name);
438 static void quiet_suite_finish(struct torture_context *ctx,
439 struct torture_suite *suite)
444 static void quiet_test_result(struct torture_context *context,
445 enum torture_result res, const char *reason)
449 case TORTURE_OK: putchar('.'); break;
450 case TORTURE_FAIL: putchar('F'); break;
451 case TORTURE_ERROR: putchar('E'); break;
452 case TORTURE_SKIP: putchar('I'); break;
456 const static struct torture_ui_ops quiet_ui_ops = {
457 .suite_start = quiet_suite_start,
458 .suite_finish = quiet_suite_finish,
459 .test_result = quiet_test_result
462 void run_shell(struct torture_context *tctx)
470 cline = smb_readline("torture> ", NULL, NULL);
475 ret = poptParseArgvString(cline, &argc, &argv);
477 fprintf(stderr, "Error parsing line\n");
481 if (!strcmp(argv[0], "quit")) {
483 } else if (!strcmp(argv[0], "set")) {
485 fprintf(stderr, "Usage: set <variable> <value>\n");
487 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
488 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
491 } else if (!strcmp(argv[0], "help")) {
492 fprintf(stderr, "Available commands:\n"
493 " help - This help command\n"
495 " set - Change variables\n"
497 } else if (!strcmp(argv[0], "run")) {
499 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
501 run_test(tctx, argv[1]);
508 /****************************************************************************
510 ****************************************************************************/
511 int main(int argc,char *argv[])
517 struct torture_context *torture;
518 const struct torture_ui_ops *ui_ops;
521 static const char *target = "other";
524 static const char *ui_ops_name = "simple";
525 const char *basedir = NULL;
526 const char *extra_module = NULL;
527 static int list_tests = 0;
528 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
529 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
531 struct poptOption long_options[] = {
533 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
534 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
535 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
536 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
537 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
538 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
539 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
540 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
541 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
542 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
543 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
544 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
545 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
546 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
547 "run dangerous tests (eg. wiping out password database)", NULL},
548 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
549 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
550 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
551 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
552 "run async tests", NULL},
553 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
554 "number of simultaneous async requests", NULL},
555 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
556 "set maximum time for smbtorture to live", "seconds"},
558 POPT_COMMON_CONNECTION
559 POPT_COMMON_CREDENTIALS
566 /* we are never interested in SIGPIPE */
567 BlockSignals(true, SIGPIPE);
569 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
570 POPT_CONTEXT_KEEP_FIRST);
572 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
574 while((opt = poptGetNextOpt(pc)) != -1) {
577 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
580 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
583 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
586 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
589 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
592 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
595 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
598 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
603 if (strcmp(target, "samba3") == 0) {
604 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
605 } else if (strcmp(target, "samba4") == 0) {
606 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
610 /* this will only work if nobody else uses alarm(),
611 which means it won't work for some tests, but we
612 can't use the event context method we use for smbd
613 as so many tests create their own event
614 context. This will at least catch most cases. */
615 signal(SIGALRM, max_runtime_handler);
619 if (extra_module != NULL) {
620 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
623 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
626 if (NT_STATUS_IS_ERR(status)) {
627 d_printf("Error initializing module %s: %s\n",
628 poptGetOptArg(pc), nt_errstr(status));
640 if (torture_seed == 0) {
641 torture_seed = time(NULL);
643 printf("Using seed %d\n", torture_seed);
644 srandom(torture_seed);
646 argv_new = discard_const_p(char *, poptGetArgs(pc));
649 for (i=0; i<argc; i++) {
650 if (argv_new[i] == NULL) {
656 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
661 if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
666 if (!strcmp(ui_ops_name, "simple")) {
667 ui_ops = &std_ui_ops;
668 } else if (!strcmp(ui_ops_name, "subunit")) {
669 ui_ops = &subunit_ui_ops;
670 } else if (!strcmp(ui_ops_name, "quiet")) {
671 ui_ops = &quiet_ui_ops;
673 printf("Unknown output format '%s'\n", ui_ops_name);
677 torture = torture_context_init(event_context_init(NULL), ui_ops);
678 if (basedir != NULL) {
679 if (basedir[0] != '/') {
680 fprintf(stderr, "Please specify an absolute path to --basedir\n");
683 torture->outputdir = basedir;
685 char *pwd = talloc_size(torture, PATH_MAX);
686 if (!getcwd(pwd, PATH_MAX)) {
687 fprintf(stderr, "Unable to determine current working directory\n");
690 torture->outputdir = pwd;
693 torture->lp_ctx = cmdline_lp_ctx;
696 printf("You must specify a test to run, or 'ALL'\n");
700 for (i=2;i<argc_new;i++) {
701 if (!run_test(torture, argv_new[i])) {
707 if (torture->returncode && correct) {