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