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 "../libcli/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,
43 const char **restricted,
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 if (restricted != NULL)
62 ret &= torture_run_suite_restricted(torture, o, restricted);
64 ret &= torture_run_suite(torture, o);
66 ret &= run_matching(torture, name, expr, restricted, o, matched);
69 for (t = suite->testcases; t; t = t->next) {
70 char *name = talloc_asprintf(torture, "%s.%s", prefix, t->name);
71 if (gen_fnmatch(expr, name) == 0) {
73 reload_charcnv(torture->lp_ctx);
74 ret &= torture_run_tcase_restricted(torture, t, restricted);
76 for (p = t->tests; p; p = p->next) {
77 name = talloc_asprintf(torture, "%s.%s.%s", prefix, t->name, p->name);
78 if (gen_fnmatch(expr, name) == 0) {
80 reload_charcnv(torture->lp_ctx);
81 ret &= torture_run_test_restricted(torture, t, p, restricted);
89 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
91 /****************************************************************************
92 run a specified test or "ALL"
93 ****************************************************************************/
94 bool torture_run_named_tests(struct torture_context *torture, const char *name,
95 const char **restricted)
99 struct torture_suite *o;
101 torture_ui_report_time(torture);
103 if (strequal(name, "ALL")) {
104 if (restricted != NULL) {
105 printf("--load-list and ALL are incompatible\n");
108 for (o = torture_root->children; o; o = o->next) {
109 ret &= torture_run_suite(torture, o);
114 ret = run_matching(torture, NULL, name, restricted, torture_root, &matched);
117 printf("Unknown torture operation '%s'\n", name);
124 bool torture_parse_target(struct loadparm_context *lp_ctx, const char *target)
126 char *host = NULL, *share = NULL;
127 struct dcerpc_binding *binding_struct;
130 /* see if its a RPC transport specifier */
131 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
132 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
133 if (NT_STATUS_IS_ERR(status)) {
134 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
137 lpcfg_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
138 if (lpcfg_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
139 lpcfg_set_cmdline(lp_ctx, "torture:share", "IPC$");
140 lpcfg_set_cmdline(lp_ctx, "torture:binding", target);
142 lpcfg_set_cmdline(lp_ctx, "torture:host", host);
143 lpcfg_set_cmdline(lp_ctx, "torture:share", share);
144 lpcfg_set_cmdline(lp_ctx, "torture:binding", host);
150 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
152 char *userdn, *basedn, *secret;
155 /* retrievieng the userdn */
156 p = strchr_m(dns, '#');
158 lpcfg_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
159 lpcfg_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
160 lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", "");
163 userdn = strndup(dns, p - dns);
164 lpcfg_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
166 /* retrieve the basedn */
168 p = strchr_m(d, '#');
170 lpcfg_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
171 lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", "");
174 basedn = strndup(d, p - d);
175 lpcfg_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
177 /* retrieve the secret */
180 lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", "");
184 lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
186 printf ("%s - %s - %s\n", userdn, basedn, secret);
190 /* Print the full test list, formatted into separate labelled test
193 static void print_structured_testsuite_list(void)
195 struct torture_suite *o;
196 struct torture_suite *s;
197 struct torture_tcase *t;
200 if (torture_root == NULL) {
201 printf("NO TESTS LOADED\n");
205 for (o = torture_root->children; o; o = o->next) {
206 printf("\n%s (%s):\n ", o->description, o->name);
209 for (s = o->children; s; s = s->next) {
210 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
214 i+=printf("%s.%s ", o->name, s->name);
217 for (t = o->testcases; t; t = t->next) {
218 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
222 i+=printf("%s.%s ", o->name, t->name);
228 printf("\nThe default test is ALL.\n");
231 static void print_testsuite_list(void)
233 struct torture_suite *o;
234 struct torture_suite *s;
235 struct torture_tcase *t;
237 if (torture_root == NULL)
240 for (o = torture_root->children; o; o = o->next) {
241 for (s = o->children; s; s = s->next) {
242 printf("%s.%s\n", o->name, s->name);
245 for (t = o->testcases; t; t = t->next) {
246 printf("%s.%s\n", o->name, t->name);
251 void torture_print_testsuites(bool structured)
254 print_structured_testsuite_list();
256 print_testsuite_list();
260 _NORETURN_ static void usage(poptContext pc)
262 poptPrintUsage(pc, stdout, 0);
265 printf("The binding format is:\n\n");
267 printf(" TRANSPORT:host[flags]\n\n");
269 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
270 printf(" or ncalrpc for local connections.\n\n");
272 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
273 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
274 printf(" string.\n\n");
276 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
277 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
278 printf(" will be auto-determined.\n\n");
280 printf(" other recognised flags are:\n\n");
282 printf(" sign : enable ntlmssp signing\n");
283 printf(" seal : enable ntlmssp sealing\n");
284 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
285 printf(" validate: enable the NDR validator\n");
286 printf(" print: enable debugging of the packets\n");
287 printf(" bigendian: use bigendian RPC\n");
288 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
290 printf(" For example, these all connect to the samr pipe:\n\n");
292 printf(" ncacn_np:myserver\n");
293 printf(" ncacn_np:myserver[samr]\n");
294 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
295 printf(" ncacn_np:myserver[/pipe/samr]\n");
296 printf(" ncacn_np:myserver[samr,sign,print]\n");
297 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
298 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
299 printf(" ncacn_np:\n");
300 printf(" ncacn_np:[/pipe/samr]\n\n");
302 printf(" ncacn_ip_tcp:myserver\n");
303 printf(" ncacn_ip_tcp:myserver[1024]\n");
304 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
306 printf(" ncalrpc:\n\n");
308 printf("The UNC format is:\n\n");
310 printf(" //server/share\n\n");
312 printf("Tests are:");
314 print_structured_testsuite_list();
319 _NORETURN_ static void max_runtime_handler(int sig)
321 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
325 struct timeval last_suite_started;
327 static void simple_suite_start(struct torture_context *ctx,
328 struct torture_suite *suite)
330 last_suite_started = timeval_current();
331 printf("Running %s\n", suite->name);
334 static void simple_suite_finish(struct torture_context *ctx,
335 struct torture_suite *suite)
338 printf("%s took %g secs\n\n", suite->name,
339 timeval_elapsed(&last_suite_started));
342 static void simple_test_result(struct torture_context *context,
343 enum torture_result res, const char *reason)
348 printf("OK: %s\n", reason);
351 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
354 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
357 printf("SKIP: %s - %s\n", context->active_test->name, reason);
362 static void simple_comment(struct torture_context *test,
365 printf("%s", comment);
368 static void simple_warning(struct torture_context *test,
371 fprintf(stderr, "WARNING: %s\n", comment);
374 static void simple_progress(struct torture_context *test,
375 int offset, enum torture_progress_whence whence)
379 const static struct torture_ui_ops std_ui_ops = {
380 .comment = simple_comment,
381 .warning = simple_warning,
382 .suite_start = simple_suite_start,
383 .suite_finish = simple_suite_finish,
384 .test_result = simple_test_result,
385 .progress = simple_progress,
388 /****************************************************************************
390 ****************************************************************************/
391 int main(int argc,char *argv[])
397 struct torture_context *torture;
398 struct torture_results *results;
399 const struct torture_ui_ops *ui_ops;
402 static const char *target = "other";
405 static const char *ui_ops_name = "subunit";
406 const char *basedir = NULL;
408 const char *extra_module = NULL;
409 static int list_tests = 0, list_testsuites = 0;
410 int num_extra_users = 0;
411 char **restricted = NULL;
412 int num_restricted = -1;
413 const char *load_list = NULL;
414 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
415 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
418 struct poptOption long_options[] = {
420 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
421 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
422 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
423 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
424 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
425 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
426 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
427 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
428 {"list-suites", 0, POPT_ARG_NONE, &list_testsuites, 0, "List available testsuites and exit", NULL },
429 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests in specified suites and exit", NULL },
430 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
431 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
432 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
433 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
434 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
435 "run dangerous tests (eg. wiping out password database)", NULL},
436 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
437 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
438 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
439 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
440 "run async tests", NULL},
441 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
442 "number of simultaneous async requests", NULL},
443 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
444 "set maximum time for smbtorture to live", "seconds"},
445 {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
446 "extra user credentials", NULL},
447 {"load-list", 0, POPT_ARG_STRING, &load_list, 0,
448 "load a test id list from a text file", NULL},
450 POPT_COMMON_CONNECTION
451 POPT_COMMON_CREDENTIALS
458 /* we are never interested in SIGPIPE */
459 BlockSignals(true, SIGPIPE);
461 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
462 POPT_CONTEXT_KEEP_FIRST);
464 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
466 while((opt = poptGetNextOpt(pc)) != -1) {
469 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
472 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
475 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
478 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
481 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
484 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
487 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
490 lpcfg_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
494 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
496 const char *value = poptGetOptArg(pc);
497 lpcfg_set_cmdline(cmdline_lp_ctx, option, value);
503 printf("bad command line option %d\n", opt);
509 if (load_list != NULL) {
510 restricted = file_lines_load(load_list, &num_restricted, 0,
511 talloc_autofree_context());
512 if (restricted == NULL) {
513 printf("Unable to read load list file '%s'\n", load_list);
518 if (strcmp(target, "samba3") == 0) {
519 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
520 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
521 } else if (strcmp(target, "samba4") == 0) {
522 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
523 } else if (strcmp(target, "winxp") == 0) {
524 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:winxp", "true");
525 } else if (strcmp(target, "w2k3") == 0) {
526 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:w2k3", "true");
527 } else if (strcmp(target, "w2k8") == 0) {
528 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
529 lpcfg_set_cmdline(cmdline_lp_ctx,
530 "torture:invalid_lock_range_support", "false");
531 } else if (strcmp(target, "win7") == 0) {
532 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
533 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:cn_max_buffer_size",
535 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
536 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
538 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
539 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:search_ea_support", "false");
541 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:hide_on_access_denied",
543 } else if (strcmp(target, "onefs") == 0) {
544 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:onefs", "true");
545 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:openx_deny_dos_support",
547 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:range_not_locked_on_file_close", "false");
548 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
549 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:ea_support", "false");
550 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:smbexit_pdu_support",
552 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:smblock_pdu_support",
554 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:2_step_break_to_none",
556 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:deny_dos_support", "false");
557 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:deny_fcb_support", "false");
558 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:read_support", "false");
559 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:writeclose_support", "false");
560 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
561 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
562 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:raw_search_search", "false");
563 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:search_ea_size", "false");
567 /* this will only work if nobody else uses alarm(),
568 which means it won't work for some tests, but we
569 can't use the event context method we use for smbd
570 as so many tests create their own event
571 context. This will at least catch most cases. */
572 signal(SIGALRM, max_runtime_handler);
576 if (extra_module != NULL) {
577 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
580 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
583 if (NT_STATUS_IS_ERR(status)) {
584 d_printf("Error initializing module %s: %s\n",
585 poptGetOptArg(pc), nt_errstr(status));
592 if (list_testsuites) {
593 print_testsuite_list();
597 if (torture_seed == 0) {
598 torture_seed = time(NULL);
600 printf("Using seed %d\n", torture_seed);
601 srandom(torture_seed);
603 argv_new = discard_const_p(char *, poptGetArgs(pc));
606 for (i=0; i<argc; i++) {
607 if (argv_new[i] == NULL) {
613 if (!strcmp(ui_ops_name, "simple")) {
614 ui_ops = &std_ui_ops;
615 } else if (!strcmp(ui_ops_name, "subunit")) {
616 ui_ops = &torture_subunit_ui_ops;
618 printf("Unknown output format '%s'\n", ui_ops_name);
622 results = torture_results_init(talloc_autofree_context(), ui_ops);
624 torture = torture_context_init(s4_event_context_init(talloc_autofree_context()),
626 if (basedir != NULL) {
627 if (basedir[0] != '/') {
628 fprintf(stderr, "Please specify an absolute path to --basedir\n");
631 outputdir = talloc_asprintf(torture, "%s/smbtortureXXXXXX", basedir);
633 char *pwd = talloc_size(torture, PATH_MAX);
634 if (!getcwd(pwd, PATH_MAX)) {
635 fprintf(stderr, "Unable to determine current working directory\n");
638 outputdir = talloc_asprintf(torture, "%s/smbtortureXXXXXX", pwd);
641 fprintf(stderr, "Could not allocate per-run output dir\n");
644 torture->outputdir = mkdtemp(outputdir);
645 if (!torture->outputdir) {
646 perror("Failed to make temp output dir");
649 torture->lp_ctx = cmdline_lp_ctx;
651 gensec_init(cmdline_lp_ctx);
654 /* In shell mode, just ignore any remaining test names. */
655 torture_shell(torture);
658 /* At this point, we should just have a target string,
659 * followed by a series of test names. Unless we are in
660 * shell mode, in which case we don't need anythig more.
664 printf("You must specify a test to run, or 'ALL'\n");
669 /* Take the target name or binding. */
670 if (!torture_parse_target(cmdline_lp_ctx, argv_new[1])) {
675 for (i=2;i<argc_new;i++) {
676 if (!torture_run_named_tests(torture, argv_new[i],
677 (const char **)restricted)) {
683 /* Now delete the temp dir we created */
684 torture_deltree_outputdir(torture);
686 if (torture->results->returncode && correct) {