s3: Add an async smbsock_connect
[Samba.git] / source4 / torture / smbtorture.c
blobd01dc9a856f6f27afa2b2a5dde3e07228e77581a
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester
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/>.
21 #include "includes.h"
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/ldb/include/ldb.h"
30 #include "lib/events/events.h"
31 #include "dynconfig/dynconfig.h"
33 #include "torture/smbtorture.h"
34 #include "../lib/util/dlinklist.h"
35 #include "librpc/rpc/dcerpc.h"
36 #include "auth/gensec/gensec.h"
37 #include "param/param.h"
39 #include "auth/credentials/credentials.h"
41 static bool run_matching(struct torture_context *torture,
42 const char *prefix,
43 const char *expr,
44 struct torture_suite *suite,
45 bool *matched)
47 bool ret = true;
49 if (suite == NULL) {
50 struct torture_suite *o;
52 for (o = (torture_root == NULL?NULL:torture_root->children); o; o = o->next) {
53 if (gen_fnmatch(expr, o->name) == 0) {
54 *matched = true;
55 reload_charcnv(torture->lp_ctx);
56 ret &= torture_run_suite(torture, o);
57 continue;
60 ret &= run_matching(torture, o->name, expr, o, matched);
62 } else {
63 char *name;
64 struct torture_suite *c;
65 struct torture_tcase *t;
67 for (c = suite->children; c; c = c->next) {
68 asprintf(&name, "%s-%s", prefix, c->name);
70 if (gen_fnmatch(expr, name) == 0) {
71 *matched = true;
72 reload_charcnv(torture->lp_ctx);
73 torture->active_testname = talloc_strdup(torture, prefix);
74 ret &= torture_run_suite(torture, c);
75 free(name);
76 continue;
79 ret &= run_matching(torture, name, expr, c, matched);
81 free(name);
84 for (t = suite->testcases; t; t = t->next) {
85 asprintf(&name, "%s-%s", prefix, t->name);
86 if (gen_fnmatch(expr, name) == 0) {
87 *matched = true;
88 reload_charcnv(torture->lp_ctx);
89 torture->active_testname = talloc_strdup(torture, prefix);
90 ret &= torture_run_tcase(torture, t);
91 talloc_free(torture->active_testname);
93 free(name);
97 return ret;
100 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
102 /****************************************************************************
103 run a specified test or "ALL"
104 ****************************************************************************/
105 static bool run_test(struct torture_context *torture, const char *name)
107 bool ret = true;
108 bool matched = false;
109 struct torture_suite *o;
111 if (strequal(name, "ALL")) {
112 for (o = torture_root->children; o; o = o->next) {
113 ret &= torture_run_suite(torture, o);
115 return ret;
118 ret = run_matching(torture, NULL, name, NULL, &matched);
120 if (!matched) {
121 printf("Unknown torture operation '%s'\n", name);
122 return false;
125 return ret;
128 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
130 char *host = NULL, *share = NULL;
131 struct dcerpc_binding *binding_struct;
132 NTSTATUS status;
134 /* see if its a RPC transport specifier */
135 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
136 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
137 if (NT_STATUS_IS_ERR(status)) {
138 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
139 return false;
141 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
142 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
143 lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
144 lp_set_cmdline(lp_ctx, "torture:binding", target);
145 } else {
146 lp_set_cmdline(lp_ctx, "torture:host", host);
147 lp_set_cmdline(lp_ctx, "torture:share", share);
148 lp_set_cmdline(lp_ctx, "torture:binding", host);
151 return true;
154 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
156 char *userdn, *basedn, *secret;
157 char *p, *d;
159 /* retrievieng the userdn */
160 p = strchr_m(dns, '#');
161 if (!p) {
162 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
163 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
164 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
165 return;
167 userdn = strndup(dns, p - dns);
168 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
170 /* retrieve the basedn */
171 d = p + 1;
172 p = strchr_m(d, '#');
173 if (!p) {
174 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
175 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
176 return;
178 basedn = strndup(d, p - d);
179 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
181 /* retrieve the secret */
182 p = p + 1;
183 if (!p) {
184 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
185 return;
187 secret = strdup(p);
188 lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
190 printf ("%s - %s - %s\n", userdn, basedn, secret);
194 static void print_test_list(void)
196 struct torture_suite *o;
197 struct torture_suite *s;
198 struct torture_tcase *t;
200 if (torture_root == NULL)
201 return;
203 for (o = torture_root->children; o; o = o->next) {
204 for (s = o->children; s; s = s->next) {
205 printf("%s-%s\n", o->name, s->name);
208 for (t = o->testcases; t; t = t->next) {
209 printf("%s-%s\n", o->name, t->name);
214 _NORETURN_ static void usage(poptContext pc)
216 struct torture_suite *o;
217 struct torture_suite *s;
218 struct torture_tcase *t;
219 int i;
221 poptPrintUsage(pc, stdout, 0);
222 printf("\n");
224 printf("The binding format is:\n\n");
226 printf(" TRANSPORT:host[flags]\n\n");
228 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
229 printf(" or ncalrpc for local connections.\n\n");
231 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
232 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
233 printf(" string.\n\n");
235 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
236 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
237 printf(" will be auto-determined.\n\n");
239 printf(" other recognised flags are:\n\n");
241 printf(" sign : enable ntlmssp signing\n");
242 printf(" seal : enable ntlmssp sealing\n");
243 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
244 printf(" validate: enable the NDR validator\n");
245 printf(" print: enable debugging of the packets\n");
246 printf(" bigendian: use bigendian RPC\n");
247 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
249 printf(" For example, these all connect to the samr pipe:\n\n");
251 printf(" ncacn_np:myserver\n");
252 printf(" ncacn_np:myserver[samr]\n");
253 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
254 printf(" ncacn_np:myserver[/pipe/samr]\n");
255 printf(" ncacn_np:myserver[samr,sign,print]\n");
256 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
257 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
258 printf(" ncacn_np:\n");
259 printf(" ncacn_np:[/pipe/samr]\n\n");
261 printf(" ncacn_ip_tcp:myserver\n");
262 printf(" ncacn_ip_tcp:myserver[1024]\n");
263 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
265 printf(" ncalrpc:\n\n");
267 printf("The UNC format is:\n\n");
269 printf(" //server/share\n\n");
271 printf("Tests are:");
273 if (torture_root == NULL) {
274 printf("NO TESTS LOADED\n");
275 exit(1);
278 for (o = torture_root->children; o; o = o->next) {
279 printf("\n%s (%s):\n ", o->description, o->name);
281 i = 0;
282 for (s = o->children; s; s = s->next) {
283 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
284 printf("\n ");
285 i = 0;
287 i+=printf("%s-%s ", o->name, s->name);
290 for (t = o->testcases; t; t = t->next) {
291 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
292 printf("\n ");
293 i = 0;
295 i+=printf("%s-%s ", o->name, t->name);
298 if (i) printf("\n");
301 printf("\nThe default test is ALL.\n");
303 exit(1);
306 _NORETURN_ static void max_runtime_handler(int sig)
308 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
309 exit(1);
312 struct timeval last_suite_started;
314 static void simple_suite_start(struct torture_context *ctx,
315 struct torture_suite *suite)
317 last_suite_started = timeval_current();
318 printf("Running %s\n", suite->name);
321 static void simple_suite_finish(struct torture_context *ctx,
322 struct torture_suite *suite)
325 printf("%s took %g secs\n\n", suite->name,
326 timeval_elapsed(&last_suite_started));
329 static void simple_test_result(struct torture_context *context,
330 enum torture_result res, const char *reason)
332 switch (res) {
333 case TORTURE_OK:
334 if (reason)
335 printf("OK: %s\n", reason);
336 break;
337 case TORTURE_FAIL:
338 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
339 break;
340 case TORTURE_ERROR:
341 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
342 break;
343 case TORTURE_SKIP:
344 printf("SKIP: %s - %s\n", context->active_test->name, reason);
345 break;
349 static void simple_comment(struct torture_context *test,
350 const char *comment)
352 printf("%s", comment);
355 static void simple_warning(struct torture_context *test,
356 const char *comment)
358 fprintf(stderr, "WARNING: %s\n", comment);
361 const static struct torture_ui_ops std_ui_ops = {
362 .comment = simple_comment,
363 .warning = simple_warning,
364 .suite_start = simple_suite_start,
365 .suite_finish = simple_suite_finish,
366 .test_result = simple_test_result
370 static void quiet_suite_start(struct torture_context *ctx,
371 struct torture_suite *suite)
373 int i;
374 ctx->results->quiet = true;
375 for (i = 1; i < ctx->level; i++) putchar('\t');
376 printf("%s: ", suite->name);
377 fflush(stdout);
380 static void quiet_suite_finish(struct torture_context *ctx,
381 struct torture_suite *suite)
383 putchar('\n');
386 static void quiet_test_result(struct torture_context *context,
387 enum torture_result res, const char *reason)
389 fflush(stdout);
390 switch (res) {
391 case TORTURE_OK: putchar('.'); break;
392 case TORTURE_FAIL: putchar('F'); break;
393 case TORTURE_ERROR: putchar('E'); break;
394 case TORTURE_SKIP: putchar('I'); break;
398 const static struct torture_ui_ops quiet_ui_ops = {
399 .suite_start = quiet_suite_start,
400 .suite_finish = quiet_suite_finish,
401 .test_result = quiet_test_result
404 static void run_shell(struct torture_context *tctx)
406 char *cline;
407 int argc;
408 const char **argv;
409 int ret;
411 while (1) {
412 cline = smb_readline("torture> ", NULL, NULL);
414 if (cline == NULL)
415 return;
417 ret = poptParseArgvString(cline, &argc, &argv);
418 if (ret != 0) {
419 fprintf(stderr, "Error parsing line\n");
420 continue;
423 if (!strcmp(argv[0], "quit")) {
424 return;
425 } else if (!strcmp(argv[0], "set")) {
426 if (argc < 3) {
427 fprintf(stderr, "Usage: set <variable> <value>\n");
428 } else {
429 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
430 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
431 talloc_free(name);
433 } else if (!strcmp(argv[0], "help")) {
434 fprintf(stderr, "Available commands:\n"
435 " help - This help command\n"
436 " run - Run test\n"
437 " set - Change variables\n"
438 "\n");
439 } else if (!strcmp(argv[0], "run")) {
440 if (argc < 2) {
441 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
442 } else {
443 run_test(tctx, argv[1]);
446 free(cline);
450 /****************************************************************************
451 main program
452 ****************************************************************************/
453 int main(int argc,char *argv[])
455 int opt, i;
456 bool correct = true;
457 int max_runtime=0;
458 int argc_new;
459 struct torture_context *torture;
460 struct torture_results *results;
461 const struct torture_ui_ops *ui_ops;
462 char **argv_new;
463 poptContext pc;
464 static const char *target = "other";
465 NTSTATUS status;
466 int shell = false;
467 static const char *ui_ops_name = "simple";
468 const char *basedir = NULL;
469 const char *extra_module = NULL;
470 static int list_tests = 0;
471 int num_extra_users = 0;
472 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
473 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,OPT_EXTRA_USER};
475 struct poptOption long_options[] = {
476 POPT_AUTOHELP
477 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
478 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
479 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
480 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
481 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
482 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
483 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
484 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
485 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
486 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
487 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
488 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
489 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
490 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
491 "run dangerous tests (eg. wiping out password database)", NULL},
492 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
493 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
494 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
495 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
496 "run async tests", NULL},
497 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
498 "number of simultaneous async requests", NULL},
499 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
500 "set maximum time for smbtorture to live", "seconds"},
501 {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
502 "extra user credentials", NULL},
503 POPT_COMMON_SAMBA
504 POPT_COMMON_CONNECTION
505 POPT_COMMON_CREDENTIALS
506 POPT_COMMON_VERSION
507 { NULL }
510 setlinebuf(stdout);
512 /* we are never interested in SIGPIPE */
513 BlockSignals(true, SIGPIPE);
515 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
516 POPT_CONTEXT_KEEP_FIRST);
518 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
520 while((opt = poptGetNextOpt(pc)) != -1) {
521 switch (opt) {
522 case OPT_LOADFILE:
523 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
524 break;
525 case OPT_UNCLIST:
526 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
527 break;
528 case OPT_TIMELIMIT:
529 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
530 break;
531 case OPT_NUMPROGS:
532 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
533 break;
534 case OPT_DNS:
535 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
536 break;
537 case OPT_DANGEROUS:
538 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
539 break;
540 case OPT_ASYNC:
541 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
542 break;
543 case OPT_SMB_PORTS:
544 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
545 break;
546 case OPT_EXTRA_USER:
548 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
549 ++num_extra_users);
550 char *value = poptGetOptArg(pc);
551 lp_set_cmdline(cmdline_lp_ctx, option, value);
552 talloc_free(option);
554 break;
558 if (strcmp(target, "samba3") == 0) {
559 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
560 } else if (strcmp(target, "samba4") == 0) {
561 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
562 } else if (strcmp(target, "win7") == 0) {
563 lp_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
566 if (max_runtime) {
567 /* this will only work if nobody else uses alarm(),
568 which means it won't work for some tests, but we
569 can't use the event context method we use for smbd
570 as so many tests create their own event
571 context. This will at least catch most cases. */
572 signal(SIGALRM, max_runtime_handler);
573 alarm(max_runtime);
576 if (extra_module != NULL) {
577 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
579 if (fn == NULL)
580 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
581 else {
582 status = fn();
583 if (NT_STATUS_IS_ERR(status)) {
584 d_printf("Error initializing module %s: %s\n",
585 poptGetOptArg(pc), nt_errstr(status));
588 } else {
589 torture_init();
592 if (list_tests) {
593 print_test_list();
594 return 0;
597 if (torture_seed == 0) {
598 torture_seed = time(NULL);
600 printf("Using seed %d\n", torture_seed);
601 srandom(torture_seed);
603 argv_new = discard_const_p(char *, poptGetArgs(pc));
605 argc_new = argc;
606 for (i=0; i<argc; i++) {
607 if (argv_new[i] == NULL) {
608 argc_new = i;
609 break;
613 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
614 usage(pc);
615 exit(1);
618 if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
619 usage(pc);
620 exit(1);
623 if (!strcmp(ui_ops_name, "simple")) {
624 ui_ops = &std_ui_ops;
625 } else if (!strcmp(ui_ops_name, "subunit")) {
626 ui_ops = &torture_subunit_ui_ops;
627 } else if (!strcmp(ui_ops_name, "quiet")) {
628 ui_ops = &quiet_ui_ops;
629 } else {
630 printf("Unknown output format '%s'\n", ui_ops_name);
631 exit(1);
634 results = torture_results_init(talloc_autofree_context(), ui_ops);
636 torture = torture_context_init(s4_event_context_init(NULL), results);
637 if (basedir != NULL) {
638 if (basedir[0] != '/') {
639 fprintf(stderr, "Please specify an absolute path to --basedir\n");
640 return 1;
642 torture->outputdir = basedir;
643 } else {
644 char *pwd = talloc_size(torture, PATH_MAX);
645 if (!getcwd(pwd, PATH_MAX)) {
646 fprintf(stderr, "Unable to determine current working directory\n");
647 return 1;
649 torture->outputdir = pwd;
652 torture->lp_ctx = cmdline_lp_ctx;
654 gensec_init(cmdline_lp_ctx);
656 if (argc_new == 0) {
657 printf("You must specify a test to run, or 'ALL'\n");
658 } else if (shell) {
659 run_shell(torture);
660 } else {
661 for (i=2;i<argc_new;i++) {
662 if (!run_test(torture, argv_new[i])) {
663 correct = false;
668 if (torture->results->returncode && correct) {
669 return(0);
670 } else {
671 return(1);