r14542: Remove librpc, libndr and libnbt from includes.h
[ira/wip.git] / source4 / 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 #include "librpc/rpc/dcerpc.h"
41
42 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
43
44 /****************************************************************************
45 run a specified test or "ALL"
46 ****************************************************************************/
47 static BOOL run_test(const char *name)
48 {
49         BOOL ret = True;
50         struct torture_op *o;
51         BOOL matched = False;
52
53         if (strequal(name,"ALL")) {
54                 for (o = torture_ops; o; o = o->next) {
55                         if (!run_test(o->name)) {
56                                 ret = False;
57                         }
58                 }
59                 return ret;
60         }
61
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);
75                                 }
76                                          
77                         } else {
78                                 struct timeval tv = timeval_current();
79                                 if (!o->fn()) {
80                                         ret = False;
81                                         printf("TEST %s FAILED!\n", o->name);
82                                 }
83                                 t = timeval_elapsed(&tv);
84                         }
85                         printf("%s took %g secs\n\n", o->name, t);
86                 }
87         }
88
89         if (!matched) {
90                 printf("Unknown torture operation '%s'\n", name);
91         }
92
93         return ret;
94 }
95
96 static void parse_dns(const char *dns)
97 {
98         char *userdn, *basedn, *secret;
99         char *p, *d;
100
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;
108         }
109         userdn = strndup(dns, p - dns);
110         lp_set_cmdline("torture:ldap_userdn", userdn);
111
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;
119         }
120         basedn = strndup(d, p - d);
121         lp_set_cmdline("torture:ldap_basedn", basedn);
122
123         /* retrieve the secret */
124         p = p + 1;
125         if (!p) {
126                 lp_set_cmdline("torture:ldap_secret", "");
127                 return;
128         }
129         secret = strdup(p);
130         lp_set_cmdline("torture:ldap_secret", secret);
131
132         printf ("%s - %s - %s\n", userdn, basedn, secret);
133
134 }
135
136 static void usage(poptContext pc)
137 {
138         struct torture_op *o;
139         int i;
140
141         poptPrintUsage(pc, stdout, 0);
142         printf("\n");
143
144         printf("The binding format is:\n\n");
145
146         printf("  TRANSPORT:host[flags]\n\n");
147
148         printf("  where TRANSPORT is either ncacn_np for SMB or ncacn_ip_tcp for RPC/TCP\n\n");
149
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");
153
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");
157
158         printf("  other recognised flags are:\n\n");
159
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");
167
168         printf("  For example, these all connect to the samr pipe:\n\n");
169
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");
179
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");
183
184         printf("The unc format is:\n\n");
185
186         printf("    //server/share\n\n");
187
188         printf("tests are:\n");
189
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;
195                 }
196                 i+=printf("%s ", o->name);
197         }
198         printf("\n\n");
199
200         printf("default test is ALL\n");
201
202         exit(1);
203 }
204
205 static BOOL is_binding_string(const char *binding_string)
206 {
207         TALLOC_CTX *mem_ctx = talloc_init("is_binding_string");
208         struct dcerpc_binding *binding_struct;
209         NTSTATUS status;
210         
211         status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
212
213         talloc_free(mem_ctx);
214         return NT_STATUS_IS_OK(status);
215 }
216
217 static void max_runtime_handler(int sig)
218 {
219         DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
220         exit(1);
221 }
222
223 /****************************************************************************
224   main program
225 ****************************************************************************/
226  int main(int argc,char *argv[])
227 {
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};
237         
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
260         };
261
262 #ifdef HAVE_SETBUFFER
263         setbuffer(stdout, NULL, 0);
264 #endif
265
266         torture_init();
267
268         /* we are never interested in SIGPIPE */
269         BlockSignals(True,SIGPIPE);
270
271         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
272                             POPT_CONTEXT_KEEP_FIRST);
273
274         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
275
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);
301                 }
302         }
303
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);
312         }
313
314         ldb_global_init();
315
316         if (torture_seed == 0) {
317                 torture_seed = time(NULL);
318         } 
319         printf("Using seed %d\n", torture_seed);
320         srandom(torture_seed);
321
322         argv_new = discard_const_p(char *, poptGetArgs(pc));
323
324         argc_new = argc;
325         for (i=0; i<argc; i++) {
326                 if (argv_new[i] == NULL) {
327                         argc_new = i;
328                         break;
329                 }
330         }
331
332         if (argc_new < 3) {
333                 usage(pc);
334                 exit(1);
335         }
336
337         for(p = argv_new[1]; *p; p++) {
338                 if(*p == '\\')
339                         *p = '/';
340         }
341
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;
348
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);
352                 }
353
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);
358         }
359
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;
366                         }
367                 }
368         }
369
370         if (correct) {
371                 return(0);
372         } else {
373                 return(1);
374         }
375 }