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"
35 #include "lib/util/samba_modules.h"
37 #if HAVE_READLINE_HISTORY_H
38 #include <readline/history.h>
41 static char *prefix_name(TALLOC_CTX
*mem_ctx
, const char *prefix
, const char *name
)
44 return talloc_strdup(mem_ctx
, name
);
46 return talloc_asprintf(mem_ctx
, "%s.%s", prefix
, name
);
49 static void print_test_list(const struct torture_suite
*suite
, const char *prefix
, const char *expr
)
51 struct torture_suite
*o
;
52 struct torture_tcase
*t
;
53 struct torture_test
*p
;
55 for (o
= suite
->children
; o
; o
= o
->next
) {
56 char *name
= prefix_name(NULL
, prefix
, o
->name
);
57 print_test_list(o
, name
, expr
);
61 for (t
= suite
->testcases
; t
; t
= t
->next
) {
62 for (p
= t
->tests
; p
; p
= p
->next
) {
63 char *name
= talloc_asprintf(NULL
, "%s.%s.%s", prefix
, t
->name
, p
->name
);
64 if (strncmp(name
, expr
, strlen(expr
)) == 0) {
72 static bool run_matching(struct torture_context
*torture
,
75 const char **restricted
,
76 struct torture_suite
*suite
,
80 struct torture_suite
*o
;
81 struct torture_tcase
*t
;
82 struct torture_test
*p
;
84 for (o
= suite
->children
; o
; o
= o
->next
) {
86 name
= prefix_name(torture
, prefix
, o
->name
);
87 if (gen_fnmatch(expr
, name
) == 0) {
89 reload_charcnv(torture
->lp_ctx
);
90 if (restricted
!= NULL
)
91 ret
&= torture_run_suite_restricted(torture
, o
, restricted
);
93 ret
&= torture_run_suite(torture
, o
);
95 ret
&= run_matching(torture
, name
, expr
, restricted
, o
, matched
);
98 for (t
= suite
->testcases
; t
; t
= t
->next
) {
99 char *name
= talloc_asprintf(torture
, "%s.%s", prefix
, t
->name
);
100 if (gen_fnmatch(expr
, name
) == 0) {
102 reload_charcnv(torture
->lp_ctx
);
103 ret
&= torture_run_tcase_restricted(torture
, t
, restricted
);
105 for (p
= t
->tests
; p
; p
= p
->next
) {
106 name
= talloc_asprintf(torture
, "%s.%s.%s", prefix
, t
->name
, p
->name
);
107 if (gen_fnmatch(expr
, name
) == 0) {
109 reload_charcnv(torture
->lp_ctx
);
110 ret
&= torture_run_test_restricted(torture
, t
, p
, restricted
);
118 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
120 /****************************************************************************
121 run a specified test or "ALL"
122 ****************************************************************************/
123 bool torture_run_named_tests(struct torture_context
*torture
, const char *name
,
124 const char **restricted
)
127 bool matched
= false;
128 struct torture_suite
*o
;
130 torture_ui_report_time(torture
);
132 if (strequal(name
, "ALL")) {
133 if (restricted
!= NULL
) {
134 printf("--load-list and ALL are incompatible\n");
137 for (o
= torture_root
->children
; o
; o
= o
->next
) {
138 ret
&= torture_run_suite(torture
, o
);
143 ret
= run_matching(torture
, NULL
, name
, restricted
, torture_root
, &matched
);
146 printf("Unknown torture operation '%s'\n", name
);
153 bool torture_parse_target(struct loadparm_context
*lp_ctx
, const char *target
)
155 char *host
= NULL
, *share
= NULL
;
156 struct dcerpc_binding
*binding_struct
;
159 /* see if its a RPC transport specifier */
160 if (!smbcli_parse_unc(target
, NULL
, &host
, &share
)) {
163 status
= dcerpc_parse_binding(talloc_autofree_context(), target
, &binding_struct
);
164 if (NT_STATUS_IS_ERR(status
)) {
165 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target
);
169 h
= dcerpc_binding_get_string_option(binding_struct
, "host");
170 host
= discard_const_p(char, h
);
172 lpcfg_set_cmdline(lp_ctx
, "torture:host", host
);
175 if (lpcfg_parm_string(lp_ctx
, NULL
, "torture", "share") == NULL
)
176 lpcfg_set_cmdline(lp_ctx
, "torture:share", "IPC$");
177 lpcfg_set_cmdline(lp_ctx
, "torture:binding", target
);
179 lpcfg_set_cmdline(lp_ctx
, "torture:host", host
);
180 lpcfg_set_cmdline(lp_ctx
, "torture:share", share
);
181 lpcfg_set_cmdline(lp_ctx
, "torture:binding", host
);
187 static void parse_dns(struct loadparm_context
*lp_ctx
, const char *dns
)
189 char *userdn
, *basedn
, *secret
;
192 /* retrievieng the userdn */
193 p
= strchr_m(dns
, '#');
195 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_userdn", "");
196 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_basedn", "");
197 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_secret", "");
200 userdn
= strndup(dns
, p
- dns
);
201 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_userdn", userdn
);
203 /* retrieve the basedn */
205 p
= strchr_m(d
, '#');
207 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_basedn", "");
208 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_secret", "");
211 basedn
= strndup(d
, p
- d
);
212 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_basedn", basedn
);
214 /* retrieve the secret */
217 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_secret", "");
221 lpcfg_set_cmdline(lp_ctx
, "torture:ldap_secret", secret
);
223 printf ("%s - %s - %s\n", userdn
, basedn
, secret
);
227 /* Print the full test list, formatted into separate labelled test
230 static void print_structured_testsuite_list(void)
232 struct torture_suite
*o
;
233 struct torture_suite
*s
;
234 struct torture_tcase
*t
;
237 if (torture_root
== NULL
) {
238 printf("NO TESTS LOADED\n");
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");
268 static void print_testsuite_list(void)
270 struct torture_suite
*o
;
271 struct torture_suite
*s
;
272 struct torture_tcase
*t
;
274 if (torture_root
== NULL
)
277 for (o
= torture_root
->children
; o
; o
= o
->next
) {
278 for (s
= o
->children
; s
; s
= s
->next
) {
279 printf("%s.%s\n", o
->name
, s
->name
);
282 for (t
= o
->testcases
; t
; t
= t
->next
) {
283 printf("%s.%s\n", o
->name
, t
->name
);
288 void torture_print_testsuites(bool structured
)
291 print_structured_testsuite_list();
293 print_testsuite_list();
297 static void usage(poptContext pc
)
299 poptPrintUsage(pc
, stdout
, 0);
302 printf("The binding format is:\n\n");
304 printf(" TRANSPORT:host[flags]\n\n");
306 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
307 printf(" or ncalrpc for local connections.\n\n");
309 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
310 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
311 printf(" string.\n\n");
313 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
314 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
315 printf(" will be auto-determined.\n\n");
317 printf(" other recognised flags are:\n\n");
319 printf(" sign : enable ntlmssp signing\n");
320 printf(" seal : enable ntlmssp sealing\n");
321 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
322 printf(" validate: enable the NDR validator\n");
323 printf(" print: enable debugging of the packets\n");
324 printf(" bigendian: use bigendian RPC\n");
325 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
327 printf(" For example, these all connect to the samr pipe:\n\n");
329 printf(" ncacn_np:myserver\n");
330 printf(" ncacn_np:myserver[samr]\n");
331 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
332 printf(" ncacn_np:myserver[/pipe/samr]\n");
333 printf(" ncacn_np:myserver[samr,sign,print]\n");
334 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
335 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
336 printf(" ncacn_np:\n");
337 printf(" ncacn_np:[/pipe/samr]\n\n");
339 printf(" ncacn_ip_tcp:myserver\n");
340 printf(" ncacn_ip_tcp:myserver[1024]\n");
341 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
343 printf(" ncalrpc:\n\n");
345 printf("The UNC format is:\n\n");
347 printf(" //server/share\n\n");
349 printf("Tests are:");
351 print_structured_testsuite_list();
355 _NORETURN_
static void max_runtime_handler(int sig
)
357 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
361 /****************************************************************************
363 ****************************************************************************/
364 int main(int argc
, const char *argv
[])
370 struct torture_context
*torture
;
371 struct torture_results
*results
;
372 const struct torture_ui_ops
*ui_ops
;
375 static const char *target
= "other";
378 static const char *ui_ops_name
= "subunit";
379 const char *basedir
= NULL
;
381 const char *extra_module
= NULL
;
382 static int list_tests
= 0, list_testsuites
= 0;
383 int num_extra_users
= 0;
384 const char **restricted
= NULL
;
385 int num_restricted
= -1;
386 const char *load_list
= NULL
;
387 enum {OPT_LOADFILE
=1000,OPT_UNCLIST
,OPT_TIMELIMIT
,OPT_DNS
, OPT_LIST
,
388 OPT_DANGEROUS
,OPT_SMB_PORTS
,OPT_ASYNC
,OPT_NUMPROGS
,
391 struct poptOption long_options
[] = {
393 {"format", 0, POPT_ARG_STRING
, &ui_ops_name
, 0, "Output format (one of: simple, subunit)", NULL
},
394 {"smb-ports", 'p', POPT_ARG_STRING
, NULL
, OPT_SMB_PORTS
, "SMB ports", NULL
},
395 {"basedir", 0, POPT_ARG_STRING
, &basedir
, 0, "base directory", "BASEDIR" },
396 {"seed", 0, POPT_ARG_INT
, &torture_seed
, 0, "Seed to use for randomizer", NULL
},
397 {"num-progs", 0, POPT_ARG_INT
, NULL
, OPT_NUMPROGS
, "num progs", NULL
},
398 {"num-ops", 0, POPT_ARG_INT
, &torture_numops
, 0, "num ops", NULL
},
399 {"entries", 0, POPT_ARG_INT
, &torture_entries
, 0, "entries", NULL
},
400 {"loadfile", 0, POPT_ARG_STRING
, NULL
, OPT_LOADFILE
, "NBench load file to use", NULL
},
401 {"list-suites", 0, POPT_ARG_NONE
, &list_testsuites
, 0, "List available testsuites and exit", NULL
},
402 {"list", 0, POPT_ARG_NONE
, &list_tests
, 0, "List available tests in specified suites and exit", NULL
},
403 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
404 {"timelimit", 't', POPT_ARG_INT
, NULL
, OPT_TIMELIMIT
, "Set time limit (in seconds)", NULL
},
405 {"failures", 'f', POPT_ARG_INT
, &torture_failures
, 0, "failures", NULL
},
406 {"parse-dns", 'D', POPT_ARG_STRING
, NULL
, OPT_DNS
, "parse-dns", NULL
},
407 {"dangerous", 'X', POPT_ARG_NONE
, NULL
, OPT_DANGEROUS
,
408 "run dangerous tests (eg. wiping out password database)", NULL
},
409 {"load-module", 0, POPT_ARG_STRING
, &extra_module
, 0, "load tests from DSO file", "SOFILE"},
410 {"shell", 0, POPT_ARG_NONE
, &shell
, true, "Run shell", NULL
},
411 {"target", 'T', POPT_ARG_STRING
, &target
, 0, "samba3|samba4|other", NULL
},
412 {"async", 'a', POPT_ARG_NONE
, NULL
, OPT_ASYNC
,
413 "run async tests", NULL
},
414 {"num-async", 0, POPT_ARG_INT
, &torture_numasync
, 0,
415 "number of simultaneous async requests", NULL
},
416 {"maximum-runtime", 0, POPT_ARG_INT
, &max_runtime
, 0,
417 "set maximum time for smbtorture to live", "seconds"},
418 {"extra-user", 0, POPT_ARG_STRING
, NULL
, OPT_EXTRA_USER
,
419 "extra user credentials", NULL
},
420 {"load-list", 0, POPT_ARG_STRING
, &load_list
, 0,
421 "load a test id list from a text file", NULL
},
423 POPT_COMMON_CONNECTION
424 POPT_COMMON_CREDENTIALS
431 printf("smbtorture %s\n", samba_version_string());
433 /* we are never interested in SIGPIPE */
434 BlockSignals(true, SIGPIPE
);
436 pc
= poptGetContext("smbtorture", argc
, argv
, long_options
,
437 POPT_CONTEXT_KEEP_FIRST
);
439 poptSetOtherOptionHelp(pc
, "<binding>|<unc> TEST1 TEST2 ...");
441 while((opt
= poptGetNextOpt(pc
)) != -1) {
444 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:loadfile", poptGetOptArg(pc
));
447 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:unclist", poptGetOptArg(pc
));
450 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:timelimit", poptGetOptArg(pc
));
453 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:nprocs", poptGetOptArg(pc
));
456 parse_dns(cmdline_lp_ctx
, poptGetOptArg(pc
));
459 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:dangerous", "Yes");
462 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:async", "Yes");
465 lpcfg_set_cmdline(cmdline_lp_ctx
, "smb ports", poptGetOptArg(pc
));
469 char *option
= talloc_asprintf(NULL
, "torture:extra_user%u",
471 const char *value
= poptGetOptArg(pc
);
472 lpcfg_set_cmdline(cmdline_lp_ctx
, option
, value
);
478 printf("bad command line option %d\n", opt
);
484 if (load_list
!= NULL
) {
486 r
= file_lines_load(load_list
, &num_restricted
, 0, talloc_autofree_context());
487 restricted
= discard_const_p(const char *, r
);
488 if (restricted
== NULL
) {
489 printf("Unable to read load list file '%s'\n", load_list
);
494 if (strcmp(target
, "samba3") == 0) {
495 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:samba3", "true");
496 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
497 } else if (strcmp(target
, "samba4") == 0) {
498 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:samba4", "true");
499 } else if (strcmp(target
, "samba4-ntvfs") == 0) {
500 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:samba4", "true");
501 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:samba4-ntvfs", "true");
502 } else if (strcmp(target
, "winxp") == 0) {
503 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:winxp", "true");
504 } else if (strcmp(target
, "w2k3") == 0) {
505 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:w2k3", "true");
506 } else if (strcmp(target
, "w2k8") == 0) {
507 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:w2k8", "true");
508 lpcfg_set_cmdline(cmdline_lp_ctx
,
509 "torture:invalid_lock_range_support", "false");
510 } else if (strcmp(target
, "w2k12") == 0) {
511 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:w2k12", "true");
512 } else if (strcmp(target
, "win7") == 0) {
513 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:win7", "true");
514 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:cn_max_buffer_size",
516 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
517 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:rewind_support", "false");
519 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
520 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:search_ea_support", "false");
522 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:hide_on_access_denied",
524 } else if (strcmp(target
, "onefs") == 0) {
525 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:onefs", "true");
526 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:openx_deny_dos_support",
528 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:range_not_locked_on_file_close", "false");
529 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:sacl_support", "false");
530 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:ea_support", "false");
531 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:smbexit_pdu_support",
533 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:smblock_pdu_support",
535 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:2_step_break_to_none",
537 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:deny_dos_support", "false");
538 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:deny_fcb_support", "false");
539 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:read_support", "false");
540 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:writeclose_support", "false");
541 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
542 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:rewind_support", "false");
543 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:raw_search_search", "false");
544 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:search_ea_size", "false");
548 /* this will only work if nobody else uses alarm(),
549 which means it won't work for some tests, but we
550 can't use the event context method we use for smbd
551 as so many tests create their own event
552 context. This will at least catch most cases. */
553 signal(SIGALRM
, max_runtime_handler
);
557 if (extra_module
!= NULL
) {
558 init_module_fn fn
= load_module(poptGetOptArg(pc
), false, NULL
);
561 d_printf("Unable to load module from %s\n", poptGetOptArg(pc
));
564 if (NT_STATUS_IS_ERR(status
)) {
565 d_printf("Error initializing module %s: %s\n",
566 poptGetOptArg(pc
), nt_errstr(status
));
573 if (list_testsuites
) {
574 print_testsuite_list();
578 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
581 for (i
=0; i
<argc
; i
++) {
582 if (argv_new
[i
] == NULL
) {
590 print_test_list(torture_root
, NULL
, "");
592 for (i
=1;i
<argc_new
;i
++) {
593 print_test_list(torture_root
, NULL
, argv_new
[i
]);
599 if (torture_seed
== 0) {
600 torture_seed
= time(NULL
);
602 printf("Using seed %d\n", torture_seed
);
603 srandom(torture_seed
);
605 if (!strcmp(ui_ops_name
, "simple")) {
606 ui_ops
= &torture_simple_ui_ops
;
607 } else if (!strcmp(ui_ops_name
, "subunit")) {
608 ui_ops
= &torture_subunit_ui_ops
;
610 printf("Unknown output format '%s'\n", ui_ops_name
);
614 results
= torture_results_init(talloc_autofree_context(), ui_ops
);
616 torture
= torture_context_init(s4_event_context_init(talloc_autofree_context()),
618 if (basedir
!= NULL
) {
619 if (basedir
[0] != '/') {
620 fprintf(stderr
, "Please specify an absolute path to --basedir\n");
623 outputdir
= talloc_asprintf(torture
, "%s/smbtortureXXXXXX", basedir
);
625 char *pwd
= talloc_size(torture
, PATH_MAX
);
626 if (!getcwd(pwd
, PATH_MAX
)) {
627 fprintf(stderr
, "Unable to determine current working directory\n");
630 outputdir
= talloc_asprintf(torture
, "%s/smbtortureXXXXXX", pwd
);
633 fprintf(stderr
, "Could not allocate per-run output dir\n");
636 torture
->outputdir
= mkdtemp(outputdir
);
637 if (!torture
->outputdir
) {
638 perror("Failed to make temp output dir");
641 torture
->lp_ctx
= cmdline_lp_ctx
;
646 /* In shell mode, just ignore any remaining test names. */
647 torture_shell(torture
);
650 /* At this point, we should just have a target string,
651 * followed by a series of test names. Unless we are in
652 * shell mode, in which case we don't need anythig more.
656 printf("You must specify a test to run, or 'ALL'\n");
658 torture
->results
->returncode
= 1;
659 } else if (!torture_parse_target(cmdline_lp_ctx
, argv_new
[1])) {
660 /* Take the target name or binding. */
662 torture
->results
->returncode
= 1;
664 for (i
=2;i
<argc_new
;i
++) {
665 if (!torture_run_named_tests(torture
, argv_new
[i
],
666 (const char **)restricted
)) {
673 /* Now delete the temp dir we created */
674 torture_deltree_outputdir(torture
);
676 if (torture
->results
->returncode
&& correct
) {