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_test_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_test_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_tests(bool structured)
254 print_structured_test_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_test_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;
407 const char *extra_module = NULL;
408 static int list_tests = 0;
409 int num_extra_users = 0;
410 char **restricted = NULL;
411 int num_restricted = -1;
412 const char *load_list = NULL;
413 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
414 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
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, &load_list, 0,
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 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
470 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
473 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
476 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
479 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
482 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
485 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
488 lpcfg_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 lpcfg_set_cmdline(cmdline_lp_ctx, option, value);
501 printf("bad command line option %d\n", opt);
507 if (load_list != NULL) {
508 restricted = file_lines_load(load_list, &num_restricted, 0,
509 talloc_autofree_context());
510 if (restricted == NULL) {
511 printf("Unable to read load list file '%s'\n", load_list);
516 if (strcmp(target, "samba3") == 0) {
517 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
518 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
519 } else if (strcmp(target, "samba4") == 0) {
520 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
521 } else if (strcmp(target, "winxp") == 0) {
522 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:winxp", "true");
523 } else if (strcmp(target, "w2k3") == 0) {
524 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:w2k3", "true");
525 } else if (strcmp(target, "w2k8") == 0) {
526 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
527 lpcfg_set_cmdline(cmdline_lp_ctx,
528 "torture:invalid_lock_range_support", "false");
529 } else if (strcmp(target, "win7") == 0) {
530 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
531 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:cn_max_buffer_size",
533 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
534 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
536 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
537 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:search_ea_support", "false");
539 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:hide_on_access_denied",
541 } else if (strcmp(target, "onefs") == 0) {
542 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:onefs", "true");
543 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:openx_deny_dos_support",
545 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:range_not_locked_on_file_close", "false");
546 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
547 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:ea_support", "false");
548 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:smbexit_pdu_support",
550 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:smblock_pdu_support",
552 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:2_step_break_to_none",
554 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:deny_dos_support", "false");
555 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:deny_fcb_support", "false");
556 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:read_support", "false");
557 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:writeclose_support", "false");
558 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
559 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
560 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:raw_search_search", "false");
561 lpcfg_set_cmdline(cmdline_lp_ctx, "torture:search_ea_size", "false");
565 /* this will only work if nobody else uses alarm(),
566 which means it won't work for some tests, but we
567 can't use the event context method we use for smbd
568 as so many tests create their own event
569 context. This will at least catch most cases. */
570 signal(SIGALRM, max_runtime_handler);
574 if (extra_module != NULL) {
575 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
578 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
581 if (NT_STATUS_IS_ERR(status)) {
582 d_printf("Error initializing module %s: %s\n",
583 poptGetOptArg(pc), nt_errstr(status));
595 if (torture_seed == 0) {
596 torture_seed = time(NULL);
598 printf("Using seed %d\n", torture_seed);
599 srandom(torture_seed);
601 argv_new = discard_const_p(char *, poptGetArgs(pc));
604 for (i=0; i<argc; i++) {
605 if (argv_new[i] == NULL) {
611 if (!strcmp(ui_ops_name, "simple")) {
612 ui_ops = &std_ui_ops;
613 } else if (!strcmp(ui_ops_name, "subunit")) {
614 ui_ops = &torture_subunit_ui_ops;
616 printf("Unknown output format '%s'\n", ui_ops_name);
620 results = torture_results_init(talloc_autofree_context(), ui_ops);
622 torture = torture_context_init(s4_event_context_init(talloc_autofree_context()),
624 if (basedir != NULL) {
625 if (basedir[0] != '/') {
626 fprintf(stderr, "Please specify an absolute path to --basedir\n");
629 torture->outputdir = basedir;
631 char *pwd = talloc_size(torture, PATH_MAX);
632 if (!getcwd(pwd, PATH_MAX)) {
633 fprintf(stderr, "Unable to determine current working directory\n");
636 torture->outputdir = pwd;
639 torture->lp_ctx = cmdline_lp_ctx;
641 gensec_init(cmdline_lp_ctx);
644 /* In shell mode, just ignore any remaining test names. */
645 torture_shell(torture);
648 /* At this point, we should just have a target string,
649 * followed by a series of test names. Unless we are in
650 * shell mode, in which case we don't need anythig more.
654 printf("You must specify a test to run, or 'ALL'\n");
659 /* Take the target name or binding. */
660 if (!torture_parse_target(cmdline_lp_ctx, argv_new[1])) {
665 for (i=2;i<argc_new;i++) {
666 if (!torture_run_named_tests(torture, argv_new[i],
667 (const char **)restricted)) {
673 if (torture->results->returncode && correct) {