r16160: Fix double semicolon in ui.h
[mat/samba.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 "system/time.h"
25 #include "system/wait.h"
26 #include "system/filesys.h"
27 #include "libcli/libcli.h"
28 #include "lib/ldb/include/ldb.h"
29 #include "lib/events/events.h"
30
31 #include "torture/torture.h"
32 #include "torture/ui.h"
33 #include "build.h"
34 #include "dlinklist.h"
35 #include "librpc/rpc/dcerpc.h"
36
37 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
38
39 /****************************************************************************
40 run a specified test or "ALL"
41 ****************************************************************************/
42 static BOOL run_test(struct torture_context *torture, const char *name)
43 {
44         BOOL ret = True;
45         struct torture_op *o;
46         BOOL matched = False;
47
48         if (strequal(name,"ALL")) {
49                 for (o = torture_ops; o; o = o->next) {
50                         if (!run_test(torture, o->name)) {
51                                 ret = False;
52                         }
53                 }
54                 return ret;
55         }
56
57         for (o = torture_ops; o; o = o->next) {
58                 if (gen_fnmatch(name, o->name) == 0) {
59                         double t;
60                         matched = True;
61                         init_iconv();
62                         printf("Running %s\n", o->name);
63                         if (o->multi_fn) {
64                                 BOOL result = False;
65                                 t = torture_create_procs(o->multi_fn, 
66                                                          &result);
67                                 if (!result) { 
68                                         ret = False;
69                                         printf("TEST %s FAILED!\n", o->name);
70                                 }
71                                          
72                         } else {
73                                 struct timeval tv = timeval_current();
74                                 if (!o->fn(torture)) {
75                                         ret = False;
76                                         printf("TEST %s FAILED!\n", o->name);
77                                 }
78                                 t = timeval_elapsed(&tv);
79                         }
80                         printf("%s took %g secs\n\n", o->name, t);
81                 }
82         }
83
84         if (!matched) {
85                 printf("Unknown torture operation '%s'\n", name);
86                 ret = False;
87         }
88
89         return ret;
90 }
91
92 static void parse_dns(const char *dns)
93 {
94         char *userdn, *basedn, *secret;
95         char *p, *d;
96
97         /* retrievieng the userdn */
98         p = strchr_m(dns, '#');
99         if (!p) {
100                 lp_set_cmdline("torture:ldap_userdn", "");
101                 lp_set_cmdline("torture:ldap_basedn", "");
102                 lp_set_cmdline("torture:ldap_secret", "");
103                 return;
104         }
105         userdn = strndup(dns, p - dns);
106         lp_set_cmdline("torture:ldap_userdn", userdn);
107
108         /* retrieve the basedn */
109         d = p + 1;
110         p = strchr_m(d, '#');
111         if (!p) {
112                 lp_set_cmdline("torture:ldap_basedn", "");
113                 lp_set_cmdline("torture:ldap_secret", "");
114                 return;
115         }
116         basedn = strndup(d, p - d);
117         lp_set_cmdline("torture:ldap_basedn", basedn);
118
119         /* retrieve the secret */
120         p = p + 1;
121         if (!p) {
122                 lp_set_cmdline("torture:ldap_secret", "");
123                 return;
124         }
125         secret = strdup(p);
126         lp_set_cmdline("torture:ldap_secret", secret);
127
128         printf ("%s - %s - %s\n", userdn, basedn, secret);
129
130 }
131
132 static void usage(poptContext pc)
133 {
134         struct torture_op *o;
135         char last_prefix[64];
136         int i;
137
138         poptPrintUsage(pc, stdout, 0);
139         printf("\n");
140
141         printf("The binding format is:\n\n");
142
143         printf("  TRANSPORT:host[flags]\n\n");
144
145         printf("  where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
146         printf("  or ncalrpc for local connections.\n\n");
147
148         printf("  'host' is an IP or hostname or netbios name. If the binding string\n");
149         printf("  identifies the server side of an endpoint, 'host' may be an empty\n");
150         printf("  string.\n\n");
151
152         printf("  'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
153         printf("  a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
154         printf("  will be auto-determined.\n\n");
155
156         printf("  other recognised flags are:\n\n");
157
158         printf("    sign : enable ntlmssp signing\n");
159         printf("    seal : enable ntlmssp sealing\n");
160         printf("    connect : enable rpc connect level auth (auth, but no sign or seal)\n");
161         printf("    validate: enable the NDR validator\n");
162         printf("    print: enable debugging of the packets\n");
163         printf("    bigendian: use bigendian RPC\n");
164         printf("    padcheck: check reply data for non-zero pad bytes\n\n");
165
166         printf("  For example, these all connect to the samr pipe:\n\n");
167
168         printf("    ncacn_np:myserver\n");
169         printf("    ncacn_np:myserver[samr]\n");
170         printf("    ncacn_np:myserver[\\pipe\\samr]\n");
171         printf("    ncacn_np:myserver[/pipe/samr]\n");
172         printf("    ncacn_np:myserver[samr,sign,print]\n");
173         printf("    ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
174         printf("    ncacn_np:myserver[/pipe/samr,seal,validate]\n");
175         printf("    ncacn_np:\n");
176         printf("    ncacn_np:[/pipe/samr]\n\n");
177
178         printf("    ncacn_ip_tcp:myserver\n");
179         printf("    ncacn_ip_tcp:myserver[1024]\n");
180         printf("    ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
181
182         printf("    ncalrpc:\n\n");
183
184         printf("The UNC format is:\n\n");
185
186         printf("  //server/share\n\n");
187
188         printf("Tests are:");
189
190         i = 0;
191         last_prefix[0] = '\0';
192         for (o = torture_ops; o; o = o->next) {
193                 const char * sep;
194
195                 if ((sep = strchr(o->name, '-'))) {
196                         if (strncmp(o->name, last_prefix, sep - o->name) != 0) {
197                                 strncpy(last_prefix, o->name,
198                                         MIN(sizeof(last_prefix),
199                                             sep - o->name));
200                                 printf("\n\n  ");
201                                 i = 0;
202                         }
203                 }
204
205                 if (i + strlen(o->name) >= (MAX_COLS - 2)) {
206                         printf("\n  ");
207                         i = 0;
208                 }
209                 i+=printf("%s ", o->name);
210         }
211         printf("\n\n");
212
213         printf("The default test is ALL.\n");
214
215         exit(1);
216 }
217
218 static BOOL is_binding_string(const char *binding_string)
219 {
220         TALLOC_CTX *mem_ctx = talloc_init("is_binding_string");
221         struct dcerpc_binding *binding_struct;
222         NTSTATUS status;
223         
224         status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
225
226         talloc_free(mem_ctx);
227         return NT_STATUS_IS_OK(status);
228 }
229
230 static void max_runtime_handler(int sig)
231 {
232         DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
233         exit(1);
234 }
235
236 static void simple_test_start (struct torture_test *test)
237 {
238         printf("Testing %s...\n", test->name);
239 }
240
241 static void simple_test_result (struct torture_test *test, enum torture_result res, const char *reason)
242 {
243         printf("\t %d: %s\n",res, reason?reason:"");
244 }
245
246 static void simple_comment (struct torture_test *test, const char *comment)
247 {
248         printf("# %s\n", comment);
249 }
250
251 const static struct torture_ui_ops std_ui_ops = {
252         .comment = simple_comment,
253         .test_start = simple_test_start,
254         .test_result = simple_test_result
255 };
256
257
258 static void subunit_test_start (struct torture_test *test)
259 {
260         printf("test: %s\n", test->name);
261 }
262
263 static void subunit_test_result (struct torture_test *test, enum torture_result res, const char *reason)
264 {
265         switch (res) {
266         case TORTURE_OK:
267                 printf("success: %s\n", test->name);
268                 break;
269         case TORTURE_FAIL:
270                 printf("failure: %s [ %s ]\n", test->name, reason);
271                 break;
272         case TORTURE_TODO:
273                 printf("todo: %s\n", test->name);
274                 break;
275         case TORTURE_SKIP:
276                 printf("skip: %s\n", test->name);
277                 break;
278         }
279 }
280
281 static void subunit_comment (struct torture_test *test, const char *comment)
282 {
283         printf("# %s\n", comment);
284 }
285
286 const static struct torture_ui_ops subunit_ui_ops = {
287         .comment = subunit_comment,
288         .test_start = subunit_test_start,
289         .test_result = subunit_test_result
290 };
291
292 static void harness_test_start (struct torture_test *test)
293 {
294 }
295
296 static void harness_test_result (struct torture_test *test, enum torture_result res, const char *reason)
297 {
298         switch (res) {
299         case TORTURE_OK:
300                 printf("ok %s - %s\n", test->name, reason);
301                 break;
302         case TORTURE_FAIL:
303                 printf("not ok %s - %s\n", test->name, reason);
304                 break;
305         case TORTURE_TODO:
306                 printf("todo %s - %s\n", test->name, reason);
307                 break;
308         case TORTURE_SKIP:
309                 printf("skip %s - %s\n", test->name, reason);
310                 break;
311         }
312 }
313
314 static void harness_comment (struct torture_test *test, const char *comment)
315 {
316         printf("# %s\n", comment);
317 }
318
319 const static struct torture_ui_ops harness_ui_ops = {
320         .comment = harness_comment,
321         .test_start = harness_test_start,
322         .test_result = harness_test_result
323 };
324
325 /****************************************************************************
326   main program
327 ****************************************************************************/
328  int main(int argc,char *argv[])
329 {
330         int opt, i;
331         char *p;
332         BOOL correct = True;
333         int max_runtime=0;
334         int argc_new;
335         struct torture_context *torture;
336         char **argv_new;
337         poptContext pc;
338         static char *ui_ops_name = "simple";
339         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
340               OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC};
341         
342         struct poptOption long_options[] = {
343                 POPT_AUTOHELP
344                 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
345                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
346                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "seed",         NULL},
347                 {"num-progs",     0, POPT_ARG_INT,  &torture_nprocs,    0,      "num progs",    NULL},
348                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
349                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
350                 {"use-oplocks", 'L', POPT_ARG_NONE, &use_oplocks,       0,      "use oplocks",  NULL},
351                 {"show-all",      0, POPT_ARG_NONE, &torture_showall,   0,      "show all",     NULL},
352                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "loadfile",     NULL},
353                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
354                 {"timelimit",   't', POPT_ARG_STRING,   NULL,   OPT_TIMELIMIT,  "timelimit",    NULL},
355                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
356                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
357                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,
358                  "run dangerous tests (eg. wiping out password database)", NULL},
359                 {"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
360                  "run async tests", NULL},
361                 {"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
362                  "number of simultaneous async requests", NULL},
363                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
364                  "set maximum time for smbtorture to live", "seconds"},
365                 POPT_COMMON_SAMBA
366                 POPT_COMMON_CONNECTION
367                 POPT_COMMON_CREDENTIALS
368                 POPT_COMMON_VERSION
369                 POPT_TABLEEND
370         };
371
372 #ifdef HAVE_SETBUFFER
373         setbuffer(stdout, NULL, 0);
374 #endif
375
376         /* we are never interested in SIGPIPE */
377         BlockSignals(True,SIGPIPE);
378
379         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
380                             POPT_CONTEXT_KEEP_FIRST);
381
382         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
383
384         while((opt = poptGetNextOpt(pc)) != -1) {
385                 switch (opt) {
386                 case OPT_LOADFILE:
387                         lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
388                         break;
389                 case OPT_UNCLIST:
390                         lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
391                         break;
392                 case OPT_TIMELIMIT:
393                         lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
394                         break;
395                 case OPT_DNS:
396                         parse_dns(poptGetOptArg(pc));
397                         break;
398                 case OPT_DANGEROUS:
399                         lp_set_cmdline("torture:dangerous", "Yes");
400                         break;
401                 case OPT_ASYNC:
402                         lp_set_cmdline("torture:async", "Yes");
403                         break;
404                 case OPT_SMB_PORTS:
405                         lp_set_cmdline("smb ports", poptGetOptArg(pc));
406                         break;
407                 default:
408                         d_printf("Invalid option %s: %s\n", 
409                                  poptBadOption(pc, 0), poptStrerror(opt));
410                         torture_init();
411                         usage(pc);
412                         exit(1);
413                 }
414         }
415
416         if (max_runtime) {
417                 /* this will only work if nobody else uses alarm(),
418                    which means it won't work for some tests, but we
419                    can't use the event context method we use for smbd
420                    as so many tests create their own event
421                    context. This will at least catch most cases. */
422                 signal(SIGALRM, max_runtime_handler);
423                 alarm(max_runtime);
424         }
425
426         torture_init();
427         ldb_global_init();
428
429         if (torture_seed == 0) {
430                 torture_seed = time(NULL);
431         } 
432         printf("Using seed %d\n", torture_seed);
433         srandom(torture_seed);
434
435         argv_new = discard_const_p(char *, poptGetArgs(pc));
436
437         argc_new = argc;
438         for (i=0; i<argc; i++) {
439                 if (argv_new[i] == NULL) {
440                         argc_new = i;
441                         break;
442                 }
443         }
444
445         if (argc_new < 3) {
446                 usage(pc);
447                 exit(1);
448         }
449
450         for(p = argv_new[1]; *p; p++) {
451                 if(*p == '\\')
452                         *p = '/';
453         }
454
455         /* see if its a RPC transport specifier */
456         if (is_binding_string(argv_new[1])) {
457                 lp_set_cmdline("torture:binding", argv_new[1]);
458         } else {
459                 char *binding = NULL;
460                 char *host = NULL, *share = NULL;
461
462                 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
463                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
464                         usage(pc);
465                 }
466
467                 lp_set_cmdline("torture:host", host);
468                 lp_set_cmdline("torture:share", share);
469                 asprintf(&binding, "ncacn_np:%s", host);
470                 lp_set_cmdline("torture:binding", binding);
471         }
472
473         torture = talloc_zero(NULL, struct torture_context);
474         if (!strcmp(ui_ops_name, "simple")) {
475                 torture->ui_ops = &std_ui_ops;
476         } else if (!strcmp(ui_ops_name, "subunit")) {
477                 torture->ui_ops = &subunit_ui_ops;
478         } else if (!strcmp(ui_ops_name, "harness")) {
479                 torture->ui_ops = &harness_ui_ops;
480         } else {
481                 printf("Unknown output format '%s'\n", ui_ops_name);
482                 exit(1);
483         }
484
485         if (argc_new == 0) {
486                 printf("You must specify a test to run, or 'ALL'\n");
487         } else {
488                 for (i=2;i<argc_new;i++) {
489                         if (!run_test(torture, argv_new[i])) {
490                                 correct = False;
491                         }
492                 }
493         }
494
495         talloc_free(torture);
496
497         if (correct) {
498                 return(0);
499         } else {
500                 return(1);
501         }
502 }