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,
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 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 bool torture_run_named_tests(struct torture_context *torture, const char *name,
98 const char **restricted)
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 bool torture_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 void torture_print_tests(bool structured)
255 print_structured_test_list();
261 _NORETURN_ static void usage(poptContext pc)
263 poptPrintUsage(pc, stdout, 0);
266 printf("The binding format is:\n\n");
268 printf(" TRANSPORT:host[flags]\n\n");
270 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
271 printf(" or ncalrpc for local connections.\n\n");
273 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
274 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
275 printf(" string.\n\n");
277 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
278 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
279 printf(" will be auto-determined.\n\n");
281 printf(" other recognised flags are:\n\n");
283 printf(" sign : enable ntlmssp signing\n");
284 printf(" seal : enable ntlmssp sealing\n");
285 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
286 printf(" validate: enable the NDR validator\n");
287 printf(" print: enable debugging of the packets\n");
288 printf(" bigendian: use bigendian RPC\n");
289 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
291 printf(" For example, these all connect to the samr pipe:\n\n");
293 printf(" ncacn_np:myserver\n");
294 printf(" ncacn_np:myserver[samr]\n");
295 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
296 printf(" ncacn_np:myserver[/pipe/samr]\n");
297 printf(" ncacn_np:myserver[samr,sign,print]\n");
298 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
299 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
300 printf(" ncacn_np:\n");
301 printf(" ncacn_np:[/pipe/samr]\n\n");
303 printf(" ncacn_ip_tcp:myserver\n");
304 printf(" ncacn_ip_tcp:myserver[1024]\n");
305 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
307 printf(" ncalrpc:\n\n");
309 printf("The UNC format is:\n\n");
311 printf(" //server/share\n\n");
313 printf("Tests are:");
315 print_structured_test_list();
320 _NORETURN_ static void max_runtime_handler(int sig)
322 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
326 struct timeval last_suite_started;
328 static void simple_suite_start(struct torture_context *ctx,
329 struct torture_suite *suite)
331 last_suite_started = timeval_current();
332 printf("Running %s\n", suite->name);
335 static void simple_suite_finish(struct torture_context *ctx,
336 struct torture_suite *suite)
339 printf("%s took %g secs\n\n", suite->name,
340 timeval_elapsed(&last_suite_started));
343 static void simple_test_result(struct torture_context *context,
344 enum torture_result res, const char *reason)
349 printf("OK: %s\n", reason);
352 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
355 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
358 printf("SKIP: %s - %s\n", context->active_test->name, reason);
363 static void simple_comment(struct torture_context *test,
366 printf("%s", comment);
369 static void simple_warning(struct torture_context *test,
372 fprintf(stderr, "WARNING: %s\n", comment);
375 static void simple_progress(struct torture_context *test,
376 int offset, enum torture_progress_whence whence)
380 const static struct torture_ui_ops std_ui_ops = {
381 .comment = simple_comment,
382 .warning = simple_warning,
383 .suite_start = simple_suite_start,
384 .suite_finish = simple_suite_finish,
385 .test_result = simple_test_result,
386 .progress = simple_progress,
389 /****************************************************************************
391 ****************************************************************************/
392 int main(int argc,char *argv[])
398 struct torture_context *torture;
399 struct torture_results *results;
400 const struct torture_ui_ops *ui_ops;
403 static const char *target = "other";
406 static const char *ui_ops_name = "subunit";
407 const char *basedir = NULL;
408 const char *extra_module = NULL;
409 static int list_tests = 0;
410 int num_extra_users = 0;
411 char **restricted = NULL;
412 int num_restricted = -1;
413 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
414 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
415 OPT_EXTRA_USER,OPT_LOAD_LIST,};
417 struct poptOption long_options[] = {
419 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
420 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
421 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
422 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
423 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
424 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
425 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
426 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
427 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
428 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
429 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
430 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
431 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
432 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
433 "run dangerous tests (eg. wiping out password database)", NULL},
434 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
435 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
436 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
437 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
438 "run async tests", NULL},
439 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
440 "number of simultaneous async requests", NULL},
441 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
442 "set maximum time for smbtorture to live", "seconds"},
443 {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
444 "extra user credentials", NULL},
445 {"load-list", 0, POPT_ARG_STRING, NULL, OPT_LOAD_LIST,
446 "load a test id list from a text file", NULL},
448 POPT_COMMON_CONNECTION
449 POPT_COMMON_CREDENTIALS
456 /* we are never interested in SIGPIPE */
457 BlockSignals(true, SIGPIPE);
459 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
460 POPT_CONTEXT_KEEP_FIRST);
462 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
464 while((opt = poptGetNextOpt(pc)) != -1) {
467 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
470 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
473 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
476 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
479 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
482 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
485 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
488 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
492 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
494 const char *value = poptGetOptArg(pc);
495 lp_set_cmdline(cmdline_lp_ctx, option, value);
500 restricted = file_lines_load(optarg, &num_restricted, 0,
501 talloc_autofree_context());
502 if (restricted == NULL) {
503 printf("Unable to read load list file '%s'\n", optarg);
509 printf("bad command line option %d\n", opt);
515 if (strcmp(target, "samba3") == 0) {
516 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
517 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
518 } else if (strcmp(target, "samba4") == 0) {
519 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
520 } else if (strcmp(target, "winxp") == 0) {
521 lp_set_cmdline(cmdline_lp_ctx, "torture:winxp", "true");
522 } else if (strcmp(target, "w2k3") == 0) {
523 lp_set_cmdline(cmdline_lp_ctx, "torture:w2k3", "true");
524 } else if (strcmp(target, "w2k8") == 0) {
525 lp_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
526 lp_set_cmdline(cmdline_lp_ctx,
527 "torture:invalid_lock_range_support", "false");
528 } else if (strcmp(target, "win7") == 0) {
529 lp_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
530 lp_set_cmdline(cmdline_lp_ctx, "torture:cn_max_buffer_size",
532 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
533 lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
535 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
536 lp_set_cmdline(cmdline_lp_ctx, "torture:search_ea_support", "false");
538 lp_set_cmdline(cmdline_lp_ctx, "torture:hide_on_access_denied",
540 } else if (strcmp(target, "onefs") == 0) {
541 lp_set_cmdline(cmdline_lp_ctx, "torture:onefs", "true");
542 lp_set_cmdline(cmdline_lp_ctx, "torture:openx_deny_dos_support",
544 lp_set_cmdline(cmdline_lp_ctx, "torture:range_not_locked_on_file_close", "false");
545 lp_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
546 lp_set_cmdline(cmdline_lp_ctx, "torture:ea_support", "false");
547 lp_set_cmdline(cmdline_lp_ctx, "torture:smbexit_pdu_support",
549 lp_set_cmdline(cmdline_lp_ctx, "torture:smblock_pdu_support",
551 lp_set_cmdline(cmdline_lp_ctx, "torture:2_step_break_to_none",
553 lp_set_cmdline(cmdline_lp_ctx, "torture:deny_dos_support", "false");
554 lp_set_cmdline(cmdline_lp_ctx, "torture:deny_fcb_support", "false");
555 lp_set_cmdline(cmdline_lp_ctx, "torture:read_support", "false");
556 lp_set_cmdline(cmdline_lp_ctx, "torture:writeclose_support", "false");
557 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
558 lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
559 lp_set_cmdline(cmdline_lp_ctx, "torture:raw_search_search", "false");
560 lp_set_cmdline(cmdline_lp_ctx, "torture:search_ea_size", "false");
564 /* this will only work if nobody else uses alarm(),
565 which means it won't work for some tests, but we
566 can't use the event context method we use for smbd
567 as so many tests create their own event
568 context. This will at least catch most cases. */
569 signal(SIGALRM, max_runtime_handler);
573 if (extra_module != NULL) {
574 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
577 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
580 if (NT_STATUS_IS_ERR(status)) {
581 d_printf("Error initializing module %s: %s\n",
582 poptGetOptArg(pc), nt_errstr(status));
594 if (torture_seed == 0) {
595 torture_seed = time(NULL);
597 printf("Using seed %d\n", torture_seed);
598 srandom(torture_seed);
600 argv_new = discard_const_p(char *, poptGetArgs(pc));
603 for (i=0; i<argc; i++) {
604 if (argv_new[i] == NULL) {
610 if (!strcmp(ui_ops_name, "simple")) {
611 ui_ops = &std_ui_ops;
612 } else if (!strcmp(ui_ops_name, "subunit")) {
613 ui_ops = &torture_subunit_ui_ops;
615 printf("Unknown output format '%s'\n", ui_ops_name);
619 results = torture_results_init(talloc_autofree_context(), ui_ops);
621 torture = torture_context_init(s4_event_context_init(talloc_autofree_context()),
623 if (basedir != NULL) {
624 if (basedir[0] != '/') {
625 fprintf(stderr, "Please specify an absolute path to --basedir\n");
628 torture->outputdir = basedir;
630 char *pwd = talloc_size(torture, PATH_MAX);
631 if (!getcwd(pwd, PATH_MAX)) {
632 fprintf(stderr, "Unable to determine current working directory\n");
635 torture->outputdir = pwd;
638 torture->lp_ctx = cmdline_lp_ctx;
640 gensec_init(cmdline_lp_ctx);
643 /* In shell mode, just ignore any remaining test names. */
644 torture_shell(torture);
647 /* At this point, we should just have a target string,
648 * followed by a series of test names. Unless we are in
649 * shell mode, in which case we don't need anythig more.
653 printf("You must specify a test to run, or 'ALL'\n");
658 /* Take the target name or binding. */
659 if (!torture_parse_target(cmdline_lp_ctx, argv_new[1])) {
664 for (i=2;i<argc_new;i++) {
665 if (!torture_run_named_tests(torture, argv_new[i],
666 (const char **)restricted)) {
672 if (torture->results->returncode && correct) {