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 "lib/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"
37 static bool run_matching(struct torture_context
*torture
,
40 struct torture_suite
*suite
,
46 struct torture_suite
*o
;
48 for (o
= (torture_root
== NULL
?NULL
:torture_root
->children
); o
; o
= o
->next
) {
49 if (gen_fnmatch(expr
, o
->name
) == 0) {
51 reload_charcnv(torture
->lp_ctx
);
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
);
66 if (gen_fnmatch(expr
, name
) == 0) {
68 reload_charcnv(torture
->lp_ctx
);
69 torture
->active_testname
= talloc_strdup(torture
, prefix
);
70 ret
&= torture_run_suite(torture
, c
);
75 ret
&= run_matching(torture
, name
, expr
, c
, matched
);
80 for (t
= suite
->testcases
; t
; t
= t
->next
) {
81 asprintf(&name
, "%s-%s", prefix
, t
->name
);
82 if (gen_fnmatch(expr
, name
) == 0) {
84 reload_charcnv(torture
->lp_ctx
);
85 torture
->active_testname
= talloc_strdup(torture
, prefix
);
86 ret
&= torture_run_tcase(torture
, t
);
87 talloc_free(torture
->active_testname
);
96 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
98 /****************************************************************************
99 run a specified test or "ALL"
100 ****************************************************************************/
101 static bool run_test(struct torture_context
*torture
, const char *name
)
104 bool matched
= false;
105 struct torture_suite
*o
;
107 if (strequal(name
, "ALL")) {
108 for (o
= torture_root
->children
; o
; o
= o
->next
) {
109 ret
&= torture_run_suite(torture
, o
);
114 ret
= run_matching(torture
, NULL
, name
, NULL
, &matched
);
117 printf("Unknown torture operation '%s'\n", name
);
124 static bool 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 lp_set_cmdline(lp_ctx
, "torture:host", binding_struct
->host
);
138 if (lp_parm_string(lp_ctx
, NULL
, "torture", "share") == NULL
)
139 lp_set_cmdline(lp_ctx
, "torture:share", "IPC$");
140 lp_set_cmdline(lp_ctx
, "torture:binding", target
);
142 lp_set_cmdline(lp_ctx
, "torture:host", host
);
143 lp_set_cmdline(lp_ctx
, "torture:share", share
);
144 lp_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 lp_set_cmdline(lp_ctx
, "torture:ldap_userdn", "");
159 lp_set_cmdline(lp_ctx
, "torture:ldap_basedn", "");
160 lp_set_cmdline(lp_ctx
, "torture:ldap_secret", "");
163 userdn
= strndup(dns
, p
- dns
);
164 lp_set_cmdline(lp_ctx
, "torture:ldap_userdn", userdn
);
166 /* retrieve the basedn */
168 p
= strchr_m(d
, '#');
170 lp_set_cmdline(lp_ctx
, "torture:ldap_basedn", "");
171 lp_set_cmdline(lp_ctx
, "torture:ldap_secret", "");
174 basedn
= strndup(d
, p
- d
);
175 lp_set_cmdline(lp_ctx
, "torture:ldap_basedn", basedn
);
177 /* retrieve the secret */
180 lp_set_cmdline(lp_ctx
, "torture:ldap_secret", "");
184 lp_set_cmdline(lp_ctx
, "torture:ldap_secret", secret
);
186 printf ("%s - %s - %s\n", userdn
, basedn
, secret
);
190 static void print_test_list(void)
192 struct torture_suite
*o
;
193 struct torture_suite
*s
;
194 struct torture_tcase
*t
;
196 if (torture_root
== NULL
)
199 for (o
= torture_root
->children
; o
; o
= o
->next
) {
200 for (s
= o
->children
; s
; s
= s
->next
) {
201 printf("%s-%s\n", o
->name
, s
->name
);
204 for (t
= o
->testcases
; t
; t
= t
->next
) {
205 printf("%s-%s\n", o
->name
, t
->name
);
210 _NORETURN_
static void usage(poptContext pc
)
212 struct torture_suite
*o
;
213 struct torture_suite
*s
;
214 struct torture_tcase
*t
;
217 poptPrintUsage(pc
, stdout
, 0);
220 printf("The binding format is:\n\n");
222 printf(" TRANSPORT:host[flags]\n\n");
224 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
225 printf(" or ncalrpc for local connections.\n\n");
227 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
228 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
229 printf(" string.\n\n");
231 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
232 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
233 printf(" will be auto-determined.\n\n");
235 printf(" other recognised flags are:\n\n");
237 printf(" sign : enable ntlmssp signing\n");
238 printf(" seal : enable ntlmssp sealing\n");
239 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
240 printf(" validate: enable the NDR validator\n");
241 printf(" print: enable debugging of the packets\n");
242 printf(" bigendian: use bigendian RPC\n");
243 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
245 printf(" For example, these all connect to the samr pipe:\n\n");
247 printf(" ncacn_np:myserver\n");
248 printf(" ncacn_np:myserver[samr]\n");
249 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
250 printf(" ncacn_np:myserver[/pipe/samr]\n");
251 printf(" ncacn_np:myserver[samr,sign,print]\n");
252 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
253 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
254 printf(" ncacn_np:\n");
255 printf(" ncacn_np:[/pipe/samr]\n\n");
257 printf(" ncacn_ip_tcp:myserver\n");
258 printf(" ncacn_ip_tcp:myserver[1024]\n");
259 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
261 printf(" ncalrpc:\n\n");
263 printf("The UNC format is:\n\n");
265 printf(" //server/share\n\n");
267 printf("Tests are:");
269 if (torture_root
== NULL
) {
270 printf("NO TESTS LOADED\n");
274 for (o
= torture_root
->children
; o
; o
= o
->next
) {
275 printf("\n%s (%s):\n ", o
->description
, o
->name
);
278 for (s
= o
->children
; s
; s
= s
->next
) {
279 if (i
+ strlen(o
->name
) + strlen(s
->name
) >= (MAX_COLS
- 3)) {
283 i
+=printf("%s-%s ", o
->name
, s
->name
);
286 for (t
= o
->testcases
; t
; t
= t
->next
) {
287 if (i
+ strlen(o
->name
) + strlen(t
->name
) >= (MAX_COLS
- 3)) {
291 i
+=printf("%s-%s ", o
->name
, t
->name
);
297 printf("\nThe default test is ALL.\n");
302 _NORETURN_
static void max_runtime_handler(int sig
)
304 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
308 struct timeval last_suite_started
;
310 static void simple_suite_start(struct torture_context
*ctx
,
311 struct torture_suite
*suite
)
313 last_suite_started
= timeval_current();
314 printf("Running %s\n", suite
->name
);
317 static void simple_suite_finish(struct torture_context
*ctx
,
318 struct torture_suite
*suite
)
321 printf("%s took %g secs\n\n", suite
->name
,
322 timeval_elapsed(&last_suite_started
));
325 static void simple_test_result(struct torture_context
*context
,
326 enum torture_result res
, const char *reason
)
331 printf("OK: %s\n", reason
);
334 printf("TEST %s FAILED! - %s\n", context
->active_test
->name
, reason
);
337 printf("ERROR IN TEST %s! - %s\n", context
->active_test
->name
, reason
);
340 printf("SKIP: %s - %s\n", context
->active_test
->name
, reason
);
345 static void simple_comment(struct torture_context
*test
,
348 printf("%s", comment
);
351 static void simple_warning(struct torture_context
*test
,
354 fprintf(stderr
, "WARNING: %s\n", comment
);
357 const static struct torture_ui_ops std_ui_ops
= {
358 .comment
= simple_comment
,
359 .warning
= simple_warning
,
360 .suite_start
= simple_suite_start
,
361 .suite_finish
= simple_suite_finish
,
362 .test_result
= simple_test_result
366 static void run_shell(struct torture_context
*tctx
)
374 cline
= smb_readline("torture> ", NULL
, NULL
);
379 ret
= poptParseArgvString(cline
, &argc
, &argv
);
381 fprintf(stderr
, "Error parsing line\n");
385 if (!strcmp(argv
[0], "quit")) {
387 } else if (!strcmp(argv
[0], "set")) {
389 fprintf(stderr
, "Usage: set <variable> <value>\n");
391 char *name
= talloc_asprintf(NULL
, "torture:%s", argv
[1]);
392 lp_set_cmdline(tctx
->lp_ctx
, name
, argv
[2]);
395 } else if (!strcmp(argv
[0], "help")) {
396 fprintf(stderr
, "Available commands:\n"
397 " help - This help command\n"
399 " set - Change variables\n"
401 } else if (!strcmp(argv
[0], "run")) {
403 fprintf(stderr
, "Usage: run TEST-NAME [OPTIONS...]\n");
405 run_test(tctx
, argv
[1]);
412 /****************************************************************************
414 ****************************************************************************/
415 int main(int argc
,char *argv
[])
421 struct torture_context
*torture
;
422 struct torture_results
*results
;
423 const struct torture_ui_ops
*ui_ops
;
426 static const char *target
= "other";
429 static const char *ui_ops_name
= "subunit";
430 const char *basedir
= NULL
;
431 const char *extra_module
= NULL
;
432 static int list_tests
= 0;
433 int num_extra_users
= 0;
434 enum {OPT_LOADFILE
=1000,OPT_UNCLIST
,OPT_TIMELIMIT
,OPT_DNS
, OPT_LIST
,
435 OPT_DANGEROUS
,OPT_SMB_PORTS
,OPT_ASYNC
,OPT_NUMPROGS
,
438 struct poptOption long_options
[] = {
440 {"format", 0, POPT_ARG_STRING
, &ui_ops_name
, 0, "Output format (one of: simple, subunit)", NULL
},
441 {"smb-ports", 'p', POPT_ARG_STRING
, NULL
, OPT_SMB_PORTS
, "SMB ports", NULL
},
442 {"basedir", 0, POPT_ARG_STRING
, &basedir
, 0, "base directory", "BASEDIR" },
443 {"seed", 0, POPT_ARG_INT
, &torture_seed
, 0, "Seed to use for randomizer", NULL
},
444 {"num-progs", 0, POPT_ARG_INT
, NULL
, OPT_NUMPROGS
, "num progs", NULL
},
445 {"num-ops", 0, POPT_ARG_INT
, &torture_numops
, 0, "num ops", NULL
},
446 {"entries", 0, POPT_ARG_INT
, &torture_entries
, 0, "entries", NULL
},
447 {"loadfile", 0, POPT_ARG_STRING
, NULL
, OPT_LOADFILE
, "NBench load file to use", NULL
},
448 {"list", 0, POPT_ARG_NONE
, &list_tests
, 0, "List available tests and exit", NULL
},
449 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
450 {"timelimit", 't', POPT_ARG_INT
, NULL
, OPT_TIMELIMIT
, "Set time limit (in seconds)", NULL
},
451 {"failures", 'f', POPT_ARG_INT
, &torture_failures
, 0, "failures", NULL
},
452 {"parse-dns", 'D', POPT_ARG_STRING
, NULL
, OPT_DNS
, "parse-dns", NULL
},
453 {"dangerous", 'X', POPT_ARG_NONE
, NULL
, OPT_DANGEROUS
,
454 "run dangerous tests (eg. wiping out password database)", NULL
},
455 {"load-module", 0, POPT_ARG_STRING
, &extra_module
, 0, "load tests from DSO file", "SOFILE"},
456 {"shell", 0, POPT_ARG_NONE
, &shell
, true, "Run shell", NULL
},
457 {"target", 'T', POPT_ARG_STRING
, &target
, 0, "samba3|samba4|other", NULL
},
458 {"async", 'a', POPT_ARG_NONE
, NULL
, OPT_ASYNC
,
459 "run async tests", NULL
},
460 {"num-async", 0, POPT_ARG_INT
, &torture_numasync
, 0,
461 "number of simultaneous async requests", NULL
},
462 {"maximum-runtime", 0, POPT_ARG_INT
, &max_runtime
, 0,
463 "set maximum time for smbtorture to live", "seconds"},
464 {"extra-user", 0, POPT_ARG_STRING
, NULL
, OPT_EXTRA_USER
,
465 "extra user credentials", NULL
},
467 POPT_COMMON_CONNECTION
468 POPT_COMMON_CREDENTIALS
475 /* we are never interested in SIGPIPE */
476 BlockSignals(true, SIGPIPE
);
478 pc
= poptGetContext("smbtorture", argc
, (const char **) argv
, long_options
,
479 POPT_CONTEXT_KEEP_FIRST
);
481 poptSetOtherOptionHelp(pc
, "<binding>|<unc> TEST1 TEST2 ...");
483 while((opt
= poptGetNextOpt(pc
)) != -1) {
486 lp_set_cmdline(cmdline_lp_ctx
, "torture:loadfile", poptGetOptArg(pc
));
489 lp_set_cmdline(cmdline_lp_ctx
, "torture:unclist", poptGetOptArg(pc
));
492 lp_set_cmdline(cmdline_lp_ctx
, "torture:timelimit", poptGetOptArg(pc
));
495 lp_set_cmdline(cmdline_lp_ctx
, "torture:nprocs", poptGetOptArg(pc
));
498 parse_dns(cmdline_lp_ctx
, poptGetOptArg(pc
));
501 lp_set_cmdline(cmdline_lp_ctx
, "torture:dangerous", "Yes");
504 lp_set_cmdline(cmdline_lp_ctx
, "torture:async", "Yes");
507 lp_set_cmdline(cmdline_lp_ctx
, "smb ports", poptGetOptArg(pc
));
511 char *option
= talloc_asprintf(NULL
, "torture:extra_user%u",
513 const char *value
= poptGetOptArg(pc
);
514 lp_set_cmdline(cmdline_lp_ctx
, option
, value
);
519 printf("bad command line option\n");
524 if (strcmp(target
, "samba3") == 0) {
525 lp_set_cmdline(cmdline_lp_ctx
, "torture:samba3", "true");
526 lp_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
527 } else if (strcmp(target
, "samba4") == 0) {
528 lp_set_cmdline(cmdline_lp_ctx
, "torture:samba4", "true");
529 } else if (strcmp(target
, "winxp") == 0) {
530 lp_set_cmdline(cmdline_lp_ctx
, "torture:winxp", "true");
531 } else if (strcmp(target
, "w2k3") == 0) {
532 lp_set_cmdline(cmdline_lp_ctx
, "torture:w2k3", "true");
533 } else if (strcmp(target
, "w2k8") == 0) {
534 lp_set_cmdline(cmdline_lp_ctx
, "torture:w2k8", "true");
535 lp_set_cmdline(cmdline_lp_ctx
,
536 "torture:invalid_lock_range_support", "false");
537 } else if (strcmp(target
, "win7") == 0) {
538 lp_set_cmdline(cmdline_lp_ctx
, "torture:win7", "true");
539 lp_set_cmdline(cmdline_lp_ctx
, "torture:cn_max_buffer_size",
541 lp_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
542 lp_set_cmdline(cmdline_lp_ctx
, "torture:rewind_support", "false");
544 /* RAW-SEARCH for fails for inexplicable reasons against win7 */
545 lp_set_cmdline(cmdline_lp_ctx
, "torture:search_ea_support", "false");
547 lp_set_cmdline(cmdline_lp_ctx
, "torture:hide_on_access_denied",
549 } else if (strcmp(target
, "onefs") == 0) {
550 lp_set_cmdline(cmdline_lp_ctx
, "torture:onefs", "true");
551 lp_set_cmdline(cmdline_lp_ctx
, "torture:openx_deny_dos_support",
553 lp_set_cmdline(cmdline_lp_ctx
, "torture:range_not_locked_on_file_close", "false");
554 lp_set_cmdline(cmdline_lp_ctx
, "torture:sacl_support", "false");
555 lp_set_cmdline(cmdline_lp_ctx
, "torture:ea_support", "false");
556 lp_set_cmdline(cmdline_lp_ctx
, "torture:smbexit_pdu_support",
558 lp_set_cmdline(cmdline_lp_ctx
, "torture:smblock_pdu_support",
560 lp_set_cmdline(cmdline_lp_ctx
, "torture:2_step_break_to_none",
562 lp_set_cmdline(cmdline_lp_ctx
, "torture:deny_dos_support", "false");
563 lp_set_cmdline(cmdline_lp_ctx
, "torture:deny_fcb_support", "false");
564 lp_set_cmdline(cmdline_lp_ctx
, "torture:read_support", "false");
565 lp_set_cmdline(cmdline_lp_ctx
, "torture:writeclose_support", "false");
566 lp_set_cmdline(cmdline_lp_ctx
, "torture:resume_key_support", "false");
567 lp_set_cmdline(cmdline_lp_ctx
, "torture:rewind_support", "false");
571 /* this will only work if nobody else uses alarm(),
572 which means it won't work for some tests, but we
573 can't use the event context method we use for smbd
574 as so many tests create their own event
575 context. This will at least catch most cases. */
576 signal(SIGALRM
, max_runtime_handler
);
580 if (extra_module
!= NULL
) {
581 init_module_fn fn
= load_module(talloc_autofree_context(), poptGetOptArg(pc
));
584 d_printf("Unable to load module from %s\n", poptGetOptArg(pc
));
587 if (NT_STATUS_IS_ERR(status
)) {
588 d_printf("Error initializing module %s: %s\n",
589 poptGetOptArg(pc
), nt_errstr(status
));
601 if (torture_seed
== 0) {
602 torture_seed
= time(NULL
);
604 printf("Using seed %d\n", torture_seed
);
605 srandom(torture_seed
);
607 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
610 for (i
=0; i
<argc
; i
++) {
611 if (argv_new
[i
] == NULL
) {
617 if (!(argc_new
>= 3 || (shell
&& argc_new
>= 2))) {
622 if (!parse_target(cmdline_lp_ctx
, argv_new
[1])) {
627 if (!strcmp(ui_ops_name
, "simple")) {
628 ui_ops
= &std_ui_ops
;
629 } else if (!strcmp(ui_ops_name
, "subunit")) {
630 ui_ops
= &torture_subunit_ui_ops
;
632 printf("Unknown output format '%s'\n", ui_ops_name
);
636 results
= torture_results_init(talloc_autofree_context(), ui_ops
);
638 torture
= torture_context_init(s4_event_context_init(NULL
), results
);
639 if (basedir
!= NULL
) {
640 if (basedir
[0] != '/') {
641 fprintf(stderr
, "Please specify an absolute path to --basedir\n");
644 torture
->outputdir
= basedir
;
646 char *pwd
= talloc_size(torture
, PATH_MAX
);
647 if (!getcwd(pwd
, PATH_MAX
)) {
648 fprintf(stderr
, "Unable to determine current working directory\n");
651 torture
->outputdir
= pwd
;
654 torture
->lp_ctx
= cmdline_lp_ctx
;
656 gensec_init(cmdline_lp_ctx
);
659 printf("You must specify a test to run, or 'ALL'\n");
663 for (i
=2;i
<argc_new
;i
++) {
664 if (!run_test(torture
, argv_new
[i
])) {
670 if (torture
->results
->returncode
&& correct
) {