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
;
408 const char *extra_module
= NULL
;
409 static int list_tests
= 0;
410 int num_extra_users
= 0;
411 char **restricted
= NULL
;
412 int num_restricted
= -1;
413 const char *load_list
= NULL
;
414 enum {OPT_LOADFILE
=1000,OPT_UNCLIST
,OPT_TIMELIMIT
,OPT_DNS
, OPT_LIST
,
415 OPT_DANGEROUS
,OPT_SMB_PORTS
,OPT_ASYNC
,OPT_NUMPROGS
,
418 struct poptOption long_options
[] = {
420 {"format", 0, POPT_ARG_STRING
, &ui_ops_name
, 0, "Output format (one of: simple, subunit)", NULL
},
421 {"smb-ports", 'p', POPT_ARG_STRING
, NULL
, OPT_SMB_PORTS
, "SMB ports", NULL
},
422 {"basedir", 0, POPT_ARG_STRING
, &basedir
, 0, "base directory", "BASEDIR" },
423 {"seed", 0, POPT_ARG_INT
, &torture_seed
, 0, "Seed to use for randomizer", NULL
},
424 {"num-progs", 0, POPT_ARG_INT
, NULL
, OPT_NUMPROGS
, "num progs", NULL
},
425 {"num-ops", 0, POPT_ARG_INT
, &torture_numops
, 0, "num ops", NULL
},
426 {"entries", 0, POPT_ARG_INT
, &torture_entries
, 0, "entries", NULL
},
427 {"loadfile", 0, POPT_ARG_STRING
, NULL
, OPT_LOADFILE
, "NBench load file to use", NULL
},
428 {"list", 0, POPT_ARG_NONE
, &list_tests
, 0, "List available tests and exit", NULL
},
429 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
430 {"timelimit", 't', POPT_ARG_INT
, NULL
, OPT_TIMELIMIT
, "Set time limit (in seconds)", NULL
},
431 {"failures", 'f', POPT_ARG_INT
, &torture_failures
, 0, "failures", NULL
},
432 {"parse-dns", 'D', POPT_ARG_STRING
, NULL
, OPT_DNS
, "parse-dns", NULL
},
433 {"dangerous", 'X', POPT_ARG_NONE
, NULL
, OPT_DANGEROUS
,
434 "run dangerous tests (eg. wiping out password database)", NULL
},
435 {"load-module", 0, POPT_ARG_STRING
, &extra_module
, 0, "load tests from DSO file", "SOFILE"},
436 {"shell", 0, POPT_ARG_NONE
, &shell
, true, "Run shell", NULL
},
437 {"target", 'T', POPT_ARG_STRING
, &target
, 0, "samba3|samba4|other", NULL
},
438 {"async", 'a', POPT_ARG_NONE
, NULL
, OPT_ASYNC
,
439 "run async tests", NULL
},
440 {"num-async", 0, POPT_ARG_INT
, &torture_numasync
, 0,
441 "number of simultaneous async requests", NULL
},
442 {"maximum-runtime", 0, POPT_ARG_INT
, &max_runtime
, 0,
443 "set maximum time for smbtorture to live", "seconds"},
444 {"extra-user", 0, POPT_ARG_STRING
, NULL
, OPT_EXTRA_USER
,
445 "extra user credentials", NULL
},
446 {"load-list", 0, POPT_ARG_STRING
, &load_list
, 0,
447 "load a test id list from a text file", NULL
},
449 POPT_COMMON_CONNECTION
450 POPT_COMMON_CREDENTIALS
457 /* we are never interested in SIGPIPE */
458 BlockSignals(true, SIGPIPE
);
460 pc
= poptGetContext("smbtorture", argc
, (const char **) argv
, long_options
,
461 POPT_CONTEXT_KEEP_FIRST
);
463 poptSetOtherOptionHelp(pc
, "<binding>|<unc> TEST1 TEST2 ...");
465 while((opt
= poptGetNextOpt(pc
)) != -1) {
468 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:loadfile", poptGetOptArg(pc
));
471 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:unclist", poptGetOptArg(pc
));
474 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:timelimit", poptGetOptArg(pc
));
477 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:nprocs", poptGetOptArg(pc
));
480 parse_dns(cmdline_lp_ctx
, poptGetOptArg(pc
));
483 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:dangerous", "Yes");
486 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:async", "Yes");
489 lpcfg_set_cmdline(cmdline_lp_ctx
, "smb ports", poptGetOptArg(pc
));
493 char *option
= talloc_asprintf(NULL
, "torture:extra_user%u",
495 const char *value
= poptGetOptArg(pc
);
496 lpcfg_set_cmdline(cmdline_lp_ctx
, option
, value
);
502 printf("bad command line option %d\n", opt
);
508 if (load_list
!= NULL
) {
509 restricted
= file_lines_load(load_list
, &num_restricted
, 0,
510 talloc_autofree_context());
511 if (restricted
== NULL
) {
512 printf("Unable to read load list file '%s'\n", load_list
);
517 if (strcmp(target
, "samba3") == 0) {
518 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:samba3", "true");
519 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
520 } else if (strcmp(target
, "samba4") == 0) {
521 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:samba4", "true");
522 } else if (strcmp(target
, "winxp") == 0) {
523 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:winxp", "true");
524 } else if (strcmp(target
, "w2k3") == 0) {
525 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:w2k3", "true");
526 } else if (strcmp(target
, "w2k8") == 0) {
527 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:w2k8", "true");
528 lpcfg_set_cmdline(cmdline_lp_ctx
,
529 "torture:invalid_lock_range_support", "false");
530 } else if (strcmp(target
, "win7") == 0) {
531 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:win7", "true");
532 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:cn_max_buffer_size",
534 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
535 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:rewind_support", "false");
537 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
538 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:search_ea_support", "false");
540 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:hide_on_access_denied",
542 } else if (strcmp(target
, "onefs") == 0) {
543 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:onefs", "true");
544 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:openx_deny_dos_support",
546 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:range_not_locked_on_file_close", "false");
547 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:sacl_support", "false");
548 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:ea_support", "false");
549 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:smbexit_pdu_support",
551 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:smblock_pdu_support",
553 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:2_step_break_to_none",
555 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:deny_dos_support", "false");
556 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:deny_fcb_support", "false");
557 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:read_support", "false");
558 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:writeclose_support", "false");
559 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
560 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:rewind_support", "false");
561 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:raw_search_search", "false");
562 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:search_ea_size", "false");
566 /* this will only work if nobody else uses alarm(),
567 which means it won't work for some tests, but we
568 can't use the event context method we use for smbd
569 as so many tests create their own event
570 context. This will at least catch most cases. */
571 signal(SIGALRM
, max_runtime_handler
);
575 if (extra_module
!= NULL
) {
576 init_module_fn fn
= load_module(talloc_autofree_context(), poptGetOptArg(pc
));
579 d_printf("Unable to load module from %s\n", poptGetOptArg(pc
));
582 if (NT_STATUS_IS_ERR(status
)) {
583 d_printf("Error initializing module %s: %s\n",
584 poptGetOptArg(pc
), nt_errstr(status
));
596 if (torture_seed
== 0) {
597 torture_seed
= time(NULL
);
599 printf("Using seed %d\n", torture_seed
);
600 srandom(torture_seed
);
602 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
605 for (i
=0; i
<argc
; i
++) {
606 if (argv_new
[i
] == NULL
) {
612 if (!strcmp(ui_ops_name
, "simple")) {
613 ui_ops
= &std_ui_ops
;
614 } else if (!strcmp(ui_ops_name
, "subunit")) {
615 ui_ops
= &torture_subunit_ui_ops
;
617 printf("Unknown output format '%s'\n", ui_ops_name
);
621 results
= torture_results_init(talloc_autofree_context(), ui_ops
);
623 torture
= torture_context_init(s4_event_context_init(talloc_autofree_context()),
625 if (basedir
!= NULL
) {
626 if (basedir
[0] != '/') {
627 fprintf(stderr
, "Please specify an absolute path to --basedir\n");
630 outputdir
= talloc_asprintf(torture
, "%s/smbtortureXXXXXX", basedir
);
632 char *pwd
= talloc_size(torture
, PATH_MAX
);
633 if (!getcwd(pwd
, PATH_MAX
)) {
634 fprintf(stderr
, "Unable to determine current working directory\n");
637 outputdir
= talloc_asprintf(torture
, "%s/smbtortureXXXXXX", pwd
);
640 fprintf(stderr
, "Could not allocate per-run output dir\n");
643 torture
->outputdir
= mkdtemp(outputdir
);
644 if (!torture
->outputdir
) {
645 perror("Failed to make temp output dir");
648 torture
->lp_ctx
= cmdline_lp_ctx
;
650 gensec_init(cmdline_lp_ctx
);
653 /* In shell mode, just ignore any remaining test names. */
654 torture_shell(torture
);
657 /* At this point, we should just have a target string,
658 * followed by a series of test names. Unless we are in
659 * shell mode, in which case we don't need anythig more.
663 printf("You must specify a test to run, or 'ALL'\n");
668 /* Take the target name or binding. */
669 if (!torture_parse_target(cmdline_lp_ctx
, argv_new
[1])) {
674 for (i
=2;i
<argc_new
;i
++) {
675 if (!torture_run_named_tests(torture
, argv_new
[i
],
676 (const char **)restricted
)) {
682 /* Now delete the temp dir we created */
683 torture_deltree_outputdir(torture
);
685 if (torture
->results
->returncode
&& correct
) {