• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/torture/
1/*
2   Unix SMB/CIFS implementation.
3   SMB torture tester
4   Copyright (C) Andrew Tridgell 1997-2003
5   Copyright (C) Jelmer Vernooij 2006-2008
6
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.
11
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.
16
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/>.
19*/
20
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"
32
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"
38
39#include "auth/credentials/credentials.h"
40
41static bool run_matching(struct torture_context *torture,
42						 const char *prefix,
43						 const char *expr,
44						 struct torture_suite *suite,
45						 bool *matched)
46{
47	bool ret = true;
48
49	if (suite == NULL) {
50		struct torture_suite *o;
51
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;
58			}
59
60			ret &= run_matching(torture, o->name, expr, o, matched);
61		}
62	} else {
63		char *name;
64		struct torture_suite *c;
65		struct torture_tcase *t;
66
67		for (c = suite->children; c; c = c->next) {
68			asprintf(&name, "%s-%s", prefix, c->name);
69
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;
77			}
78
79			ret &= run_matching(torture, name, expr, c, matched);
80
81			free(name);
82		}
83
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);
92			}
93			free(name);
94		}
95	}
96
97	return ret;
98}
99
100#define MAX_COLS 80 /* FIXME: Determine this at run-time */
101
102/****************************************************************************
103run a specified test or "ALL"
104****************************************************************************/
105static bool run_test(struct torture_context *torture, const char *name)
106{
107	bool ret = true;
108	bool matched = false;
109	struct torture_suite *o;
110
111	if (strequal(name, "ALL")) {
112		for (o = torture_root->children; o; o = o->next) {
113			ret &= torture_run_suite(torture, o);
114		}
115		return ret;
116	}
117
118	ret = run_matching(torture, NULL, name, NULL, &matched);
119
120	if (!matched) {
121		printf("Unknown torture operation '%s'\n", name);
122		return false;
123	}
124
125	return ret;
126}
127
128static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
129{
130	char *host = NULL, *share = NULL;
131	struct dcerpc_binding *binding_struct;
132	NTSTATUS status;
133
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;
140		}
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);
149	}
150
151	return true;
152}
153
154static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
155{
156	char *userdn, *basedn, *secret;
157	char *p, *d;
158
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;
166	}
167	userdn = strndup(dns, p - dns);
168	lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
169
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;
177	}
178	basedn = strndup(d, p - d);
179	lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
180
181	/* retrieve the secret */
182	p = p + 1;
183	if (!p) {
184		lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
185		return;
186	}
187	secret = strdup(p);
188	lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
189
190	printf ("%s - %s - %s\n", userdn, basedn, secret);
191
192}
193
194static void print_test_list(void)
195{
196	struct torture_suite *o;
197	struct torture_suite *s;
198	struct torture_tcase *t;
199
200	if (torture_root == NULL)
201		return;
202
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);
206		}
207
208		for (t = o->testcases; t; t = t->next) {
209			printf("%s-%s\n", o->name, t->name);
210		}
211	}
212}
213
214_NORETURN_ static void usage(poptContext pc)
215{
216	struct torture_suite *o;
217	struct torture_suite *s;
218	struct torture_tcase *t;
219	int i;
220
221	poptPrintUsage(pc, stdout, 0);
222	printf("\n");
223
224	printf("The binding format is:\n\n");
225
226	printf("  TRANSPORT:host[flags]\n\n");
227
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");
230
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");
234
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");
238
239	printf("  other recognised flags are:\n\n");
240
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");
248
249	printf("  For example, these all connect to the samr pipe:\n\n");
250
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");
260
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");
264
265	printf("    ncalrpc:\n\n");
266
267	printf("The UNC format is:\n\n");
268
269	printf("  //server/share\n\n");
270
271	printf("Tests are:");
272
273	if (torture_root == NULL) {
274	    printf("NO TESTS LOADED\n");
275	    exit(1);
276	}
277
278	for (o = torture_root->children; o; o = o->next) {
279		printf("\n%s (%s):\n  ", o->description, o->name);
280
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;
286			}
287			i+=printf("%s-%s ", o->name, s->name);
288		}
289
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;
294			}
295			i+=printf("%s-%s ", o->name, t->name);
296		}
297
298		if (i) printf("\n");
299	}
300
301	printf("\nThe default test is ALL.\n");
302
303	exit(1);
304}
305
306_NORETURN_ static void max_runtime_handler(int sig)
307{
308	DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
309	exit(1);
310}
311
312struct timeval last_suite_started;
313
314static void simple_suite_start(struct torture_context *ctx,
315			       struct torture_suite *suite)
316{
317	last_suite_started = timeval_current();
318	printf("Running %s\n", suite->name);
319}
320
321static void simple_suite_finish(struct torture_context *ctx,
322			        struct torture_suite *suite)
323{
324
325	printf("%s took %g secs\n\n", suite->name,
326		   timeval_elapsed(&last_suite_started));
327}
328
329static void simple_test_result(struct torture_context *context,
330			       enum torture_result res, const char *reason)
331{
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;
346	}
347}
348
349static void simple_comment(struct torture_context *test,
350			   const char *comment)
351{
352	printf("%s", comment);
353}
354
355static void simple_warning(struct torture_context *test,
356			   const char *comment)
357{
358	fprintf(stderr, "WARNING: %s\n", comment);
359}
360
361const 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
367};
368
369
370static void run_shell(struct torture_context *tctx)
371{
372	char *cline;
373	int argc;
374	const char **argv;
375	int ret;
376
377	while (1) {
378		cline = smb_readline("torture> ", NULL, NULL);
379
380		if (cline == NULL)
381			return;
382
383		ret = poptParseArgvString(cline, &argc, &argv);
384		if (ret != 0) {
385			fprintf(stderr, "Error parsing line\n");
386			continue;
387		}
388
389		if (!strcmp(argv[0], "quit")) {
390			return;
391		} else if (!strcmp(argv[0], "set")) {
392			if (argc < 3) {
393				fprintf(stderr, "Usage: set <variable> <value>\n");
394			} else {
395				char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
396				lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
397				talloc_free(name);
398			}
399		} else if (!strcmp(argv[0], "help")) {
400			fprintf(stderr, "Available commands:\n"
401							" help - This help command\n"
402							" run - Run test\n"
403							" set - Change variables\n"
404							"\n");
405		} else if (!strcmp(argv[0], "run")) {
406			if (argc < 2) {
407				fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
408			} else {
409				run_test(tctx, argv[1]);
410			}
411		}
412		free(cline);
413	}
414}
415
416/****************************************************************************
417  main program
418****************************************************************************/
419int main(int argc,char *argv[])
420{
421	int opt, i;
422	bool correct = true;
423	int max_runtime=0;
424	int argc_new;
425	struct torture_context *torture;
426	struct torture_results *results;
427	const struct torture_ui_ops *ui_ops;
428	char **argv_new;
429	poptContext pc;
430	static const char *target = "other";
431	NTSTATUS status;
432	int shell = false;
433	static const char *ui_ops_name = "subunit";
434	const char *basedir = NULL;
435	const char *extra_module = NULL;
436	static int list_tests = 0;
437	int num_extra_users = 0;
438	enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
439	      OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
440	      OPT_EXTRA_USER,};
441
442	struct poptOption long_options[] = {
443		POPT_AUTOHELP
444		{"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
445		{"smb-ports",	'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,	"SMB ports", 	NULL},
446		{"basedir",	  0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
447		{"seed",	  0, POPT_ARG_INT,  &torture_seed, 	0,	"Seed to use for randomizer", 	NULL},
448		{"num-progs",	  0, POPT_ARG_INT,  NULL, 	OPT_NUMPROGS,	"num progs",	NULL},
449		{"num-ops",	  0, POPT_ARG_INT,  &torture_numops, 	0, 	"num ops",	NULL},
450		{"entries",	  0, POPT_ARG_INT,  &torture_entries, 	0,	"entries",	NULL},
451		{"loadfile",	  0, POPT_ARG_STRING,	NULL, 	OPT_LOADFILE,	"NBench load file to use", 	NULL},
452		{"list", 	  0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
453		{"unclist",	  0, POPT_ARG_STRING,	NULL, 	OPT_UNCLIST,	"unclist", 	NULL},
454		{"timelimit",	't', POPT_ARG_INT,	NULL, 	OPT_TIMELIMIT,	"Set time limit (in seconds)", 	NULL},
455		{"failures",	'f', POPT_ARG_INT,  &torture_failures, 	0,	"failures", 	NULL},
456		{"parse-dns",	'D', POPT_ARG_STRING,	NULL, 	OPT_DNS,	"parse-dns", 	NULL},
457		{"dangerous",	'X', POPT_ARG_NONE,	NULL,   OPT_DANGEROUS,
458		 "run dangerous tests (eg. wiping out password database)", NULL},
459		{"load-module",  0,  POPT_ARG_STRING, &extra_module,     0, "load tests from DSO file",    "SOFILE"},
460		{"shell", 		0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
461		{"target", 		'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
462		{"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
463		 "run async tests", NULL},
464		{"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
465		 "number of simultaneous async requests", NULL},
466		{"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
467		 "set maximum time for smbtorture to live", "seconds"},
468		{"extra-user",   0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
469		 "extra user credentials", NULL},
470		POPT_COMMON_SAMBA
471		POPT_COMMON_CONNECTION
472		POPT_COMMON_CREDENTIALS
473		POPT_COMMON_VERSION
474		{ NULL }
475	};
476
477	setlinebuf(stdout);
478
479	/* we are never interested in SIGPIPE */
480	BlockSignals(true, SIGPIPE);
481
482	pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
483			    POPT_CONTEXT_KEEP_FIRST);
484
485	poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
486
487	while((opt = poptGetNextOpt(pc)) != -1) {
488		switch (opt) {
489		case OPT_LOADFILE:
490			lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
491			break;
492		case OPT_UNCLIST:
493			lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
494			break;
495		case OPT_TIMELIMIT:
496			lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
497			break;
498		case OPT_NUMPROGS:
499			lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
500			break;
501		case OPT_DNS:
502			parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
503			break;
504		case OPT_DANGEROUS:
505			lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
506			break;
507		case OPT_ASYNC:
508			lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
509			break;
510		case OPT_SMB_PORTS:
511			lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
512			break;
513		case OPT_EXTRA_USER:
514			{
515				char *option = talloc_asprintf(NULL, "torture:extra_user%u",
516							       ++num_extra_users);
517				char *value = poptGetOptArg(pc);
518				lp_set_cmdline(cmdline_lp_ctx, option, value);
519				talloc_free(option);
520			}
521			break;
522		default:
523			printf("bad command line option\n");
524			exit(1);
525		}
526	}
527
528	if (strcmp(target, "samba3") == 0) {
529		lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
530	} else if (strcmp(target, "samba4") == 0) {
531		lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
532	} else if (strcmp(target, "w2k8") == 0) {
533		lp_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
534	} else if (strcmp(target, "win7") == 0) {
535		lp_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
536	} else if (strcmp(target, "onefs") == 0) {
537		lp_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
538	}
539
540	if (max_runtime) {
541		/* this will only work if nobody else uses alarm(),
542		   which means it won't work for some tests, but we
543		   can't use the event context method we use for smbd
544		   as so many tests create their own event
545		   context. This will at least catch most cases. */
546		signal(SIGALRM, max_runtime_handler);
547		alarm(max_runtime);
548	}
549
550	if (extra_module != NULL) {
551	    init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
552
553	    if (fn == NULL)
554		d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
555	    else {
556		status = fn();
557		if (NT_STATUS_IS_ERR(status)) {
558		    d_printf("Error initializing module %s: %s\n",
559			     poptGetOptArg(pc), nt_errstr(status));
560		}
561	    }
562	} else {
563		torture_init();
564	}
565
566	if (list_tests) {
567		print_test_list();
568		return 0;
569	}
570
571	if (torture_seed == 0) {
572		torture_seed = time(NULL);
573	}
574	printf("Using seed %d\n", torture_seed);
575	srandom(torture_seed);
576
577	argv_new = discard_const_p(char *, poptGetArgs(pc));
578
579	argc_new = argc;
580	for (i=0; i<argc; i++) {
581		if (argv_new[i] == NULL) {
582			argc_new = i;
583			break;
584		}
585	}
586
587	if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
588		usage(pc);
589		exit(1);
590	}
591
592	if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
593		usage(pc);
594		exit(1);
595	}
596
597	if (!strcmp(ui_ops_name, "simple")) {
598		ui_ops = &std_ui_ops;
599	} else if (!strcmp(ui_ops_name, "subunit")) {
600		ui_ops = &torture_subunit_ui_ops;
601	} else {
602		printf("Unknown output format '%s'\n", ui_ops_name);
603		exit(1);
604	}
605
606	results = torture_results_init(talloc_autofree_context(), ui_ops);
607
608	torture = torture_context_init(s4_event_context_init(NULL), results);
609	if (basedir != NULL) {
610		if (basedir[0] != '/') {
611			fprintf(stderr, "Please specify an absolute path to --basedir\n");
612			return 1;
613		}
614		torture->outputdir = basedir;
615	} else {
616		char *pwd = talloc_size(torture, PATH_MAX);
617		if (!getcwd(pwd, PATH_MAX)) {
618			fprintf(stderr, "Unable to determine current working directory\n");
619			return 1;
620		}
621		torture->outputdir = pwd;
622	}
623
624	torture->lp_ctx = cmdline_lp_ctx;
625
626	gensec_init(cmdline_lp_ctx);
627
628	if (argc_new == 0) {
629		printf("You must specify a test to run, or 'ALL'\n");
630	} else if (shell) {
631		run_shell(torture);
632	} else {
633		for (i=2;i<argc_new;i++) {
634			if (!run_test(torture, argv_new[i])) {
635				correct = false;
636			}
637		}
638	}
639
640	if (torture->results->returncode && correct) {
641		return(0);
642	} else {
643		return(1);
644	}
645}
646