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/events/events.h"
31 #include "torture/smbtorture.h"
32 #include "librpc/rpc/dcerpc.h"
33 #include "auth/gensec/gensec.h"
34 #include "param/param.h"
36 #if HAVE_READLINE_HISTORY_H
37 #include <readline/history.h>
40 static bool run_matching(struct torture_context *torture,
44 struct torture_suite *suite,
48 struct torture_suite *o;
49 struct torture_tcase *t;
50 struct torture_test *p;
52 for (o = suite->children; o; o = o->next) {
55 name = talloc_strdup(torture, o->name);
57 name = talloc_asprintf(torture, "%s-%s", prefix, o->name);
58 if (gen_fnmatch(expr, name) == 0) {
60 reload_charcnv(torture->lp_ctx);
61 torture->active_testname = name;
62 if (restricted != NULL)
63 ret &= torture_run_suite_restricted(torture, o, restricted);
65 ret &= torture_run_suite(torture, o);
67 ret &= run_matching(torture, name, expr, restricted, o, matched);
70 for (t = suite->testcases; t; t = t->next) {
71 char *name = talloc_asprintf(torture, "%s-%s", prefix, t->name);
72 if (gen_fnmatch(expr, name) == 0) {
74 reload_charcnv(torture->lp_ctx);
75 torture->active_testname = name;
76 ret &= torture_run_tcase(torture, t);
78 for (p = t->tests; p; p = p->next) {
79 name = talloc_asprintf(torture, "%s-%s-%s", prefix, t->name, p->name);
80 if (gen_fnmatch(expr, name) == 0) {
82 reload_charcnv(torture->lp_ctx);
83 torture->active_testname = name;
84 ret &= torture_run_test(torture, t, p);
92 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
94 /****************************************************************************
95 run a specified test or "ALL"
96 ****************************************************************************/
97 static bool run_test(struct torture_context *torture, const char *name,
101 bool matched = false;
102 struct torture_suite *o;
104 if (strequal(name, "ALL")) {
105 if (restricted != NULL) {
106 printf("--load-list and ALL are incompatible\n");
109 for (o = torture_root->children; o; o = o->next) {
110 ret &= torture_run_suite(torture, o);
115 ret = run_matching(torture, NULL, name, restricted, torture_root, &matched);
118 printf("Unknown torture operation '%s'\n", name);
125 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
127 char *host = NULL, *share = NULL;
128 struct dcerpc_binding *binding_struct;
131 /* see if its a RPC transport specifier */
132 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
133 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
134 if (NT_STATUS_IS_ERR(status)) {
135 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
138 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
139 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
140 lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
141 lp_set_cmdline(lp_ctx, "torture:binding", target);
143 lp_set_cmdline(lp_ctx, "torture:host", host);
144 lp_set_cmdline(lp_ctx, "torture:share", share);
145 lp_set_cmdline(lp_ctx, "torture:binding", host);
151 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
153 char *userdn, *basedn, *secret;
156 /* retrievieng the userdn */
157 p = strchr_m(dns, '#');
159 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
160 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
161 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
164 userdn = strndup(dns, p - dns);
165 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
167 /* retrieve the basedn */
169 p = strchr_m(d, '#');
171 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
172 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
175 basedn = strndup(d, p - d);
176 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
178 /* retrieve the secret */
181 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
185 lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
187 printf ("%s - %s - %s\n", userdn, basedn, secret);
191 /* Print the full test list, formatted into separate labelled test
194 static void print_structured_test_list(void)
196 struct torture_suite *o;
197 struct torture_suite *s;
198 struct torture_tcase *t;
201 if (torture_root == NULL) {
202 printf("NO TESTS LOADED\n");
206 for (o = torture_root->children; o; o = o->next) {
207 printf("\n%s (%s):\n ", o->description, o->name);
210 for (s = o->children; s; s = s->next) {
211 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
215 i+=printf("%s-%s ", o->name, s->name);
218 for (t = o->testcases; t; t = t->next) {
219 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
223 i+=printf("%s-%s ", o->name, t->name);
229 printf("\nThe default test is ALL.\n");
232 static void print_test_list(void)
234 struct torture_suite *o;
235 struct torture_suite *s;
236 struct torture_tcase *t;
238 if (torture_root == NULL)
241 for (o = torture_root->children; o; o = o->next) {
242 for (s = o->children; s; s = s->next) {
243 printf("%s-%s\n", o->name, s->name);
246 for (t = o->testcases; t; t = t->next) {
247 printf("%s-%s\n", o->name, t->name);
252 _NORETURN_ static void usage(poptContext pc)
254 poptPrintUsage(pc, stdout, 0);
257 printf("The binding format is:\n\n");
259 printf(" TRANSPORT:host[flags]\n\n");
261 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
262 printf(" or ncalrpc for local connections.\n\n");
264 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
265 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
266 printf(" string.\n\n");
268 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
269 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
270 printf(" will be auto-determined.\n\n");
272 printf(" other recognised flags are:\n\n");
274 printf(" sign : enable ntlmssp signing\n");
275 printf(" seal : enable ntlmssp sealing\n");
276 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
277 printf(" validate: enable the NDR validator\n");
278 printf(" print: enable debugging of the packets\n");
279 printf(" bigendian: use bigendian RPC\n");
280 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
282 printf(" For example, these all connect to the samr pipe:\n\n");
284 printf(" ncacn_np:myserver\n");
285 printf(" ncacn_np:myserver[samr]\n");
286 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
287 printf(" ncacn_np:myserver[/pipe/samr]\n");
288 printf(" ncacn_np:myserver[samr,sign,print]\n");
289 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
290 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
291 printf(" ncacn_np:\n");
292 printf(" ncacn_np:[/pipe/samr]\n\n");
294 printf(" ncacn_ip_tcp:myserver\n");
295 printf(" ncacn_ip_tcp:myserver[1024]\n");
296 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
298 printf(" ncalrpc:\n\n");
300 printf("The UNC format is:\n\n");
302 printf(" //server/share\n\n");
304 printf("Tests are:");
306 print_structured_test_list();
311 _NORETURN_ static void max_runtime_handler(int sig)
313 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
317 struct timeval last_suite_started;
319 static void simple_suite_start(struct torture_context *ctx,
320 struct torture_suite *suite)
322 last_suite_started = timeval_current();
323 printf("Running %s\n", suite->name);
326 static void simple_suite_finish(struct torture_context *ctx,
327 struct torture_suite *suite)
330 printf("%s took %g secs\n\n", suite->name,
331 timeval_elapsed(&last_suite_started));
334 static void simple_test_result(struct torture_context *context,
335 enum torture_result res, const char *reason)
340 printf("OK: %s\n", reason);
343 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
346 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
349 printf("SKIP: %s - %s\n", context->active_test->name, reason);
354 static void simple_comment(struct torture_context *test,
357 printf("%s", comment);
360 static void simple_warning(struct torture_context *test,
363 fprintf(stderr, "WARNING: %s\n", comment);
366 static void simple_progress(struct torture_context *test,
367 int offset, enum torture_progress_whence whence)
371 const static struct torture_ui_ops std_ui_ops = {
372 .comment = simple_comment,
373 .warning = simple_warning,
374 .suite_start = simple_suite_start,
375 .suite_finish = simple_suite_finish,
376 .test_result = simple_test_result,
377 .progress = simple_progress,
380 static void run_shell(struct torture_context *tctx)
388 cline = smb_readline("torture> ", NULL, NULL);
397 ret = poptParseArgvString(cline, &argc, &argv);
399 fprintf(stderr, "Error parsing line\n");
403 if (!strcmp(argv[0], "quit")) {
405 } else if (!strcmp(argv[0], "list")) {
406 print_structured_test_list();
407 } else if (!strcmp(argv[0], "set")) {
409 lp_dump(tctx->lp_ctx, stdout,
410 false /* show_defaults */,
411 0 /* skip services */);
413 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
414 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
417 } else if (!strcmp(argv[0], "help")) {
418 fprintf(stderr, "Available commands:\n"
419 " help - This help command\n"
420 " list - List the available\n"
422 " set - Change variables\n"
424 } else if (!strcmp(argv[0], "run")) {
426 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
428 run_test(tctx, argv[1]);
435 /****************************************************************************
437 ****************************************************************************/
438 int main(int argc,char *argv[])
444 struct torture_context *torture;
445 struct torture_results *results;
446 const struct torture_ui_ops *ui_ops;
449 static const char *target = "other";
451 static const char *ui_ops_name = "subunit";
452 const char *basedir = NULL;
453 const char *extra_module = NULL;
454 static int list_tests = 0;
455 int num_extra_users = 0;
456 char **restricted = NULL;
457 int num_restricted = -1;
458 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
459 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
460 OPT_EXTRA_USER,OPT_LOAD_LIST,};
462 struct poptOption long_options[] = {
464 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
465 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
466 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
467 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
468 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
469 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
470 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
471 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
472 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
473 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
474 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
475 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
476 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
477 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
478 "run dangerous tests (eg. wiping out password database)", NULL},
479 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
480 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
481 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
482 "run async tests", NULL},
483 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
484 "number of simultaneous async requests", NULL},
485 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
486 "set maximum time for smbtorture to live", "seconds"},
487 {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
488 "extra user credentials", NULL},
489 {"load-list", 0, POPT_ARG_STRING, NULL, OPT_LOAD_LIST,
490 "load a test id list from a text file", NULL},
492 POPT_COMMON_CONNECTION
493 POPT_COMMON_CREDENTIALS
500 /* we are never interested in SIGPIPE */
501 BlockSignals(true, SIGPIPE);
503 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
504 POPT_CONTEXT_KEEP_FIRST);
506 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
508 while((opt = poptGetNextOpt(pc)) != -1) {
511 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
514 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
517 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
520 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
523 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
526 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
529 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
532 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
536 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
538 const char *value = poptGetOptArg(pc);
539 lp_set_cmdline(cmdline_lp_ctx, option, value);
544 restricted = file_lines_load(optarg, &num_restricted, 0,
545 talloc_autofree_context());
546 if (restricted == NULL) {
547 printf("Unable to read load list file '%s'\n", optarg);
553 printf("bad command line option %d\n", opt);
559 if (strcmp(target, "samba3") == 0) {
560 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
561 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
562 } else if (strcmp(target, "samba4") == 0) {
563 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
564 } else if (strcmp(target, "winxp") == 0) {
565 lp_set_cmdline(cmdline_lp_ctx, "torture:winxp", "true");
566 } else if (strcmp(target, "w2k3") == 0) {
567 lp_set_cmdline(cmdline_lp_ctx, "torture:w2k3", "true");
568 } else if (strcmp(target, "w2k8") == 0) {
569 lp_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
570 lp_set_cmdline(cmdline_lp_ctx,
571 "torture:invalid_lock_range_support", "false");
572 } else if (strcmp(target, "win7") == 0) {
573 lp_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
574 lp_set_cmdline(cmdline_lp_ctx, "torture:cn_max_buffer_size",
576 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
577 lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
579 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
580 lp_set_cmdline(cmdline_lp_ctx, "torture:search_ea_support", "false");
582 lp_set_cmdline(cmdline_lp_ctx, "torture:hide_on_access_denied",
584 } else if (strcmp(target, "onefs") == 0) {
585 lp_set_cmdline(cmdline_lp_ctx, "torture:onefs", "true");
586 lp_set_cmdline(cmdline_lp_ctx, "torture:openx_deny_dos_support",
588 lp_set_cmdline(cmdline_lp_ctx, "torture:range_not_locked_on_file_close", "false");
589 lp_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
590 lp_set_cmdline(cmdline_lp_ctx, "torture:ea_support", "false");
591 lp_set_cmdline(cmdline_lp_ctx, "torture:smbexit_pdu_support",
593 lp_set_cmdline(cmdline_lp_ctx, "torture:smblock_pdu_support",
595 lp_set_cmdline(cmdline_lp_ctx, "torture:2_step_break_to_none",
597 lp_set_cmdline(cmdline_lp_ctx, "torture:deny_dos_support", "false");
598 lp_set_cmdline(cmdline_lp_ctx, "torture:deny_fcb_support", "false");
599 lp_set_cmdline(cmdline_lp_ctx, "torture:read_support", "false");
600 lp_set_cmdline(cmdline_lp_ctx, "torture:writeclose_support", "false");
601 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
602 lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
603 lp_set_cmdline(cmdline_lp_ctx, "torture:raw_search_search", "false");
604 lp_set_cmdline(cmdline_lp_ctx, "torture:search_ea_size", "false");
608 /* this will only work if nobody else uses alarm(),
609 which means it won't work for some tests, but we
610 can't use the event context method we use for smbd
611 as so many tests create their own event
612 context. This will at least catch most cases. */
613 signal(SIGALRM, max_runtime_handler);
617 if (extra_module != NULL) {
618 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
621 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
624 if (NT_STATUS_IS_ERR(status)) {
625 d_printf("Error initializing module %s: %s\n",
626 poptGetOptArg(pc), nt_errstr(status));
638 if (torture_seed == 0) {
639 torture_seed = time(NULL);
641 printf("Using seed %d\n", torture_seed);
642 srandom(torture_seed);
644 argv_new = discard_const_p(char *, poptGetArgs(pc));
647 for (i=0; i<argc; i++) {
648 if (argv_new[i] == NULL) {
654 if (!(argc_new >= 3)) {
659 if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
664 if (!strcmp(ui_ops_name, "simple")) {
665 ui_ops = &std_ui_ops;
666 } else if (!strcmp(ui_ops_name, "subunit")) {
667 ui_ops = &torture_subunit_ui_ops;
669 printf("Unknown output format '%s'\n", ui_ops_name);
673 results = torture_results_init(talloc_autofree_context(), ui_ops);
675 torture = torture_context_init(s4_event_context_init(talloc_autofree_context()),
677 if (basedir != NULL) {
678 if (basedir[0] != '/') {
679 fprintf(stderr, "Please specify an absolute path to --basedir\n");
682 torture->outputdir = basedir;
684 char *pwd = talloc_size(torture, PATH_MAX);
685 if (!getcwd(pwd, PATH_MAX)) {
686 fprintf(stderr, "Unable to determine current working directory\n");
689 torture->outputdir = pwd;
692 torture->lp_ctx = cmdline_lp_ctx;
694 gensec_init(cmdline_lp_ctx);
697 printf("You must specify a testsuite to run, or 'ALL'\n");
699 for (i=2;i<argc_new;i++) {
700 if (!run_test(torture, argv_new[i], restricted)) {
706 if (torture->results->returncode && correct) {