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"
30 #include "dynconfig.h"
32 #include "torture/torture.h"
34 #include "lib/util/dlinklist.h"
35 #include "librpc/rpc/dcerpc.h"
37 static bool run_matching(struct torture_context
*torture
,
40 struct torture_suite
*suite
,
46 struct torture_suite
*o
;
48 for (o
= torture_root
->children
; o
; o
= o
->next
) {
49 if (gen_fnmatch(expr
, o
->name
) == 0) {
52 ret
&= torture_run_suite(torture
, o
);
56 ret
&= run_matching(torture
, o
->name
, expr
, o
, matched
);
60 struct torture_suite
*c
;
61 struct torture_tcase
*t
;
63 for (c
= suite
->children
; c
; c
= c
->next
) {
64 asprintf(&name
, "%s-%s", prefix
, c
->name
);
65 if (gen_fnmatch(expr
, name
) == 0) {
68 ret
&= torture_run_suite(torture
, c
);
73 ret
&= run_matching(torture
, name
, expr
, c
, matched
);
78 for (t
= suite
->testcases
; t
; t
= t
->next
) {
79 asprintf(&name
, "%s-%s", prefix
, t
->name
);
80 if (gen_fnmatch(expr
, name
) == 0) {
83 ret
&= torture_run_tcase(torture
, t
);
92 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
94 /****************************************************************************
95 run a specified test or "ALL"
96 ****************************************************************************/
97 static bool run_test(struct torture_context
*torture
, const char *name
)
100 bool matched
= false;
101 struct torture_suite
*o
;
103 if (strequal(name
, "ALL")) {
104 for (o
= torture_root
->children
; o
; o
= o
->next
) {
105 ret
&= torture_run_suite(torture
, o
);
110 ret
= run_matching(torture
, NULL
, name
, NULL
, &matched
);
113 printf("Unknown torture operation '%s'\n", name
);
120 static void parse_dns(const char *dns
)
122 char *userdn
, *basedn
, *secret
;
125 /* retrievieng the userdn */
126 p
= strchr_m(dns
, '#');
128 lp_set_cmdline("torture:ldap_userdn", "");
129 lp_set_cmdline("torture:ldap_basedn", "");
130 lp_set_cmdline("torture:ldap_secret", "");
133 userdn
= strndup(dns
, p
- dns
);
134 lp_set_cmdline("torture:ldap_userdn", userdn
);
136 /* retrieve the basedn */
138 p
= strchr_m(d
, '#');
140 lp_set_cmdline("torture:ldap_basedn", "");
141 lp_set_cmdline("torture:ldap_secret", "");
144 basedn
= strndup(d
, p
- d
);
145 lp_set_cmdline("torture:ldap_basedn", basedn
);
147 /* retrieve the secret */
150 lp_set_cmdline("torture:ldap_secret", "");
154 lp_set_cmdline("torture:ldap_secret", secret
);
156 printf ("%s - %s - %s\n", userdn
, basedn
, secret
);
160 static void usage(poptContext pc
)
162 struct torture_suite
*o
;
163 struct torture_suite
*s
;
164 struct torture_tcase
*t
;
167 poptPrintUsage(pc
, stdout
, 0);
170 printf("The binding format is:\n\n");
172 printf(" TRANSPORT:host[flags]\n\n");
174 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
175 printf(" or ncalrpc for local connections.\n\n");
177 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
178 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
179 printf(" string.\n\n");
181 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
182 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
183 printf(" will be auto-determined.\n\n");
185 printf(" other recognised flags are:\n\n");
187 printf(" sign : enable ntlmssp signing\n");
188 printf(" seal : enable ntlmssp sealing\n");
189 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
190 printf(" validate: enable the NDR validator\n");
191 printf(" print: enable debugging of the packets\n");
192 printf(" bigendian: use bigendian RPC\n");
193 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
195 printf(" For example, these all connect to the samr pipe:\n\n");
197 printf(" ncacn_np:myserver\n");
198 printf(" ncacn_np:myserver[samr]\n");
199 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
200 printf(" ncacn_np:myserver[/pipe/samr]\n");
201 printf(" ncacn_np:myserver[samr,sign,print]\n");
202 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
203 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
204 printf(" ncacn_np:\n");
205 printf(" ncacn_np:[/pipe/samr]\n\n");
207 printf(" ncacn_ip_tcp:myserver\n");
208 printf(" ncacn_ip_tcp:myserver[1024]\n");
209 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
211 printf(" ncalrpc:\n\n");
213 printf("The UNC format is:\n\n");
215 printf(" //server/share\n\n");
217 printf("Tests are:");
219 for (o
= torture_root
->children
; o
; o
= o
->next
) {
220 printf("\n%s (%s):\n ", o
->description
, o
->name
);
223 for (s
= o
->children
; s
; s
= s
->next
) {
224 if (i
+ strlen(o
->name
) + strlen(s
->name
) >= (MAX_COLS
- 3)) {
228 i
+=printf("%s-%s ", o
->name
, s
->name
);
231 for (t
= o
->testcases
; t
; t
= t
->next
) {
232 if (i
+ strlen(o
->name
) + strlen(t
->name
) >= (MAX_COLS
- 3)) {
236 i
+=printf("%s-%s ", o
->name
, t
->name
);
242 printf("\nThe default test is ALL.\n");
247 static bool is_binding_string(const char *binding_string
)
249 TALLOC_CTX
*mem_ctx
= talloc_named_const(NULL
, 0, "is_binding_string");
250 struct dcerpc_binding
*binding_struct
;
253 status
= dcerpc_parse_binding(mem_ctx
, binding_string
, &binding_struct
);
255 talloc_free(mem_ctx
);
256 return NT_STATUS_IS_OK(status
);
259 static void max_runtime_handler(int sig
)
261 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
265 struct timeval last_suite_started
;
267 static void simple_suite_start(struct torture_context
*ctx
,
268 struct torture_suite
*suite
)
270 last_suite_started
= timeval_current();
271 printf("Running %s\n", suite
->name
);
274 static void simple_suite_finish(struct torture_context
*ctx
,
275 struct torture_suite
*suite
)
278 printf("%s took %g secs\n\n", suite
->name
,
279 timeval_elapsed(&last_suite_started
));
282 static void simple_test_result (struct torture_context
*context
,
283 enum torture_result res
, const char *reason
)
288 printf("OK: %s\n", reason
);
291 printf("TEST %s FAILED! - %s\n", context
->active_test
->name
, reason
);
294 printf("ERROR IN TEST %s! - %s\n", context
->active_test
->name
, reason
);
297 printf("SKIP: %s - %s\n", context
->active_test
->name
, reason
);
302 static void simple_comment (struct torture_context
*test
,
305 printf("%s", comment
);
308 const static struct torture_ui_ops std_ui_ops
= {
309 .comment
= simple_comment
,
310 .suite_start
= simple_suite_start
,
311 .suite_finish
= simple_suite_finish
,
312 .test_result
= simple_test_result
316 static void subunit_test_start (struct torture_context
*ctx
,
317 struct torture_tcase
*tcase
,
318 struct torture_test
*test
)
320 printf("test: %s\n", test
->name
);
323 static void subunit_test_result (struct torture_context
*context
,
324 enum torture_result res
, const char *reason
)
328 printf("success: %s", context
->active_test
->name
);
331 printf("failure: %s", context
->active_test
->name
);
334 printf("error: %s", context
->active_test
->name
);
337 printf("skip: %s", context
->active_test
->name
);
341 printf(" [ %s ]", reason
);
345 static void subunit_comment (struct torture_context
*test
,
348 fprintf(stderr
, "%s", comment
);
351 const static struct torture_ui_ops subunit_ui_ops
= {
352 .comment
= subunit_comment
,
353 .test_start
= subunit_test_start
,
354 .test_result
= subunit_test_result
357 static void harness_test_start (struct torture_context
*ctx
,
358 struct torture_tcase
*tcase
,
359 struct torture_test
*test
)
363 static void harness_test_result (struct torture_context
*context
,
364 enum torture_result res
, const char *reason
)
368 printf("ok %s - %s\n", context
->active_test
->name
, reason
);
372 printf("not ok %s - %s\n", context
->active_test
->name
, reason
);
375 printf("skip %s - %s\n", context
->active_test
->name
, reason
);
380 static void harness_comment (struct torture_context
*test
,
383 printf("# %s\n", comment
);
386 const static struct torture_ui_ops harness_ui_ops
= {
387 .comment
= harness_comment
,
388 .test_start
= harness_test_start
,
389 .test_result
= harness_test_result
392 static void quiet_suite_start(struct torture_context
*ctx
,
393 struct torture_suite
*suite
)
397 for (i
= 1; i
< ctx
->level
; i
++) putchar('\t');
398 printf("%s: ", suite
->name
);
402 static void quiet_suite_finish(struct torture_context
*ctx
,
403 struct torture_suite
*suite
)
408 static void quiet_test_result (struct torture_context
*context
,
409 enum torture_result res
, const char *reason
)
413 case TORTURE_OK
: putchar('.'); break;
414 case TORTURE_FAIL
: putchar('F'); break;
415 case TORTURE_ERROR
: putchar('E'); break;
416 case TORTURE_SKIP
: putchar('I'); break;
420 const static struct torture_ui_ops quiet_ui_ops
= {
421 .suite_start
= quiet_suite_start
,
422 .suite_finish
= quiet_suite_finish
,
423 .test_result
= quiet_test_result
427 /****************************************************************************
429 ****************************************************************************/
430 int main(int argc
,char *argv
[])
436 struct torture_context
*torture
;
437 const struct torture_ui_ops
*ui_ops
;
440 static const char *target
= "other";
441 const char **subunit_dir
;
442 static const char *ui_ops_name
= "simple";
443 enum {OPT_LOADFILE
=1000,OPT_UNCLIST
,OPT_TIMELIMIT
,OPT_DNS
,
444 OPT_DANGEROUS
,OPT_SMB_PORTS
,OPT_ASYNC
};
446 struct poptOption long_options
[] = {
448 {"format", 0, POPT_ARG_STRING
, &ui_ops_name
, 0, "Output format (one of: simple, subunit, harness)", NULL
},
449 {"smb-ports", 'p', POPT_ARG_STRING
, NULL
, OPT_SMB_PORTS
, "SMB ports", NULL
},
450 {"seed", 0, POPT_ARG_INT
, &torture_seed
, 0, "seed", NULL
},
451 {"num-ops", 0, POPT_ARG_INT
, &torture_numops
, 0, "num ops", NULL
},
452 {"entries", 0, POPT_ARG_INT
, &torture_entries
, 0, "entries", NULL
},
453 {"show-all", 0, POPT_ARG_NONE
, &torture_showall
, 0, "show all", NULL
},
454 {"loadfile", 0, POPT_ARG_STRING
, NULL
, OPT_LOADFILE
, "loadfile", NULL
},
455 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
456 {"timelimit", 't', POPT_ARG_STRING
, NULL
, OPT_TIMELIMIT
, "timelimit", NULL
},
457 {"failures", 'f', POPT_ARG_INT
, &torture_failures
, 0, "failures", NULL
},
458 {"parse-dns", 'D', POPT_ARG_STRING
, NULL
, OPT_DNS
, "parse-dns", NULL
},
459 {"dangerous", 'X', POPT_ARG_NONE
, NULL
, OPT_DANGEROUS
,
460 "run dangerous tests (eg. wiping out password database)", NULL
},
461 {"target", 'T', POPT_ARG_STRING
, &target
, 0, "samba3|samba4|other", NULL
},
462 {"async", 'a', POPT_ARG_NONE
, NULL
, OPT_ASYNC
,
463 "run async tests", NULL
},
464 {"num-async", 0, POPT_ARG_INT
, &torture_numasync
, 0,
465 "number of simultaneous async requests", NULL
},
466 {"maximum-runtime", 0, POPT_ARG_INT
, &max_runtime
, 0,
467 "set maximum time for smbtorture to live", "seconds"},
469 POPT_COMMON_CONNECTION
470 POPT_COMMON_CREDENTIALS
477 /* we are never interested in SIGPIPE */
478 BlockSignals(true,SIGPIPE
);
480 pc
= poptGetContext("smbtorture", argc
, (const char **) argv
, long_options
,
481 POPT_CONTEXT_KEEP_FIRST
);
483 poptSetOtherOptionHelp(pc
, "<binding>|<unc> TEST1 TEST2 ...");
485 while((opt
= poptGetNextOpt(pc
)) != -1) {
488 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc
));
491 lp_set_cmdline("torture:unclist", poptGetOptArg(pc
));
494 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc
));
497 parse_dns(poptGetOptArg(pc
));
500 lp_set_cmdline("torture:dangerous", "Yes");
503 lp_set_cmdline("torture:async", "Yes");
506 lp_set_cmdline("smb ports", poptGetOptArg(pc
));
509 d_printf("Invalid option %s: %s\n",
510 poptBadOption(pc
, 0), poptStrerror(opt
));
517 if (strcmp(target
, "samba3") == 0) {
518 lp_set_cmdline("torture:samba3", "true");
519 lp_set_cmdline("torture:knownfail", "samba3-knownfail");
520 } else if (strcmp(target
, "samba4") == 0) {
521 lp_set_cmdline("torture:samba4", "true");
522 lp_set_cmdline("torture:knownfail", "samba4-knownfail");
526 /* this will only work if nobody else uses alarm(),
527 which means it won't work for some tests, but we
528 can't use the event context method we use for smbd
529 as so many tests create their own event
530 context. This will at least catch most cases. */
531 signal(SIGALRM
, max_runtime_handler
);
538 subunit_dir
= lp_parm_string_list(-1, "torture", "subunitdir", ":");
539 if (subunit_dir
== NULL
)
540 torture_subunit_load_testsuites(dyn_TORTUREDIR
, true, NULL
);
542 for (i
= 0; subunit_dir
[i
]; i
++)
543 torture_subunit_load_testsuites(subunit_dir
[i
], true, NULL
);
546 if (torture_seed
== 0) {
547 torture_seed
= time(NULL
);
549 printf("Using seed %d\n", torture_seed
);
550 srandom(torture_seed
);
552 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
555 for (i
=0; i
<argc
; i
++) {
556 if (argv_new
[i
] == NULL
) {
567 /* see if its a RPC transport specifier */
568 if (is_binding_string(argv_new
[1])) {
569 lp_set_cmdline("torture:binding", argv_new
[1]);
571 char *binding
= NULL
;
572 char *host
= NULL
, *share
= NULL
;
574 if (!smbcli_parse_unc(argv_new
[1], NULL
, &host
, &share
)) {
575 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new
[1]);
579 lp_set_cmdline("torture:host", host
);
580 lp_set_cmdline("torture:share", share
);
581 asprintf(&binding
, "ncacn_np:%s", host
);
582 lp_set_cmdline("torture:binding", binding
);
585 if (!strcmp(ui_ops_name
, "simple")) {
586 ui_ops
= &std_ui_ops
;
587 } else if (!strcmp(ui_ops_name
, "subunit")) {
588 ui_ops
= &subunit_ui_ops
;
589 } else if (!strcmp(ui_ops_name
, "harness")) {
590 ui_ops
= &harness_ui_ops
;
591 } else if (!strcmp(ui_ops_name
, "quiet")) {
592 ui_ops
= &quiet_ui_ops
;
594 printf("Unknown output format '%s'\n", ui_ops_name
);
598 torture
= torture_context_init(talloc_autofree_context(),
599 lp_parm_string(-1, "torture", "knownfail"), ui_ops
);
602 printf("You must specify a test to run, or 'ALL'\n");
606 int unexpected_failures
;
607 for (i
=2;i
<argc_new
;i
++) {
608 if (!run_test(torture
, argv_new
[i
])) {
614 unexpected_failures
= str_list_length(torture
->results
.unexpected_failures
);
616 total
= torture
->results
.skipped
+torture
->results
.success
+torture
->results
.failed
+torture
->results
.errors
;
618 printf("No tests run.\n");
620 rate
= ((total
- unexpected_failures
- torture
->results
.errors
) * (100.0 / total
));
622 printf("Tests: %d, Failures: %d", total
, torture
->results
.failed
);
623 if (torture
->results
.failed
- unexpected_failures
) {
624 printf(" (%d expected)", torture
->results
.failed
- unexpected_failures
);
626 printf(", Errors: %d, Skipped: %d. Success rate: %.2f%%\n",
627 torture
->results
.errors
, torture
->results
.skipped
, rate
);
630 if (unexpected_failures
) {
631 printf("The following tests failed:\n");
632 for (i
= 0; torture
->results
.unexpected_failures
[i
]; i
++) {
633 printf(" %s\n", torture
->results
.unexpected_failures
[i
]);
638 if (str_list_length(torture
->results
.unexpected_errors
)) {
639 printf("Errors occurred while running the following tests:\n");
640 for (i
= 0; torture
->results
.unexpected_errors
[i
]; i
++) {
641 printf(" %s\n", torture
->results
.unexpected_errors
[i
]);
646 if (str_list_length(torture
->results
.unexpected_successes
)) {
647 printf("The following tests were expected to fail but succeeded:\n");
648 for (i
= 0; torture
->results
.unexpected_successes
[i
]; i
++) {
649 printf(" %s\n", torture
->results
.unexpected_successes
[i
]);
655 if (torture
->results
.returncode
) {