r14561: Update WHATSNEW.txt to revision 14554
[Samba.git] / source / torture / smbtorture.c
blobc2f4f84fac9afc39725b96ce8dafa7884b0e526b
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "system/time.h"
26 #include "system/wait.h"
27 #include "system/filesys.h"
28 #include "libcli/raw/ioctl.h"
29 #include "libcli/libcli.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/events/events.h"
32 #include "libcli/resolve/resolve.h"
33 #include "auth/credentials/credentials.h"
34 #include "libcli/ldap/ldap_client.h"
35 #include "librpc/gen_ndr/ndr_nbt.h"
37 #include "torture/torture.h"
38 #include "build.h"
39 #include "dlinklist.h"
40 #include "librpc/rpc/dcerpc.h"
42 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
44 /****************************************************************************
45 run a specified test or "ALL"
46 ****************************************************************************/
47 static BOOL run_test(const char *name)
49 BOOL ret = True;
50 struct torture_op *o;
51 BOOL matched = False;
53 if (strequal(name,"ALL")) {
54 for (o = torture_ops; o; o = o->next) {
55 if (!run_test(o->name)) {
56 ret = False;
59 return ret;
62 for (o = torture_ops; o; o = o->next) {
63 if (gen_fnmatch(name, o->name) == 0) {
64 double t;
65 matched = True;
66 init_iconv();
67 printf("Running %s\n", o->name);
68 if (o->multi_fn) {
69 BOOL result = False;
70 t = torture_create_procs(o->multi_fn,
71 &result);
72 if (!result) {
73 ret = False;
74 printf("TEST %s FAILED!\n", o->name);
77 } else {
78 struct timeval tv = timeval_current();
79 if (!o->fn()) {
80 ret = False;
81 printf("TEST %s FAILED!\n", o->name);
83 t = timeval_elapsed(&tv);
85 printf("%s took %g secs\n\n", o->name, t);
89 if (!matched) {
90 printf("Unknown torture operation '%s'\n", name);
93 return ret;
96 static void parse_dns(const char *dns)
98 char *userdn, *basedn, *secret;
99 char *p, *d;
101 /* retrievieng the userdn */
102 p = strchr_m(dns, '#');
103 if (!p) {
104 lp_set_cmdline("torture:ldap_userdn", "");
105 lp_set_cmdline("torture:ldap_basedn", "");
106 lp_set_cmdline("torture:ldap_secret", "");
107 return;
109 userdn = strndup(dns, p - dns);
110 lp_set_cmdline("torture:ldap_userdn", userdn);
112 /* retrieve the basedn */
113 d = p + 1;
114 p = strchr_m(d, '#');
115 if (!p) {
116 lp_set_cmdline("torture:ldap_basedn", "");
117 lp_set_cmdline("torture:ldap_secret", "");
118 return;
120 basedn = strndup(d, p - d);
121 lp_set_cmdline("torture:ldap_basedn", basedn);
123 /* retrieve the secret */
124 p = p + 1;
125 if (!p) {
126 lp_set_cmdline("torture:ldap_secret", "");
127 return;
129 secret = strdup(p);
130 lp_set_cmdline("torture:ldap_secret", secret);
132 printf ("%s - %s - %s\n", userdn, basedn, secret);
136 static void usage(poptContext pc)
138 struct torture_op *o;
139 int i;
141 poptPrintUsage(pc, stdout, 0);
142 printf("\n");
144 printf("The binding format is:\n\n");
146 printf(" TRANSPORT:host[flags]\n\n");
148 printf(" where TRANSPORT is either ncacn_np for SMB or ncacn_ip_tcp for RPC/TCP\n\n");
150 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
151 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
152 printf(" string.\n\n");
154 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
155 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
156 printf(" will be auto-determined.\n\n");
158 printf(" other recognised flags are:\n\n");
160 printf(" sign : enable ntlmssp signing\n");
161 printf(" seal : enable ntlmssp sealing\n");
162 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
163 printf(" validate: enable the NDR validator\n");
164 printf(" print: enable debugging of the packets\n");
165 printf(" bigendian: use bigendian RPC\n");
166 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
168 printf(" For example, these all connect to the samr pipe:\n\n");
170 printf(" ncacn_np:myserver\n");
171 printf(" ncacn_np:myserver[samr]\n");
172 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
173 printf(" ncacn_np:myserver[/pipe/samr]\n");
174 printf(" ncacn_np:myserver[samr,sign,print]\n");
175 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
176 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
177 printf(" ncacn_np:\n");
178 printf(" ncacn_np:[/pipe/samr]\n\n");
180 printf(" ncacn_ip_tcp:myserver\n");
181 printf(" ncacn_ip_tcp:myserver[1024]\n");
182 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
184 printf("The unc format is:\n\n");
186 printf(" //server/share\n\n");
188 printf("tests are:\n");
190 i = 0;
191 for (o = torture_ops; o; o = o->next) {
192 if (i + strlen(o->name) >= MAX_COLS) {
193 printf("\n");
194 i = 0;
196 i+=printf("%s ", o->name);
198 printf("\n\n");
200 printf("default test is ALL\n");
202 exit(1);
205 static BOOL is_binding_string(const char *binding_string)
207 TALLOC_CTX *mem_ctx = talloc_init("is_binding_string");
208 struct dcerpc_binding *binding_struct;
209 NTSTATUS status;
211 status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
213 talloc_free(mem_ctx);
214 return NT_STATUS_IS_OK(status);
217 static void max_runtime_handler(int sig)
219 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
220 exit(1);
223 /****************************************************************************
224 main program
225 ****************************************************************************/
226 int main(int argc,char *argv[])
228 int opt, i;
229 char *p;
230 BOOL correct = True;
231 int max_runtime=0;
232 int argc_new;
233 char **argv_new;
234 poptContext pc;
235 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
236 OPT_DANGEROUS,OPT_SMB_PORTS};
238 struct poptOption long_options[] = {
239 POPT_AUTOHELP
240 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
241 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
242 {"num-progs", 0, POPT_ARG_INT, &torture_nprocs, 0, "num progs", NULL},
243 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
244 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
245 {"use-oplocks", 'L', POPT_ARG_NONE, &use_oplocks, 0, "use oplocks", NULL},
246 {"show-all", 0, POPT_ARG_NONE, &torture_showall, 0, "show all", NULL},
247 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
248 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
249 {"timelimit", 't', POPT_ARG_STRING, NULL, OPT_TIMELIMIT, "timelimit", NULL},
250 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
251 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
252 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS, "dangerous", NULL},
253 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
254 "set maximum time for smbtorture to live", "seconds"},
255 POPT_COMMON_SAMBA
256 POPT_COMMON_CONNECTION
257 POPT_COMMON_CREDENTIALS
258 POPT_COMMON_VERSION
259 POPT_TABLEEND
262 #ifdef HAVE_SETBUFFER
263 setbuffer(stdout, NULL, 0);
264 #endif
266 torture_init();
268 /* we are never interested in SIGPIPE */
269 BlockSignals(True,SIGPIPE);
271 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
272 POPT_CONTEXT_KEEP_FIRST);
274 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
276 while((opt = poptGetNextOpt(pc)) != -1) {
277 switch (opt) {
278 case OPT_LOADFILE:
279 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
280 break;
281 case OPT_UNCLIST:
282 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
283 break;
284 case OPT_TIMELIMIT:
285 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
286 break;
287 case OPT_DNS:
288 parse_dns(poptGetOptArg(pc));
289 break;
290 case OPT_DANGEROUS:
291 lp_set_cmdline("torture:dangerous", "Yes");
292 break;
293 case OPT_SMB_PORTS:
294 lp_set_cmdline("smb ports", poptGetOptArg(pc));
295 break;
296 default:
297 d_printf("Invalid option %s: %s\n",
298 poptBadOption(pc, 0), poptStrerror(opt));
299 usage(pc);
300 exit(1);
304 if (max_runtime) {
305 /* this will only work if nobody else uses alarm(),
306 which means it won't work for some tests, but we
307 can't use the event context method we use for smbd
308 as so many tests create their own event
309 context. This will at least catch most cases. */
310 signal(SIGALRM, max_runtime_handler);
311 alarm(max_runtime);
314 ldb_global_init();
316 if (torture_seed == 0) {
317 torture_seed = time(NULL);
319 printf("Using seed %d\n", torture_seed);
320 srandom(torture_seed);
322 argv_new = discard_const_p(char *, poptGetArgs(pc));
324 argc_new = argc;
325 for (i=0; i<argc; i++) {
326 if (argv_new[i] == NULL) {
327 argc_new = i;
328 break;
332 if (argc_new < 3) {
333 usage(pc);
334 exit(1);
337 for(p = argv_new[1]; *p; p++) {
338 if(*p == '\\')
339 *p = '/';
342 /* see if its a RPC transport specifier */
343 if (is_binding_string(argv_new[1])) {
344 lp_set_cmdline("torture:binding", argv_new[1]);
345 } else {
346 char *binding = NULL;
347 char *host = NULL, *share = NULL;
349 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
350 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
351 usage(pc);
354 lp_set_cmdline("torture:host", host);
355 lp_set_cmdline("torture:share", share);
356 asprintf(&binding, "ncacn_np:%s", host);
357 lp_set_cmdline("torture:binding", binding);
360 if (argc_new == 0) {
361 printf("You must specify a test to run, or 'ALL'\n");
362 } else {
363 for (i=2;i<argc_new;i++) {
364 if (!run_test(argv_new[i])) {
365 correct = False;
370 if (correct) {
371 return(0);
372 } else {
373 return(1);