r18421: support --target=samba3, I thought that was already supported
[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 "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, "samba3|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         setlinebuf(stdout);
417
418         /* we are never interested in SIGPIPE */
419         BlockSignals(True,SIGPIPE);
420
421         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
422                             POPT_CONTEXT_KEEP_FIRST);
423
424         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
425
426         while((opt = poptGetNextOpt(pc)) != -1) {
427                 switch (opt) {
428                 case OPT_LOADFILE:
429                         lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
430                         break;
431                 case OPT_UNCLIST:
432                         lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
433                         break;
434                 case OPT_TIMELIMIT:
435                         lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
436                         break;
437                 case OPT_DNS:
438                         parse_dns(poptGetOptArg(pc));
439                         break;
440                 case OPT_DANGEROUS:
441                         lp_set_cmdline("torture:dangerous", "Yes");
442                         break;
443                 case OPT_ASYNC:
444                         lp_set_cmdline("torture:async", "Yes");
445                         break;
446                 case OPT_SMB_PORTS:
447                         lp_set_cmdline("smb ports", poptGetOptArg(pc));
448                         break;
449                 default:
450                         d_printf("Invalid option %s: %s\n", 
451                                  poptBadOption(pc, 0), poptStrerror(opt));
452                         torture_init();
453                         usage(pc);
454                         exit(1);
455                 }
456         }
457
458         if (max_runtime) {
459                 /* this will only work if nobody else uses alarm(),
460                    which means it won't work for some tests, but we
461                    can't use the event context method we use for smbd
462                    as so many tests create their own event
463                    context. This will at least catch most cases. */
464                 signal(SIGALRM, max_runtime_handler);
465                 alarm(max_runtime);
466         }
467
468         torture_init();
469         ldb_global_init();
470
471         if (torture_seed == 0) {
472                 torture_seed = time(NULL);
473         } 
474         printf("Using seed %d\n", torture_seed);
475         srandom(torture_seed);
476
477         argv_new = discard_const_p(char *, poptGetArgs(pc));
478
479         argc_new = argc;
480         for (i=0; i<argc; i++) {
481                 if (argv_new[i] == NULL) {
482                         argc_new = i;
483                         break;
484                 }
485         }
486
487         if (argc_new < 3) {
488                 usage(pc);
489                 exit(1);
490         }
491
492         if (strcmp(target, "samba3") == 0) {
493                 lp_set_cmdline("target:samba3", "true");
494         } else if (strcmp(target, "samba4") == 0) {
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 }