2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "lib/cmdline/popt_common.h"
24 #include "system/time.h"
25 #include "system/wait.h"
26 #include "system/filesys.h"
27 #include "libcli/libcli.h"
28 #include "lib/ldb/include/ldb.h"
29 #include "lib/events/events.h"
31 #include "torture/torture.h"
33 #include "lib/util/dlinklist.h"
34 #include "librpc/rpc/dcerpc.h"
36 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
38 /****************************************************************************
39 run a specified test or "ALL"
40 ****************************************************************************/
41 static BOOL run_test(struct torture_context *torture, const char *name)
44 struct torture_suite_list *o;
47 if (strequal(name,"ALL")) {
48 for (o = torture_suites; o; o = o->next) {
49 ret &= torture_run_suite(torture, o->suite);
54 for (o = torture_suites; o; o = o->next) {
55 if (gen_fnmatch(name, o->suite->name) == 0) {
58 ret &= torture_run_suite(torture, o->suite);
63 printf("Unknown torture operation '%s'\n", name);
70 static void parse_dns(const char *dns)
72 char *userdn, *basedn, *secret;
75 /* retrievieng the userdn */
76 p = strchr_m(dns, '#');
78 lp_set_cmdline("torture:ldap_userdn", "");
79 lp_set_cmdline("torture:ldap_basedn", "");
80 lp_set_cmdline("torture:ldap_secret", "");
83 userdn = strndup(dns, p - dns);
84 lp_set_cmdline("torture:ldap_userdn", userdn);
86 /* retrieve the basedn */
90 lp_set_cmdline("torture:ldap_basedn", "");
91 lp_set_cmdline("torture:ldap_secret", "");
94 basedn = strndup(d, p - d);
95 lp_set_cmdline("torture:ldap_basedn", basedn);
97 /* retrieve the secret */
100 lp_set_cmdline("torture:ldap_secret", "");
104 lp_set_cmdline("torture:ldap_secret", secret);
106 printf ("%s - %s - %s\n", userdn, basedn, secret);
110 static void usage(poptContext pc)
112 struct torture_suite_list *o;
113 char last_prefix[64];
116 poptPrintUsage(pc, stdout, 0);
119 printf("The binding format is:\n\n");
121 printf(" TRANSPORT:host[flags]\n\n");
123 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
124 printf(" or ncalrpc for local connections.\n\n");
126 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
127 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
128 printf(" string.\n\n");
130 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
131 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
132 printf(" will be auto-determined.\n\n");
134 printf(" other recognised flags are:\n\n");
136 printf(" sign : enable ntlmssp signing\n");
137 printf(" seal : enable ntlmssp sealing\n");
138 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
139 printf(" validate: enable the NDR validator\n");
140 printf(" print: enable debugging of the packets\n");
141 printf(" bigendian: use bigendian RPC\n");
142 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
144 printf(" For example, these all connect to the samr pipe:\n\n");
146 printf(" ncacn_np:myserver\n");
147 printf(" ncacn_np:myserver[samr]\n");
148 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
149 printf(" ncacn_np:myserver[/pipe/samr]\n");
150 printf(" ncacn_np:myserver[samr,sign,print]\n");
151 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
152 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
153 printf(" ncacn_np:\n");
154 printf(" ncacn_np:[/pipe/samr]\n\n");
156 printf(" ncacn_ip_tcp:myserver\n");
157 printf(" ncacn_ip_tcp:myserver[1024]\n");
158 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
160 printf(" ncalrpc:\n\n");
162 printf("The UNC format is:\n\n");
164 printf(" //server/share\n\n");
166 printf("Tests are:");
169 last_prefix[0] = '\0';
170 for (o = torture_suites; o; o = o->next) {
173 if ((sep = strchr(o->suite->name, '-'))) {
174 if (strncmp(o->suite->name, last_prefix, sep-o->suite->name) != 0) {
175 strncpy(last_prefix, o->suite->name,
176 MIN(sizeof(last_prefix),
177 sep - o->suite->name));
183 if (i + strlen(o->suite->name) >= (MAX_COLS - 2)) {
187 i+=printf("%s ", o->suite->name);
191 printf("The default test is ALL.\n");
196 static BOOL is_binding_string(const char *binding_string)
198 TALLOC_CTX *mem_ctx = talloc_named_const(NULL, 0, "is_binding_string");
199 struct dcerpc_binding *binding_struct;
202 status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
204 talloc_free(mem_ctx);
205 return NT_STATUS_IS_OK(status);
208 static void max_runtime_handler(int sig)
210 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
214 struct timeval last_suite_started;
216 static void simple_suite_start(struct torture_context *ctx,
217 struct torture_suite *suite)
219 last_suite_started = timeval_current();
220 printf("Running %s\n", suite->name);
223 static void simple_suite_finish(struct torture_context *ctx,
224 struct torture_suite *suite)
227 printf("%s took %g secs\n\n", suite->name,
228 timeval_elapsed(&last_suite_started));
231 static void simple_test_result (struct torture_context *context,
232 enum torture_result res, const char *reason)
237 printf("OK: %s\n", reason);
240 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
243 printf("TODO: %s - %s\n", context->active_test->name, reason);
246 printf("SKIP: %s - %s\n", context->active_test->name, reason);
252 static void simple_comment (struct torture_context *test, const char *comment)
254 printf("# %s\n", comment);
257 const static struct torture_ui_ops std_ui_ops = {
258 .comment = simple_comment,
259 .suite_start = simple_suite_start,
260 .suite_finish = simple_suite_finish,
261 .test_result = simple_test_result
265 static void subunit_test_start (struct torture_context *ctx,
266 struct torture_tcase *tcase,
267 struct torture_test *test)
269 printf("test: %s\n", test->name);
272 static void subunit_test_result (struct torture_context *context,
273 enum torture_result res, const char *reason)
277 printf("success: %s\n", context->active_test->name);
280 printf("failure: %s [ %s ]\n", context->active_test->name, reason);
283 printf("todo: %s\n", context->active_test->name);
286 printf("skip: %s\n", context->active_test->name);
291 static void subunit_comment (struct torture_context *test, const char *comment)
293 printf("# %s\n", comment);
296 const static struct torture_ui_ops subunit_ui_ops = {
297 .comment = subunit_comment,
298 .test_start = subunit_test_start,
299 .test_result = subunit_test_result
302 static void harness_test_start (struct torture_context *ctx,
303 struct torture_tcase *tcase,
304 struct torture_test *test)
308 static void harness_test_result (struct torture_context *context,
309 enum torture_result res, const char *reason)
313 printf("ok %s - %s\n", context->active_test->name, reason);
316 printf("not ok %s - %s\n", context->active_test->name, reason);
319 printf("todo %s - %s\n", context->active_test->name, reason);
322 printf("skip %s - %s\n", context->active_test->name, reason);
327 static void harness_comment (struct torture_context *test, const char *comment)
329 printf("# %s\n", comment);
332 const static struct torture_ui_ops harness_ui_ops = {
333 .comment = harness_comment,
334 .test_start = harness_test_start,
335 .test_result = harness_test_result
338 static void quiet_suite_start(struct torture_context *ctx,
339 struct torture_suite *suite)
341 printf("%s: ", suite->name);
344 static void quiet_suite_finish(struct torture_context *ctx,
345 struct torture_suite *suite)
350 static void quiet_test_result (struct torture_context *context,
351 enum torture_result res, const char *reason)
354 case TORTURE_OK: putchar('.'); break;
355 case TORTURE_FAIL: putchar('E'); break;
356 case TORTURE_TODO: putchar('T'); break;
357 case TORTURE_SKIP: putchar('S'); break;
361 const static struct torture_ui_ops quiet_ui_ops = {
362 .suite_start = quiet_suite_start,
363 .suite_finish = quiet_suite_finish,
364 .test_result = quiet_test_result
368 /****************************************************************************
370 ****************************************************************************/
371 int main(int argc,char *argv[])
377 struct torture_context *torture;
380 static const char *target = "other";
381 static const char *ui_ops_name = "simple";
382 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
383 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC};
385 struct poptOption long_options[] = {
387 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
388 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
389 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
390 {"num-progs", 0, POPT_ARG_INT, &torture_nprocs, 0, "num progs", NULL},
391 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
392 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
393 {"use-oplocks", 'L', POPT_ARG_NONE, &use_oplocks, 0, "use oplocks", NULL},
394 {"show-all", 0, POPT_ARG_NONE, &torture_showall, 0, "show all", NULL},
395 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
396 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
397 {"timelimit", 't', POPT_ARG_STRING, NULL, OPT_TIMELIMIT, "timelimit", NULL},
398 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
399 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
400 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
401 "run dangerous tests (eg. wiping out password database)", NULL},
402 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
403 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
404 "run async tests", NULL},
405 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
406 "number of simultaneous async requests", NULL},
407 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
408 "set maximum time for smbtorture to live", "seconds"},
410 POPT_COMMON_CONNECTION
411 POPT_COMMON_CREDENTIALS
418 /* we are never interested in SIGPIPE */
419 BlockSignals(True,SIGPIPE);
421 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
422 POPT_CONTEXT_KEEP_FIRST);
424 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
426 while((opt = poptGetNextOpt(pc)) != -1) {
429 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
432 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
435 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
438 parse_dns(poptGetOptArg(pc));
441 lp_set_cmdline("torture:dangerous", "Yes");
444 lp_set_cmdline("torture:async", "Yes");
447 lp_set_cmdline("smb ports", poptGetOptArg(pc));
450 d_printf("Invalid option %s: %s\n",
451 poptBadOption(pc, 0), poptStrerror(opt));
459 /* this will only work if nobody else uses alarm(),
460 which means it won't work for some tests, but we
461 can't use the event context method we use for smbd
462 as so many tests create their own event
463 context. This will at least catch most cases. */
464 signal(SIGALRM, max_runtime_handler);
471 if (torture_seed == 0) {
472 torture_seed = time(NULL);
474 printf("Using seed %d\n", torture_seed);
475 srandom(torture_seed);
477 argv_new = discard_const_p(char *, poptGetArgs(pc));
480 for (i=0; i<argc; i++) {
481 if (argv_new[i] == NULL) {
492 if (strcmp(target, "samba3") == 0) {
493 lp_set_cmdline("target:samba3", "true");
494 } else if (strcmp(target, "samba4") == 0) {
495 lp_set_cmdline("target:samba4", "true");
498 /* see if its a RPC transport specifier */
499 if (is_binding_string(argv_new[1])) {
500 lp_set_cmdline("torture:binding", argv_new[1]);
502 char *binding = NULL;
503 char *host = NULL, *share = NULL;
505 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
506 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
510 lp_set_cmdline("torture:host", host);
511 lp_set_cmdline("torture:share", share);
512 asprintf(&binding, "ncacn_np:%s", host);
513 lp_set_cmdline("torture:binding", binding);
516 torture = talloc_zero(NULL, struct torture_context);
517 if (!strcmp(ui_ops_name, "simple")) {
518 torture->ui_ops = &std_ui_ops;
519 } else if (!strcmp(ui_ops_name, "subunit")) {
520 torture->ui_ops = &subunit_ui_ops;
521 } else if (!strcmp(ui_ops_name, "harness")) {
522 torture->ui_ops = &harness_ui_ops;
523 } else if (!strcmp(ui_ops_name, "quiet")) {
524 torture->ui_ops = &quiet_ui_ops;
526 printf("Unknown output format '%s'\n", ui_ops_name);
531 printf("You must specify a test to run, or 'ALL'\n");
535 for (i=2;i<argc_new;i++) {
536 if (!run_test(torture, argv_new[i])) {
541 total = torture->skipped+torture->success+torture->failed;
542 rate = ((total - torture->failed) * (100.0 / total));
543 printf("Tests: %d, Errors: %d, Skipped: %d. Success rate: %.2f%%\n",
544 total, torture->failed, torture->skipped,
548 talloc_free(torture);