s4/torture: Port SMBv1 Change Notify tests to SMBv2
[nivanova/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-2008
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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/filesys.h"
26 #include "system/readline.h"
27 #include "lib/smbreadline/smbreadline.h"
28 #include "libcli/libcli.h"
29 #include "lib/events/events.h"
30
31 #include "torture/smbtorture.h"
32 #include "librpc/rpc/dcerpc.h"
33 #include "auth/gensec/gensec.h"
34 #include "param/param.h"
35
36
37 static bool run_matching(struct torture_context *torture,
38                                                  const char *prefix, 
39                                                  const char *expr,
40                                                  struct torture_suite *suite,
41                                                  bool *matched)
42 {
43         bool ret = true;
44
45         if (suite == NULL) {
46                 struct torture_suite *o;
47
48                 for (o = (torture_root == NULL?NULL:torture_root->children); o; o = o->next) {
49                         if (gen_fnmatch(expr, o->name) == 0) {
50                                 *matched = true;
51                                 reload_charcnv(torture->lp_ctx);
52                                 ret &= torture_run_suite(torture, o);
53                                 continue;
54                         }
55
56                         ret &= run_matching(torture, o->name, expr, o, matched);
57                 }
58         } else {
59                 char *name;
60                 struct torture_suite *c;
61                 struct torture_tcase *t;
62
63                 for (c = suite->children; c; c = c->next) {
64                         asprintf(&name, "%s-%s", prefix, c->name);
65
66                         if (gen_fnmatch(expr, name) == 0) {
67                                 *matched = true;
68                                 reload_charcnv(torture->lp_ctx);
69                                 torture->active_testname = talloc_strdup(torture, prefix);
70                                 ret &= torture_run_suite(torture, c);
71                                 free(name);
72                                 continue;
73                         }
74                         
75                         ret &= run_matching(torture, name, expr, c, matched);
76
77                         free(name);
78                 }
79
80                 for (t = suite->testcases; t; t = t->next) {
81                         asprintf(&name, "%s-%s", prefix, t->name);
82                         if (gen_fnmatch(expr, name) == 0) {
83                                 *matched = true;
84                                 reload_charcnv(torture->lp_ctx);
85                                 torture->active_testname = talloc_strdup(torture, prefix);
86                                 ret &= torture_run_tcase(torture, t);
87                                 talloc_free(torture->active_testname);
88                         }
89                         free(name);
90                 }
91         }
92
93         return ret;
94 }
95
96 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
97
98 /****************************************************************************
99 run a specified test or "ALL"
100 ****************************************************************************/
101 static bool run_test(struct torture_context *torture, const char *name)
102 {
103         bool ret = true;
104         bool matched = false;
105         struct torture_suite *o;
106
107         if (strequal(name, "ALL")) {
108                 for (o = torture_root->children; o; o = o->next) {
109                         ret &= torture_run_suite(torture, o);
110                 }
111                 return ret;
112         }
113
114         ret = run_matching(torture, NULL, name, NULL, &matched);
115
116         if (!matched) {
117                 printf("Unknown torture operation '%s'\n", name);
118                 return false;
119         }
120
121         return ret;
122 }
123
124 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
125 {
126         char *host = NULL, *share = NULL;
127         struct dcerpc_binding *binding_struct;
128         NTSTATUS status;
129
130         /* see if its a RPC transport specifier */
131         if (!smbcli_parse_unc(target, NULL, &host, &share)) {
132                 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
133                 if (NT_STATUS_IS_ERR(status)) {
134                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
135                         return false;
136                 }
137                 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
138                 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
139                         lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
140                 lp_set_cmdline(lp_ctx, "torture:binding", target);
141         } else {
142                 lp_set_cmdline(lp_ctx, "torture:host", host);
143                 lp_set_cmdline(lp_ctx, "torture:share", share);
144                 lp_set_cmdline(lp_ctx, "torture:binding", host);
145         }
146
147         return true;
148 }
149
150 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
151 {
152         char *userdn, *basedn, *secret;
153         char *p, *d;
154
155         /* retrievieng the userdn */
156         p = strchr_m(dns, '#');
157         if (!p) {
158                 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
159                 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
160                 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
161                 return;
162         }
163         userdn = strndup(dns, p - dns);
164         lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
165
166         /* retrieve the basedn */
167         d = p + 1;
168         p = strchr_m(d, '#');
169         if (!p) {
170                 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
171                 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
172                 return;
173         }
174         basedn = strndup(d, p - d);
175         lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
176
177         /* retrieve the secret */
178         p = p + 1;
179         if (!p) {
180                 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
181                 return;
182         }
183         secret = strdup(p);
184         lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
185
186         printf ("%s - %s - %s\n", userdn, basedn, secret);
187
188 }
189
190 static void print_test_list(void)
191 {
192         struct torture_suite *o;
193         struct torture_suite *s;
194         struct torture_tcase *t;
195
196         if (torture_root == NULL)
197                 return;
198
199         for (o = torture_root->children; o; o = o->next) {
200                 for (s = o->children; s; s = s->next) {
201                         printf("%s-%s\n", o->name, s->name);
202                 }
203
204                 for (t = o->testcases; t; t = t->next) {
205                         printf("%s-%s\n", o->name, t->name);
206                 }
207         }
208 }
209
210 _NORETURN_ static void usage(poptContext pc)
211 {
212         struct torture_suite *o;
213         struct torture_suite *s;
214         struct torture_tcase *t;
215         int i;
216
217         poptPrintUsage(pc, stdout, 0);
218         printf("\n");
219
220         printf("The binding format is:\n\n");
221
222         printf("  TRANSPORT:host[flags]\n\n");
223
224         printf("  where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
225         printf("  or ncalrpc for local connections.\n\n");
226
227         printf("  'host' is an IP or hostname or netbios name. If the binding string\n");
228         printf("  identifies the server side of an endpoint, 'host' may be an empty\n");
229         printf("  string.\n\n");
230
231         printf("  'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
232         printf("  a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
233         printf("  will be auto-determined.\n\n");
234
235         printf("  other recognised flags are:\n\n");
236
237         printf("    sign : enable ntlmssp signing\n");
238         printf("    seal : enable ntlmssp sealing\n");
239         printf("    connect : enable rpc connect level auth (auth, but no sign or seal)\n");
240         printf("    validate: enable the NDR validator\n");
241         printf("    print: enable debugging of the packets\n");
242         printf("    bigendian: use bigendian RPC\n");
243         printf("    padcheck: check reply data for non-zero pad bytes\n\n");
244
245         printf("  For example, these all connect to the samr pipe:\n\n");
246
247         printf("    ncacn_np:myserver\n");
248         printf("    ncacn_np:myserver[samr]\n");
249         printf("    ncacn_np:myserver[\\pipe\\samr]\n");
250         printf("    ncacn_np:myserver[/pipe/samr]\n");
251         printf("    ncacn_np:myserver[samr,sign,print]\n");
252         printf("    ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
253         printf("    ncacn_np:myserver[/pipe/samr,seal,validate]\n");
254         printf("    ncacn_np:\n");
255         printf("    ncacn_np:[/pipe/samr]\n\n");
256
257         printf("    ncacn_ip_tcp:myserver\n");
258         printf("    ncacn_ip_tcp:myserver[1024]\n");
259         printf("    ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
260
261         printf("    ncalrpc:\n\n");
262
263         printf("The UNC format is:\n\n");
264
265         printf("  //server/share\n\n");
266
267         printf("Tests are:");
268
269         if (torture_root == NULL) {
270             printf("NO TESTS LOADED\n");
271             exit(1);
272         }
273
274         for (o = torture_root->children; o; o = o->next) {
275                 printf("\n%s (%s):\n  ", o->description, o->name);
276
277                 i = 0;
278                 for (s = o->children; s; s = s->next) {
279                         if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
280                                 printf("\n  ");
281                                 i = 0;
282                         }
283                         i+=printf("%s-%s ", o->name, s->name);
284                 }
285
286                 for (t = o->testcases; t; t = t->next) {
287                         if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
288                                 printf("\n  ");
289                                 i = 0;
290                         }
291                         i+=printf("%s-%s ", o->name, t->name);
292                 }
293
294                 if (i) printf("\n");
295         }
296
297         printf("\nThe default test is ALL.\n");
298
299         exit(1);
300 }
301
302 _NORETURN_ static void max_runtime_handler(int sig)
303 {
304         DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
305         exit(1);
306 }
307
308 struct timeval last_suite_started;
309
310 static void simple_suite_start(struct torture_context *ctx,
311                                struct torture_suite *suite)
312 {
313         last_suite_started = timeval_current();
314         printf("Running %s\n", suite->name);
315 }
316
317 static void simple_suite_finish(struct torture_context *ctx,
318                                 struct torture_suite *suite)
319 {
320
321         printf("%s took %g secs\n\n", suite->name, 
322                    timeval_elapsed(&last_suite_started));
323 }
324
325 static void simple_test_result(struct torture_context *context, 
326                                enum torture_result res, const char *reason)
327 {
328         switch (res) {
329         case TORTURE_OK:
330                 if (reason)
331                         printf("OK: %s\n", reason);
332                 break;
333         case TORTURE_FAIL:
334                 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
335                 break;
336         case TORTURE_ERROR:
337                 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason); 
338                 break;
339         case TORTURE_SKIP:
340                 printf("SKIP: %s - %s\n", context->active_test->name, reason);
341                 break;
342         }
343 }
344
345 static void simple_comment(struct torture_context *test, 
346                            const char *comment)
347 {
348         printf("%s", comment);
349 }
350
351 static void simple_warning(struct torture_context *test, 
352                            const char *comment)
353 {
354         fprintf(stderr, "WARNING: %s\n", comment);
355 }
356
357 const static struct torture_ui_ops std_ui_ops = {
358         .comment = simple_comment,
359         .warning = simple_warning,
360         .suite_start = simple_suite_start,
361         .suite_finish = simple_suite_finish,
362         .test_result = simple_test_result
363 };
364
365
366 static void run_shell(struct torture_context *tctx)
367 {
368         char *cline;
369         int argc;
370         const char **argv;
371         int ret;
372
373         while (1) {
374                 cline = smb_readline("torture> ", NULL, NULL);
375
376                 if (cline == NULL)
377                         return;
378         
379                 ret = poptParseArgvString(cline, &argc, &argv);
380                 if (ret != 0) {
381                         fprintf(stderr, "Error parsing line\n");
382                         continue;
383                 }
384
385                 if (!strcmp(argv[0], "quit")) {
386                         return;
387                 } else if (!strcmp(argv[0], "set")) {
388                         if (argc < 3) {
389                                 fprintf(stderr, "Usage: set <variable> <value>\n");
390                         } else {
391                                 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
392                                 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
393                                 talloc_free(name);
394                         }
395                 } else if (!strcmp(argv[0], "help")) {
396                         fprintf(stderr, "Available commands:\n"
397                                                         " help - This help command\n"
398                                                         " run - Run test\n"
399                                                         " set - Change variables\n"
400                                                         "\n");
401                 } else if (!strcmp(argv[0], "run")) {
402                         if (argc < 2) {
403                                 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
404                         } else {
405                                 run_test(tctx, argv[1]);
406                         }
407                 }
408                 free(cline);
409         }
410 }
411
412 /****************************************************************************
413   main program
414 ****************************************************************************/
415 int main(int argc,char *argv[])
416 {
417         int opt, i;
418         bool correct = true;
419         int max_runtime=0;
420         int argc_new;
421         struct torture_context *torture;
422         struct torture_results *results;
423         const struct torture_ui_ops *ui_ops;
424         char **argv_new;
425         poptContext pc;
426         static const char *target = "other";
427         NTSTATUS status;
428         int shell = false;
429         static const char *ui_ops_name = "subunit";
430         const char *basedir = NULL;
431         const char *extra_module = NULL;
432         static int list_tests = 0;
433         int num_extra_users = 0;
434         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
435               OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
436               OPT_EXTRA_USER,};
437
438         struct poptOption long_options[] = {
439                 POPT_AUTOHELP
440                 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
441                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
442                 {"basedir",       0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
443                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "Seed to use for randomizer",   NULL},
444                 {"num-progs",     0, POPT_ARG_INT,  NULL,       OPT_NUMPROGS,   "num progs",    NULL},
445                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
446                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
447                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "NBench load file to use",      NULL},
448                 {"list",          0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
449                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
450                 {"timelimit",   't', POPT_ARG_INT,      NULL,   OPT_TIMELIMIT,  "Set time limit (in seconds)",  NULL},
451                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
452                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
453                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,
454                  "run dangerous tests (eg. wiping out password database)", NULL},
455                 {"load-module",  0,  POPT_ARG_STRING, &extra_module,     0, "load tests from DSO file",    "SOFILE"},
456                 {"shell",               0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
457                 {"target",              'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
458                 {"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
459                  "run async tests", NULL},
460                 {"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
461                  "number of simultaneous async requests", NULL},
462                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
463                  "set maximum time for smbtorture to live", "seconds"},
464                 {"extra-user",   0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
465                  "extra user credentials", NULL},
466                 POPT_COMMON_SAMBA
467                 POPT_COMMON_CONNECTION
468                 POPT_COMMON_CREDENTIALS
469                 POPT_COMMON_VERSION
470                 { NULL }
471         };
472
473         setlinebuf(stdout);
474
475         /* we are never interested in SIGPIPE */
476         BlockSignals(true, SIGPIPE);
477
478         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
479                             POPT_CONTEXT_KEEP_FIRST);
480
481         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
482
483         while((opt = poptGetNextOpt(pc)) != -1) {
484                 switch (opt) {
485                 case OPT_LOADFILE:
486                         lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
487                         break;
488                 case OPT_UNCLIST:
489                         lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
490                         break;
491                 case OPT_TIMELIMIT:
492                         lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
493                         break;
494                 case OPT_NUMPROGS:
495                         lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
496                         break;
497                 case OPT_DNS:
498                         parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
499                         break;
500                 case OPT_DANGEROUS:
501                         lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
502                         break;
503                 case OPT_ASYNC:
504                         lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
505                         break;
506                 case OPT_SMB_PORTS:
507                         lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
508                         break;
509                 case OPT_EXTRA_USER:
510                         {
511                                 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
512                                                                ++num_extra_users);
513                                 const char *value = poptGetOptArg(pc);
514                                 lp_set_cmdline(cmdline_lp_ctx, option, value);
515                                 talloc_free(option);
516                         }
517                         break;
518                 default:
519                         printf("bad command line option\n");
520                         exit(1);
521                 }
522         }
523
524         if (strcmp(target, "samba3") == 0) {
525                 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
526         } else if (strcmp(target, "samba4") == 0) {
527                 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
528         } else if (strcmp(target, "w2k8") == 0) {
529                 lp_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
530                 lp_set_cmdline(cmdline_lp_ctx,
531                     "torture:invalid_lock_range_support", "false");
532         } else if (strcmp(target, "win7") == 0) {
533                 lp_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
534                 lp_set_cmdline(cmdline_lp_ctx, "torture:cn_max_buffer_size",
535                      "0x00010000");
536         } else if (strcmp(target, "onefs") == 0) {
537                 lp_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
538         }
539
540         if (max_runtime) {
541                 /* this will only work if nobody else uses alarm(),
542                    which means it won't work for some tests, but we
543                    can't use the event context method we use for smbd
544                    as so many tests create their own event
545                    context. This will at least catch most cases. */
546                 signal(SIGALRM, max_runtime_handler);
547                 alarm(max_runtime);
548         }
549
550         if (extra_module != NULL) {
551             init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
552
553             if (fn == NULL) 
554                 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
555             else {
556                 status = fn();
557                 if (NT_STATUS_IS_ERR(status)) {
558                     d_printf("Error initializing module %s: %s\n", 
559                              poptGetOptArg(pc), nt_errstr(status));
560                 }
561             }
562         } else { 
563                 torture_init();
564         }
565
566         if (list_tests) {
567                 print_test_list();
568                 return 0;
569         }
570
571         if (torture_seed == 0) {
572                 torture_seed = time(NULL);
573         } 
574         printf("Using seed %d\n", torture_seed);
575         srandom(torture_seed);
576
577         argv_new = discard_const_p(char *, poptGetArgs(pc));
578
579         argc_new = argc;
580         for (i=0; i<argc; i++) {
581                 if (argv_new[i] == NULL) {
582                         argc_new = i;
583                         break;
584                 }
585         }
586
587         if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
588                 usage(pc);
589                 exit(1);
590         }
591
592         if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
593                 usage(pc);
594                 exit(1);
595         }
596
597         if (!strcmp(ui_ops_name, "simple")) {
598                 ui_ops = &std_ui_ops;
599         } else if (!strcmp(ui_ops_name, "subunit")) {
600                 ui_ops = &torture_subunit_ui_ops;
601         } else {
602                 printf("Unknown output format '%s'\n", ui_ops_name);
603                 exit(1);
604         }
605
606         results = torture_results_init(talloc_autofree_context(), ui_ops);
607
608         torture = torture_context_init(s4_event_context_init(NULL), results);
609         if (basedir != NULL) {
610                 if (basedir[0] != '/') {
611                         fprintf(stderr, "Please specify an absolute path to --basedir\n");
612                         return 1;
613                 }
614                 torture->outputdir = basedir;
615         } else {
616                 char *pwd = talloc_size(torture, PATH_MAX);
617                 if (!getcwd(pwd, PATH_MAX)) {
618                         fprintf(stderr, "Unable to determine current working directory\n");
619                         return 1;
620                 }
621                 torture->outputdir = pwd;
622         }
623
624         torture->lp_ctx = cmdline_lp_ctx;
625
626         gensec_init(cmdline_lp_ctx);
627
628         if (argc_new == 0) {
629                 printf("You must specify a test to run, or 'ALL'\n");
630         } else if (shell) {
631                 run_shell(torture);
632         } else {
633                 for (i=2;i<argc_new;i++) {
634                         if (!run_test(torture, argv_new[i])) {
635                                 correct = false;
636                         }
637                 }
638         }
639
640         if (torture->results->returncode && correct) {
641                 return(0);
642         } else {
643                 return(1);
644         }
645 }