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