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"
37 static bool run_matching(struct torture_context *torture,
41 struct torture_suite *suite,
45 struct torture_suite *o;
46 struct torture_tcase *t;
47 struct torture_test *p;
49 for (o = suite->children; o; o = o->next) {
52 name = talloc_strdup(torture, o->name);
54 name = talloc_asprintf(torture, "%s-%s", prefix, o->name);
55 if (gen_fnmatch(expr, name) == 0) {
57 reload_charcnv(torture->lp_ctx);
58 torture->active_testname = name;
59 if (restricted != NULL)
60 ret &= torture_run_suite_restricted(torture, o, restricted);
62 ret &= torture_run_suite(torture, o);
64 ret &= run_matching(torture, name, expr, restricted, o, matched);
67 for (t = suite->testcases; t; t = t->next) {
68 char *name = talloc_asprintf(torture, "%s-%s", prefix, t->name);
69 if (gen_fnmatch(expr, name) == 0) {
71 reload_charcnv(torture->lp_ctx);
72 torture->active_testname = name;
73 ret &= torture_run_tcase(torture, t);
75 for (p = t->tests; p; p = p->next) {
76 name = talloc_asprintf(torture, "%s-%s-%s", prefix, t->name, p->name);
77 if (gen_fnmatch(expr, name) == 0) {
79 reload_charcnv(torture->lp_ctx);
80 torture->active_testname = name;
81 ret &= torture_run_test(torture, t, p);
89 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
91 /****************************************************************************
92 run a specified test or "ALL"
93 ****************************************************************************/
94 static bool run_test(struct torture_context *torture, const char *name,
99 struct torture_suite *o;
101 if (strequal(name, "ALL")) {
102 if (restricted != NULL) {
103 printf("--load-list and ALL are incompatible\n");
106 for (o = torture_root->children; o; o = o->next) {
107 ret &= torture_run_suite(torture, o);
112 ret = run_matching(torture, NULL, name, restricted, torture_root, &matched);
115 printf("Unknown torture operation '%s'\n", name);
122 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
124 char *host = NULL, *share = NULL;
125 struct dcerpc_binding *binding_struct;
128 /* see if its a RPC transport specifier */
129 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
130 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
131 if (NT_STATUS_IS_ERR(status)) {
132 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
135 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
136 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
137 lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
138 lp_set_cmdline(lp_ctx, "torture:binding", target);
140 lp_set_cmdline(lp_ctx, "torture:host", host);
141 lp_set_cmdline(lp_ctx, "torture:share", share);
142 lp_set_cmdline(lp_ctx, "torture:binding", host);
148 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
150 char *userdn, *basedn, *secret;
153 /* retrievieng the userdn */
154 p = strchr_m(dns, '#');
156 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
157 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
158 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
161 userdn = strndup(dns, p - dns);
162 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
164 /* retrieve the basedn */
166 p = strchr_m(d, '#');
168 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
169 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
172 basedn = strndup(d, p - d);
173 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
175 /* retrieve the secret */
178 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
182 lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
184 printf ("%s - %s - %s\n", userdn, basedn, secret);
188 static void print_test_list(void)
190 struct torture_suite *o;
191 struct torture_suite *s;
192 struct torture_tcase *t;
194 if (torture_root == NULL)
197 for (o = torture_root->children; o; o = o->next) {
198 for (s = o->children; s; s = s->next) {
199 printf("%s-%s\n", o->name, s->name);
202 for (t = o->testcases; t; t = t->next) {
203 printf("%s-%s\n", o->name, t->name);
208 _NORETURN_ static void usage(poptContext pc)
210 struct torture_suite *o;
211 struct torture_suite *s;
212 struct torture_tcase *t;
215 poptPrintUsage(pc, stdout, 0);
218 printf("The binding format is:\n\n");
220 printf(" TRANSPORT:host[flags]\n\n");
222 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
223 printf(" or ncalrpc for local connections.\n\n");
225 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
226 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
227 printf(" string.\n\n");
229 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
230 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
231 printf(" will be auto-determined.\n\n");
233 printf(" other recognised flags are:\n\n");
235 printf(" sign : enable ntlmssp signing\n");
236 printf(" seal : enable ntlmssp sealing\n");
237 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
238 printf(" validate: enable the NDR validator\n");
239 printf(" print: enable debugging of the packets\n");
240 printf(" bigendian: use bigendian RPC\n");
241 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
243 printf(" For example, these all connect to the samr pipe:\n\n");
245 printf(" ncacn_np:myserver\n");
246 printf(" ncacn_np:myserver[samr]\n");
247 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
248 printf(" ncacn_np:myserver[/pipe/samr]\n");
249 printf(" ncacn_np:myserver[samr,sign,print]\n");
250 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
251 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
252 printf(" ncacn_np:\n");
253 printf(" ncacn_np:[/pipe/samr]\n\n");
255 printf(" ncacn_ip_tcp:myserver\n");
256 printf(" ncacn_ip_tcp:myserver[1024]\n");
257 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
259 printf(" ncalrpc:\n\n");
261 printf("The UNC format is:\n\n");
263 printf(" //server/share\n\n");
265 printf("Tests are:");
267 if (torture_root == NULL) {
268 printf("NO TESTS LOADED\n");
272 for (o = torture_root->children; o; o = o->next) {
273 printf("\n%s (%s):\n ", o->description, o->name);
276 for (s = o->children; s; s = s->next) {
277 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
281 i+=printf("%s-%s ", o->name, s->name);
284 for (t = o->testcases; t; t = t->next) {
285 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
289 i+=printf("%s-%s ", o->name, t->name);
295 printf("\nThe default test is ALL.\n");
300 _NORETURN_ static void max_runtime_handler(int sig)
302 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
306 struct timeval last_suite_started;
308 static void simple_suite_start(struct torture_context *ctx,
309 struct torture_suite *suite)
311 last_suite_started = timeval_current();
312 printf("Running %s\n", suite->name);
315 static void simple_suite_finish(struct torture_context *ctx,
316 struct torture_suite *suite)
319 printf("%s took %g secs\n\n", suite->name,
320 timeval_elapsed(&last_suite_started));
323 static void simple_test_result(struct torture_context *context,
324 enum torture_result res, const char *reason)
329 printf("OK: %s\n", reason);
332 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
335 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
338 printf("SKIP: %s - %s\n", context->active_test->name, reason);
343 static void simple_comment(struct torture_context *test,
346 printf("%s", comment);
349 static void simple_warning(struct torture_context *test,
352 fprintf(stderr, "WARNING: %s\n", comment);
355 static void simple_progress(struct torture_context *test,
356 int offset, enum torture_progress_whence whence)
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,
366 .progress = simple_progress,
370 /****************************************************************************
372 ****************************************************************************/
373 int main(int argc,char *argv[])
379 struct torture_context *torture;
380 struct torture_results *results;
381 const struct torture_ui_ops *ui_ops;
384 static const char *target = "other";
386 static const char *ui_ops_name = "subunit";
387 const char *basedir = NULL;
388 const char *extra_module = NULL;
389 static int list_tests = 0;
390 int num_extra_users = 0;
391 char **restricted = NULL;
392 int num_restricted = -1;
393 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
394 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
395 OPT_EXTRA_USER,OPT_LOAD_LIST,};
397 struct poptOption long_options[] = {
399 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
400 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
401 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
402 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
403 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
404 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
405 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
406 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
407 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
408 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
409 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
410 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
411 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
412 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
413 "run dangerous tests (eg. wiping out password database)", NULL},
414 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
415 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
416 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
417 "run async tests", NULL},
418 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
419 "number of simultaneous async requests", NULL},
420 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
421 "set maximum time for smbtorture to live", "seconds"},
422 {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
423 "extra user credentials", NULL},
424 {"load-list", 0, POPT_ARG_STRING, NULL, OPT_LOAD_LIST,
425 "load a test id list from a text file", NULL},
427 POPT_COMMON_CONNECTION
428 POPT_COMMON_CREDENTIALS
435 /* we are never interested in SIGPIPE */
436 BlockSignals(true, SIGPIPE);
438 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
439 POPT_CONTEXT_KEEP_FIRST);
441 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
443 while((opt = poptGetNextOpt(pc)) != -1) {
446 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
449 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
452 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
455 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
458 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
461 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
464 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
467 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
471 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
473 const char *value = poptGetOptArg(pc);
474 lp_set_cmdline(cmdline_lp_ctx, option, value);
479 restricted = file_lines_load(optarg, &num_restricted, 0,
480 talloc_autofree_context());
481 if (restricted == NULL) {
482 printf("Unable to read load list file '%s'\n", optarg);
487 printf("bad command line option\n");
492 if (strcmp(target, "samba3") == 0) {
493 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
494 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
495 } else if (strcmp(target, "samba4") == 0) {
496 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
497 } else if (strcmp(target, "winxp") == 0) {
498 lp_set_cmdline(cmdline_lp_ctx, "torture:winxp", "true");
499 } else if (strcmp(target, "w2k3") == 0) {
500 lp_set_cmdline(cmdline_lp_ctx, "torture:w2k3", "true");
501 } else if (strcmp(target, "w2k8") == 0) {
502 lp_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
503 lp_set_cmdline(cmdline_lp_ctx,
504 "torture:invalid_lock_range_support", "false");
505 } else if (strcmp(target, "win7") == 0) {
506 lp_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
507 lp_set_cmdline(cmdline_lp_ctx, "torture:cn_max_buffer_size",
509 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
510 lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
512 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
513 lp_set_cmdline(cmdline_lp_ctx, "torture:search_ea_support", "false");
515 lp_set_cmdline(cmdline_lp_ctx, "torture:hide_on_access_denied",
517 } else if (strcmp(target, "onefs") == 0) {
518 lp_set_cmdline(cmdline_lp_ctx, "torture:onefs", "true");
519 lp_set_cmdline(cmdline_lp_ctx, "torture:openx_deny_dos_support",
521 lp_set_cmdline(cmdline_lp_ctx, "torture:range_not_locked_on_file_close", "false");
522 lp_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
523 lp_set_cmdline(cmdline_lp_ctx, "torture:ea_support", "false");
524 lp_set_cmdline(cmdline_lp_ctx, "torture:smbexit_pdu_support",
526 lp_set_cmdline(cmdline_lp_ctx, "torture:smblock_pdu_support",
528 lp_set_cmdline(cmdline_lp_ctx, "torture:2_step_break_to_none",
530 lp_set_cmdline(cmdline_lp_ctx, "torture:deny_dos_support", "false");
531 lp_set_cmdline(cmdline_lp_ctx, "torture:deny_fcb_support", "false");
532 lp_set_cmdline(cmdline_lp_ctx, "torture:read_support", "false");
533 lp_set_cmdline(cmdline_lp_ctx, "torture:writeclose_support", "false");
534 lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
535 lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
536 lp_set_cmdline(cmdline_lp_ctx, "torture:raw_search_search", "false");
537 lp_set_cmdline(cmdline_lp_ctx, "torture:search_ea_size", "false");
541 /* this will only work if nobody else uses alarm(),
542 which means it won't work for some tests, but we
543 can't use the event context method we use for smbd
544 as so many tests create their own event
545 context. This will at least catch most cases. */
546 signal(SIGALRM, max_runtime_handler);
550 if (extra_module != NULL) {
551 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
554 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
557 if (NT_STATUS_IS_ERR(status)) {
558 d_printf("Error initializing module %s: %s\n",
559 poptGetOptArg(pc), nt_errstr(status));
571 if (torture_seed == 0) {
572 torture_seed = time(NULL);
574 printf("Using seed %d\n", torture_seed);
575 srandom(torture_seed);
577 argv_new = discard_const_p(char *, poptGetArgs(pc));
580 for (i=0; i<argc; i++) {
581 if (argv_new[i] == NULL) {
587 if (!(argc_new >= 3)) {
592 if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
597 if (!strcmp(ui_ops_name, "simple")) {
598 ui_ops = &std_ui_ops;
599 } else if (!strcmp(ui_ops_name, "subunit")) {
600 ui_ops = &torture_subunit_ui_ops;
602 printf("Unknown output format '%s'\n", ui_ops_name);
606 results = torture_results_init(talloc_autofree_context(), ui_ops);
608 torture = torture_context_init(s4_event_context_init(talloc_autofree_context()),
610 if (basedir != NULL) {
611 if (basedir[0] != '/') {
612 fprintf(stderr, "Please specify an absolute path to --basedir\n");
615 torture->outputdir = basedir;
617 char *pwd = talloc_size(torture, PATH_MAX);
618 if (!getcwd(pwd, PATH_MAX)) {
619 fprintf(stderr, "Unable to determine current working directory\n");
622 torture->outputdir = pwd;
625 torture->lp_ctx = cmdline_lp_ctx;
627 gensec_init(cmdline_lp_ctx);
630 printf("You must specify a testsuite to run, or 'ALL'\n");
632 for (i=2;i<argc_new;i++) {
633 if (!run_test(torture, argv_new[i], restricted)) {
639 if (torture->results->returncode && correct) {