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 "system/readline.h"
28 #include "lib/smbreadline/smbreadline.h"
29 #include "libcli/libcli.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/events/events.h"
32 #include "dynconfig.h"
34 #include "torture/torture.h"
36 #include "lib/util/dlinklist.h"
37 #include "librpc/rpc/dcerpc.h"
39 static bool run_matching(struct torture_context
*torture
,
42 struct torture_suite
*suite
,
48 struct torture_suite
*o
;
50 for (o
= torture_root
->children
; o
; o
= o
->next
) {
51 if (gen_fnmatch(expr
, o
->name
) == 0) {
54 ret
&= torture_run_suite(torture
, o
);
58 ret
&= run_matching(torture
, o
->name
, expr
, o
, matched
);
62 struct torture_suite
*c
;
63 struct torture_tcase
*t
;
65 for (c
= suite
->children
; c
; c
= c
->next
) {
66 asprintf(&name
, "%s-%s", prefix
, c
->name
);
68 if (gen_fnmatch(expr
, name
) == 0) {
71 torture
->active_testname
= talloc_strdup(torture
, prefix
);
72 ret
&= torture_run_suite(torture
, c
);
77 ret
&= run_matching(torture
, name
, expr
, c
, matched
);
82 for (t
= suite
->testcases
; t
; t
= t
->next
) {
83 asprintf(&name
, "%s-%s", prefix
, t
->name
);
84 if (gen_fnmatch(expr
, name
) == 0) {
87 torture
->active_testname
= talloc_strdup(torture
, prefix
);
88 ret
&= torture_run_tcase(torture
, t
);
89 talloc_free(torture
->active_testname
);
98 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
100 /****************************************************************************
101 run a specified test or "ALL"
102 ****************************************************************************/
103 static bool run_test(struct torture_context
*torture
, const char *name
)
106 bool matched
= false;
107 struct torture_suite
*o
;
109 if (strequal(name
, "ALL")) {
110 for (o
= torture_root
->children
; o
; o
= o
->next
) {
111 ret
&= torture_run_suite(torture
, o
);
116 ret
= run_matching(torture
, NULL
, name
, NULL
, &matched
);
119 printf("Unknown torture operation '%s'\n", name
);
126 static void parse_dns(const char *dns
)
128 char *userdn
, *basedn
, *secret
;
131 /* retrievieng the userdn */
132 p
= strchr_m(dns
, '#');
134 lp_set_cmdline("torture:ldap_userdn", "");
135 lp_set_cmdline("torture:ldap_basedn", "");
136 lp_set_cmdline("torture:ldap_secret", "");
139 userdn
= strndup(dns
, p
- dns
);
140 lp_set_cmdline("torture:ldap_userdn", userdn
);
142 /* retrieve the basedn */
144 p
= strchr_m(d
, '#');
146 lp_set_cmdline("torture:ldap_basedn", "");
147 lp_set_cmdline("torture:ldap_secret", "");
150 basedn
= strndup(d
, p
- d
);
151 lp_set_cmdline("torture:ldap_basedn", basedn
);
153 /* retrieve the secret */
156 lp_set_cmdline("torture:ldap_secret", "");
160 lp_set_cmdline("torture:ldap_secret", secret
);
162 printf ("%s - %s - %s\n", userdn
, basedn
, secret
);
166 static void print_test_list(void)
168 struct torture_suite
*o
;
169 struct torture_suite
*s
;
170 struct torture_tcase
*t
;
172 for (o
= torture_root
->children
; o
; o
= o
->next
) {
173 for (s
= o
->children
; s
; s
= s
->next
) {
174 printf("%s-%s\n", o
->name
, s
->name
);
177 for (t
= o
->testcases
; t
; t
= t
->next
) {
178 printf("%s-%s\n", o
->name
, t
->name
);
183 static void usage(poptContext pc
)
185 struct torture_suite
*o
;
186 struct torture_suite
*s
;
187 struct torture_tcase
*t
;
190 poptPrintUsage(pc
, stdout
, 0);
193 printf("The binding format is:\n\n");
195 printf(" TRANSPORT:host[flags]\n\n");
197 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
198 printf(" or ncalrpc for local connections.\n\n");
200 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
201 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
202 printf(" string.\n\n");
204 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
205 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
206 printf(" will be auto-determined.\n\n");
208 printf(" other recognised flags are:\n\n");
210 printf(" sign : enable ntlmssp signing\n");
211 printf(" seal : enable ntlmssp sealing\n");
212 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
213 printf(" validate: enable the NDR validator\n");
214 printf(" print: enable debugging of the packets\n");
215 printf(" bigendian: use bigendian RPC\n");
216 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
218 printf(" For example, these all connect to the samr pipe:\n\n");
220 printf(" ncacn_np:myserver\n");
221 printf(" ncacn_np:myserver[samr]\n");
222 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
223 printf(" ncacn_np:myserver[/pipe/samr]\n");
224 printf(" ncacn_np:myserver[samr,sign,print]\n");
225 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
226 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
227 printf(" ncacn_np:\n");
228 printf(" ncacn_np:[/pipe/samr]\n\n");
230 printf(" ncacn_ip_tcp:myserver\n");
231 printf(" ncacn_ip_tcp:myserver[1024]\n");
232 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
234 printf(" ncalrpc:\n\n");
236 printf("The UNC format is:\n\n");
238 printf(" //server/share\n\n");
240 printf("Tests are:");
242 for (o
= torture_root
->children
; o
; o
= o
->next
) {
243 printf("\n%s (%s):\n ", o
->description
, o
->name
);
246 for (s
= o
->children
; s
; s
= s
->next
) {
247 if (i
+ strlen(o
->name
) + strlen(s
->name
) >= (MAX_COLS
- 3)) {
251 i
+=printf("%s-%s ", o
->name
, s
->name
);
254 for (t
= o
->testcases
; t
; t
= t
->next
) {
255 if (i
+ strlen(o
->name
) + strlen(t
->name
) >= (MAX_COLS
- 3)) {
259 i
+=printf("%s-%s ", o
->name
, t
->name
);
265 printf("\nThe default test is ALL.\n");
270 static void max_runtime_handler(int sig
)
272 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
276 struct timeval last_suite_started
;
278 static void simple_suite_start(struct torture_context
*ctx
,
279 struct torture_suite
*suite
)
281 last_suite_started
= timeval_current();
282 printf("Running %s\n", suite
->name
);
285 static void simple_suite_finish(struct torture_context
*ctx
,
286 struct torture_suite
*suite
)
289 printf("%s took %g secs\n\n", suite
->name
,
290 timeval_elapsed(&last_suite_started
));
293 static void simple_test_result (struct torture_context
*context
,
294 enum torture_result res
, const char *reason
)
299 printf("OK: %s\n", reason
);
302 printf("TEST %s FAILED! - %s\n", context
->active_test
->name
, reason
);
305 printf("ERROR IN TEST %s! - %s\n", context
->active_test
->name
, reason
);
308 printf("SKIP: %s - %s\n", context
->active_test
->name
, reason
);
313 static void simple_comment (struct torture_context
*test
,
316 printf("%s", comment
);
319 static void simple_warning(struct torture_context
*test
,
322 fprintf(stderr
, "WARNING: %s\n", comment
);
325 const static struct torture_ui_ops std_ui_ops
= {
326 .comment
= simple_comment
,
327 .warning
= simple_warning
,
328 .suite_start
= simple_suite_start
,
329 .suite_finish
= simple_suite_finish
,
330 .test_result
= simple_test_result
333 static void subunit_init(struct torture_context
*ctx
)
335 /* FIXME: register segv and bus handler */
338 static void subunit_suite_start(struct torture_context
*ctx
,
339 struct torture_suite
*suite
)
341 printf("testsuite: %s\n", suite
->name
);
344 static void subunit_test_start (struct torture_context
*ctx
,
345 struct torture_tcase
*tcase
,
346 struct torture_test
*test
)
348 printf("test: %s\n", test
->name
);
351 static void subunit_test_result (struct torture_context
*context
,
352 enum torture_result res
, const char *reason
)
356 printf("success: %s", context
->active_test
->name
);
359 printf("failure: %s", context
->active_test
->name
);
362 printf("error: %s", context
->active_test
->name
);
365 printf("skip: %s", context
->active_test
->name
);
369 printf(" [\n%s\n]", reason
);
373 static void subunit_comment (struct torture_context
*test
,
376 fprintf(stderr
, "%s", comment
);
379 const static struct torture_ui_ops subunit_ui_ops
= {
380 .init
= subunit_init
,
381 .comment
= subunit_comment
,
382 .test_start
= subunit_test_start
,
383 .test_result
= subunit_test_result
,
384 .suite_start
= subunit_suite_start
387 static void harness_test_start (struct torture_context
*ctx
,
388 struct torture_tcase
*tcase
,
389 struct torture_test
*test
)
393 static void harness_test_result (struct torture_context
*context
,
394 enum torture_result res
, const char *reason
)
398 printf("ok %s - %s\n", context
->active_test
->name
, reason
);
402 printf("not ok %s - %s\n", context
->active_test
->name
, reason
);
405 printf("skip %s - %s\n", context
->active_test
->name
, reason
);
410 static void harness_comment (struct torture_context
*test
,
413 printf("# %s\n", comment
);
416 const static struct torture_ui_ops harness_ui_ops
= {
417 .comment
= harness_comment
,
418 .test_start
= harness_test_start
,
419 .test_result
= harness_test_result
422 static void quiet_suite_start(struct torture_context
*ctx
,
423 struct torture_suite
*suite
)
427 for (i
= 1; i
< ctx
->level
; i
++) putchar('\t');
428 printf("%s: ", suite
->name
);
432 static void quiet_suite_finish(struct torture_context
*ctx
,
433 struct torture_suite
*suite
)
438 static void quiet_test_result (struct torture_context
*context
,
439 enum torture_result res
, const char *reason
)
443 case TORTURE_OK
: putchar('.'); break;
444 case TORTURE_FAIL
: putchar('F'); break;
445 case TORTURE_ERROR
: putchar('E'); break;
446 case TORTURE_SKIP
: putchar('I'); break;
450 const static struct torture_ui_ops quiet_ui_ops
= {
451 .suite_start
= quiet_suite_start
,
452 .suite_finish
= quiet_suite_finish
,
453 .test_result
= quiet_test_result
456 void run_shell(struct torture_context
*tctx
)
464 cline
= smb_readline("torture> ", NULL
, NULL
);
469 ret
= poptParseArgvString(cline
, &argc
, &argv
);
471 fprintf(stderr
, "Error parsing line\n");
475 if (!strcmp(argv
[0], "quit")) {
477 } else if (!strcmp(argv
[0], "set")) {
479 fprintf(stderr
, "Usage: set <variable> <value>\n");
481 char *name
= talloc_asprintf(NULL
, "torture:%s", argv
[1]);
482 lp_set_cmdline(name
, argv
[2]);
485 } else if (!strcmp(argv
[0], "help")) {
486 fprintf(stderr
, "Available commands:\n"
487 " help - This help command\n"
489 " set - Change variables\n"
491 } else if (!strcmp(argv
[0], "run")) {
493 fprintf(stderr
, "Usage: run TEST-NAME [OPTIONS...]\n");
495 run_test(tctx
, argv
[1]);
501 /****************************************************************************
503 ****************************************************************************/
504 int main(int argc
,char *argv
[])
510 struct torture_context
*torture
;
511 const struct torture_ui_ops
*ui_ops
;
514 static const char *target
= "other";
515 struct dcerpc_binding
*binding_struct
;
518 static const char *ui_ops_name
= "simple";
519 static int list_tests
= 0;
520 enum {OPT_LOADFILE
=1000,OPT_UNCLIST
,OPT_TIMELIMIT
,OPT_DNS
, OPT_LIST
,
521 OPT_DANGEROUS
,OPT_SMB_PORTS
,OPT_ASYNC
,OPT_NUMPROGS
, OPT_BASEDIR
};
523 struct poptOption long_options
[] = {
525 {"format", 0, POPT_ARG_STRING
, &ui_ops_name
, 0, "Output format (one of: simple, subunit, harness)", NULL
},
526 {"smb-ports", 'p', POPT_ARG_STRING
, NULL
, OPT_SMB_PORTS
, "SMB ports", NULL
},
527 {"basedir", 0, POPT_ARG_STRING
, NULL
, OPT_BASEDIR
, "base directory", "BSAEDIR" },
528 {"seed", 0, POPT_ARG_INT
, &torture_seed
, 0, "seed", NULL
},
529 {"num-progs", 0, POPT_ARG_INT
, NULL
, OPT_NUMPROGS
, "num progs", NULL
},
530 {"num-ops", 0, POPT_ARG_INT
, &torture_numops
, 0, "num ops", NULL
},
531 {"entries", 0, POPT_ARG_INT
, &torture_entries
, 0, "entries", NULL
},
532 {"loadfile", 0, POPT_ARG_STRING
, NULL
, OPT_LOADFILE
, "loadfile", NULL
},
533 {"list", 0, POPT_ARG_NONE
, &list_tests
, 0, NULL
, NULL
},
534 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
535 {"timelimit", 't', POPT_ARG_INT
, NULL
, OPT_TIMELIMIT
, "timelimit", NULL
},
536 {"failures", 'f', POPT_ARG_INT
, &torture_failures
, 0, "failures", NULL
},
537 {"parse-dns", 'D', POPT_ARG_STRING
, NULL
, OPT_DNS
, "parse-dns", NULL
},
538 {"dangerous", 'X', POPT_ARG_NONE
, NULL
, OPT_DANGEROUS
,
539 "run dangerous tests (eg. wiping out password database)", NULL
},
540 {"shell", 0, POPT_ARG_NONE
, &shell
, True
, "Run shell", NULL
},
541 {"target", 'T', POPT_ARG_STRING
, &target
, 0, "samba3|samba4|other", NULL
},
542 {"async", 'a', POPT_ARG_NONE
, NULL
, OPT_ASYNC
,
543 "run async tests", NULL
},
544 {"num-async", 0, POPT_ARG_INT
, &torture_numasync
, 0,
545 "number of simultaneous async requests", NULL
},
546 {"maximum-runtime", 0, POPT_ARG_INT
, &max_runtime
, 0,
547 "set maximum time for smbtorture to live", "seconds"},
549 POPT_COMMON_CONNECTION
550 POPT_COMMON_CREDENTIALS
557 /* we are never interested in SIGPIPE */
558 BlockSignals(true, SIGPIPE
);
560 pc
= poptGetContext("smbtorture", argc
, (const char **) argv
, long_options
,
561 POPT_CONTEXT_KEEP_FIRST
);
563 poptSetOtherOptionHelp(pc
, "<binding>|<unc> TEST1 TEST2 ...");
565 while((opt
= poptGetNextOpt(pc
)) != -1) {
568 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc
));
571 lp_set_cmdline("torture:unclist", poptGetOptArg(pc
));
574 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc
));
577 lp_set_cmdline("torture:nprocs", poptGetOptArg(pc
));
580 lp_set_cmdline("torture:basedir", poptGetOptArg(pc
));
583 parse_dns(poptGetOptArg(pc
));
586 lp_set_cmdline("torture:dangerous", "Yes");
589 lp_set_cmdline("torture:async", "Yes");
592 lp_set_cmdline("smb ports", poptGetOptArg(pc
));
597 if (strcmp(target
, "samba3") == 0) {
598 lp_set_cmdline("torture:samba3", "true");
599 } else if (strcmp(target
, "samba4") == 0) {
600 lp_set_cmdline("torture:samba4", "true");
604 /* this will only work if nobody else uses alarm(),
605 which means it won't work for some tests, but we
606 can't use the event context method we use for smbd
607 as so many tests create their own event
608 context. This will at least catch most cases. */
609 signal(SIGALRM
, max_runtime_handler
);
621 if (torture_seed
== 0) {
622 torture_seed
= time(NULL
);
624 printf("Using seed %d\n", torture_seed
);
625 srandom(torture_seed
);
627 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
630 for (i
=0; i
<argc
; i
++) {
631 if (argv_new
[i
] == NULL
) {
637 if (!(argc_new
>= 3 || (shell
&& argc_new
>= 2))) {
642 /* see if its a RPC transport specifier */
643 status
= dcerpc_parse_binding(talloc_autofree_context(), argv_new
[1], &binding_struct
);
644 if (NT_STATUS_IS_OK(status
)) {
645 lp_set_cmdline("torture:host", binding_struct
->host
);
646 lp_set_cmdline("torture:share", "IPC$");
647 lp_set_cmdline("torture:binding", argv_new
[1]);
649 char *binding
= NULL
;
650 char *host
= NULL
, *share
= NULL
;
652 if (!smbcli_parse_unc(argv_new
[1], NULL
, &host
, &share
)) {
653 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new
[1]);
657 lp_set_cmdline("torture:host", host
);
658 lp_set_cmdline("torture:share", share
);
659 asprintf(&binding
, "ncacn_np:%s", host
);
660 lp_set_cmdline("torture:binding", binding
);
663 if (!strcmp(ui_ops_name
, "simple")) {
664 ui_ops
= &std_ui_ops
;
665 } else if (!strcmp(ui_ops_name
, "subunit")) {
666 ui_ops
= &subunit_ui_ops
;
667 } else if (!strcmp(ui_ops_name
, "harness")) {
668 ui_ops
= &harness_ui_ops
;
669 } else if (!strcmp(ui_ops_name
, "quiet")) {
670 ui_ops
= &quiet_ui_ops
;
672 printf("Unknown output format '%s'\n", ui_ops_name
);
676 torture
= torture_context_init(talloc_autofree_context(), ui_ops
);
679 printf("You must specify a test to run, or 'ALL'\n");
683 for (i
=2;i
<argc_new
;i
++) {
684 if (!run_test(torture
, argv_new
[i
])) {
690 if (torture
->returncode
) {