added some of the new SMB2 create tags to gentest_smb2
[kai/samba.git] / source4 / torture / gentest_smb2.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    generic testing tool - version with SMB2 support
5
6    Copyright (C) Andrew Tridgell 2003-2008
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "lib/events/events.h"
25 #include "system/time.h"
26 #include "system/filesys.h"
27 #include "libcli/raw/request.h"
28 #include "libcli/libcli.h"
29 #include "libcli/raw/libcliraw.h"
30 #include "libcli/smb2/smb2.h"
31 #include "libcli/smb2/smb2_calls.h"
32 #include "librpc/gen_ndr/security.h"
33 #include "auth/credentials/credentials.h"
34 #include "libcli/resolve/resolve.h"
35 #include "auth/gensec/gensec.h"
36 #include "param/param.h"
37 #include "dynconfig/dynconfig.h"
38
39 #define NSERVERS 2
40 #define NINSTANCES 2
41
42 /* global options */
43 static struct gentest_options {
44         int showall;
45         int analyze;
46         int analyze_always;
47         int analyze_continuous;
48         uint_t max_open_handles;
49         uint_t seed;
50         uint_t numops;
51         int use_oplocks;
52         char **ignore_patterns;
53         const char *seeds_file;
54         int use_preset_seeds;
55         int fast_reconnect;
56         int mask_indexing;
57         int no_eas;
58         int skip_cleanup;
59         int valid;
60 } options;
61
62 /* mapping between open handles on the server and local handles */
63 static struct {
64         bool active;
65         uint_t instance;
66         struct smb2_handle server_handle[NSERVERS];
67         const char *name;
68 } *open_handles;
69 static uint_t num_open_handles;
70
71 /* state information for the servers. We open NINSTANCES connections to
72    each server */
73 static struct {
74         struct smb2_tree *tree[NINSTANCES];
75         char *server_name;
76         char *share_name;
77         struct cli_credentials *credentials;
78 } servers[NSERVERS];
79
80 /* the seeds and flags for each operation */
81 static struct {
82         uint_t seed;
83         bool disabled;
84 } *op_parms;
85
86
87 /* oplock break info */
88 static struct {
89         bool got_break;
90         struct smb2_handle server_handle;
91         uint16_t handle;
92         uint8_t level;
93         bool do_close;
94 } oplocks[NSERVERS][NINSTANCES];
95
96 /* change notify reply info */
97 static struct {
98         int notify_count;
99         NTSTATUS status;
100         union smb_notify notify;
101 } notifies[NSERVERS][NINSTANCES];
102
103 /* info relevant to the current operation */
104 static struct {
105         const char *name;
106         uint_t seed;
107         NTSTATUS status;
108         uint_t opnum;
109         TALLOC_CTX *mem_ctx;
110 } current_op;
111
112 static struct smb2_handle bad_smb2_handle;
113
114
115 #define BAD_HANDLE 0xFFFE
116
117 static bool oplock_handler(struct smb2_transport *transport, const struct smb2_handle *handle,
118                            uint8_t level, void *private_data);
119 static void idle_func(struct smb2_transport *transport, void *private);
120
121 /*
122   check if a string should be ignored. This is used as the basis
123   for all error ignore settings
124 */
125 static bool ignore_pattern(const char *str)
126 {
127         int i;
128         if (!options.ignore_patterns) return false;
129
130         for (i=0;options.ignore_patterns[i];i++) {
131                 if (strcmp(options.ignore_patterns[i], str) == 0 ||
132                     gen_fnmatch(options.ignore_patterns[i], str) == 0) {
133                         DEBUG(2,("Ignoring '%s'\n", str));
134                         return true;
135                 }
136         }
137         return false;
138 }
139
140 /***************************************************** 
141 connect to the servers
142 *******************************************************/
143 static bool connect_servers_fast(void)
144 {
145         int h, i;
146
147         /* close all open files */
148         for (h=0;h<options.max_open_handles;h++) {
149                 if (!open_handles[h].active) continue;
150                 for (i=0;i<NSERVERS;i++) {
151                         NTSTATUS status = smb2_util_close(servers[i].tree[open_handles[h].instance],
152                                                           open_handles[h].server_handle[i]);
153                         if (NT_STATUS_IS_ERR(status)) {
154                                 return false;
155                         }
156                         open_handles[h].active = false;
157                 }
158         }
159
160         return true;
161 }
162
163
164
165
166 /***************************************************** 
167 connect to the servers
168 *******************************************************/
169 static bool connect_servers(struct event_context *ev,
170                             struct loadparm_context *lp_ctx)
171 {
172         int i, j;
173
174         if (options.fast_reconnect && servers[0].tree[0]) {
175                 if (connect_servers_fast()) {
176                         return true;
177                 }
178         }
179
180         /* close any existing connections */
181         for (i=0;i<NSERVERS;i++) {
182                 for (j=0;j<NINSTANCES;j++) {
183                         if (servers[i].tree[j]) {
184                                 smb2_tdis(servers[i].tree[j]);
185                                 talloc_free(servers[i].tree[j]);
186                                 servers[i].tree[j] = NULL;
187                         }
188                 }
189         }
190
191         for (i=0;i<NSERVERS;i++) {
192                 for (j=0;j<NINSTANCES;j++) {
193                         NTSTATUS status;
194                         printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
195                                servers[i].server_name, servers[i].share_name, 
196                                servers[i].credentials->username, j);
197
198                         cli_credentials_set_workstation(servers[i].credentials, 
199                                                         "gentest", CRED_SPECIFIED);
200
201                         status = smb2_connect(NULL, servers[i].server_name, 
202                                               servers[i].share_name,
203                                               lp_resolve_context(lp_ctx),
204                                               servers[i].credentials,
205                                               &servers[i].tree[j],
206                                               ev);
207                         if (!NT_STATUS_IS_OK(status)) {
208                                 printf("Failed to connect to \\\\%s\\%s - %s\n",
209                                        servers[i].server_name, servers[i].share_name,
210                                        nt_errstr(status));
211                                 return false;
212                         }
213
214                         servers[i].tree[j]->session->transport->oplock.handler = oplock_handler;
215                         servers[i].tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j);
216                         smb2_transport_idle_handler(servers[i].tree[j]->session->transport, idle_func, 50000, NULL);
217                 }
218         }
219
220         return true;
221 }
222
223 /*
224   work out the time skew between the servers - be conservative
225 */
226 static uint_t time_skew(void)
227 {
228         uint_t ret;
229         ret = labs(servers[0].tree[0]->session->transport->negotiate.system_time -
230                   servers[1].tree[0]->session->transport->negotiate.system_time);
231         return ret + 300;
232 }
233
234
235 static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2)
236 {
237         return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0;
238 }
239
240 /*
241   turn a server handle into a local handle
242 */
243 static uint_t fnum_to_handle(int server, int instance, struct smb2_handle server_handle)
244 {
245         uint_t i;
246         for (i=0;i<options.max_open_handles;i++) {
247                 if (!open_handles[i].active ||
248                     instance != open_handles[i].instance) continue;
249                 if (smb2_handle_equal(&open_handles[i].server_handle[server], &server_handle)) {
250                         return i;
251                 }
252         }
253         printf("Invalid server handle in fnum_to_handle on server %d instance %d\n", 
254                server, instance);
255         return BAD_HANDLE;
256 }
257
258 /*
259   add some newly opened handles
260 */
261 static void gen_add_handle(int instance, const char *name, struct smb2_handle handles[NSERVERS])
262 {
263         int i, h;
264         for (h=0;h<options.max_open_handles;h++) {
265                 if (!open_handles[h].active) break;
266         }
267         if (h == options.max_open_handles) {
268                 /* we have to force close a random handle */
269                 h = random() % options.max_open_handles;
270                 for (i=0;i<NSERVERS;i++) {
271                         NTSTATUS status;
272                         status = smb2_util_close(servers[i].tree[open_handles[h].instance], 
273                                                  open_handles[h].server_handle[i]);
274                         if (NT_STATUS_IS_ERR(status)) {
275                                 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
276                                        nt_errstr(status));
277                         }
278                 }
279                 printf("Recovered handle %d\n", h);
280                 num_open_handles--;
281         }
282         for (i=0;i<NSERVERS;i++) {
283                 open_handles[h].server_handle[i] = handles[i];
284                 open_handles[h].instance = instance;
285                 open_handles[h].active = true;
286                 open_handles[h].name = name;
287         }
288         num_open_handles++;
289
290         printf("OPEN num_open_handles=%d h=%d (%s)\n", 
291                num_open_handles, h, name);
292 }
293
294 /*
295   remove a closed handle
296 */
297 static void gen_remove_handle(int instance, struct smb2_handle handles[NSERVERS])
298 {
299         int h;
300         for (h=0;h<options.max_open_handles;h++) {
301                 if (instance == open_handles[h].instance &&
302                     smb2_handle_equal(&open_handles[h].server_handle[0], &handles[0])) {
303                         open_handles[h].active = false;                 
304                         num_open_handles--;
305                         printf("CLOSE num_open_handles=%d h=%d (%s)\n", 
306                                num_open_handles, h, 
307                                open_handles[h].name);
308                         return;
309                 }
310         }
311         printf("Removing invalid handle!?\n");
312         exit(1);
313 }
314
315 /*
316   return true with 'chance' probability as a percentage
317 */
318 static bool gen_chance(uint_t chance)
319 {
320         return ((random() % 100) <= chance);
321 }
322
323 /*
324   map an internal handle number to a server handle
325 */
326 static struct smb2_handle gen_lookup_handle(int server, uint16_t handle)
327 {
328         if (handle == BAD_HANDLE) return bad_smb2_handle;
329         return open_handles[handle].server_handle[server];
330 }
331
332 /*
333   return a file handle
334 */
335 static uint16_t gen_fnum(int instance)
336 {
337         uint16_t h;
338         int count = 0;
339
340         if (gen_chance(20)) return BAD_HANDLE;
341
342         while (num_open_handles > 0 && count++ < 10*options.max_open_handles) {
343                 h = random() % options.max_open_handles;
344                 if (open_handles[h].active && 
345                     open_handles[h].instance == instance) {
346                         return h;
347                 }
348         }
349         return BAD_HANDLE;
350 }
351
352 /*
353   return a file handle, but skewed so we don't close the last
354   couple of handles too readily
355 */
356 static uint16_t gen_fnum_close(int instance)
357 {
358         if (num_open_handles < 5) {
359                 if (gen_chance(90)) return BAD_HANDLE;
360         }
361
362         return gen_fnum(instance);
363 }
364
365 /*
366   generate an integer in a specified range
367 */
368 static int gen_int_range(uint64_t min, uint64_t max)
369 {
370         uint_t r = random();
371         return min + (r % (1+max-min));
372 }
373
374 /*
375   return a fnum for use as a root fid
376   be careful to call GEN_SET_FNUM() when you use this!
377 */
378 static uint16_t gen_root_fid(int instance)
379 {
380         if (gen_chance(5)) return gen_fnum(instance);
381         return 0;
382 }
383
384 /*
385   generate a file offset
386 */
387 static int gen_offset(void)
388 {
389         if (gen_chance(20)) return 0;
390 //      if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
391         return gen_int_range(0, 1024*1024);
392 }
393
394 /*
395   generate a io count
396 */
397 static int gen_io_count(void)
398 {
399         if (gen_chance(20)) return 0;
400 //      if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
401         return gen_int_range(0, 4096);
402 }
403
404 /*
405   generate a filename
406 */
407 static const char *gen_fname(void)
408 {
409         const char *names[] = {"gentest\\gentest.dat", 
410                                "gentest\\foo", 
411                                "gentest\\foo2.sym", 
412                                "gentest\\foo3.dll", 
413                                "gentest\\foo4", 
414                                "gentest\\foo4:teststream1", 
415                                "gentest\\foo4:teststream2", 
416                                "gentest\\foo5.exe", 
417                                "gentest\\foo5.exe:teststream3", 
418                                "gentest\\foo5.exe:teststream4", 
419                                "gentest\\foo6.com", 
420                                "gentest\\blah", 
421                                "gentest\\blah\\blergh.txt", 
422                                "gentest\\blah\\blergh2", 
423                                "gentest\\blah\\blergh3.txt", 
424                                "gentest\\blah\\blergh4", 
425                                "gentest\\blah\\blergh5.txt", 
426                                "gentest\\blah\\blergh5", 
427                                "gentest\\blah\\.", 
428 #if 0
429                                /* this causes problem with w2k3 */
430                                "gentest\\blah\\..", 
431 #endif
432                                "gentest\\a_very_long_name.bin", 
433                                "gentest\\x.y", 
434                                "gentest\\blah"};
435         int i;
436
437         do {
438                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
439         } while (ignore_pattern(names[i]));
440
441         return names[i];
442 }
443
444 /*
445   generate a filename with a higher chance of choosing an already 
446   open file
447 */
448 static const char *gen_fname_open(int instance)
449 {
450         uint16_t h;
451         h = gen_fnum(instance);
452         if (h == BAD_HANDLE) {
453                 return gen_fname();
454         }
455         return open_handles[h].name;
456 }
457
458 /*
459   generate a wildcard pattern
460 */
461 static const char *gen_pattern(void)
462 {
463         int i;
464         const char *names[] = {"gentest\\*.dat", 
465                                "gentest\\*", 
466                                "gentest\\*.*", 
467                                "gentest\\blah\\*.*", 
468                                "gentest\\blah\\*", 
469                                "gentest\\?"};
470
471         if (gen_chance(50)) return gen_fname();
472
473         do {
474                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
475         } while (ignore_pattern(names[i]));
476
477         return names[i];
478 }
479
480 static uint32_t gen_bits_levels(int nlevels, ...)
481 {
482         va_list ap;
483         uint32_t pct;
484         uint32_t mask;
485         int i;
486         va_start(ap, nlevels);
487         for (i=0;i<nlevels;i++) {
488                 pct = va_arg(ap, uint32_t);
489                 mask = va_arg(ap, uint32_t);
490                 if (pct == 100 || gen_chance(pct)) {
491                         va_end(ap);
492                         return mask & random();
493                 }
494         }
495         va_end(ap);
496         return 0;
497 }
498
499 /*
500   generate a bitmask
501 */
502 static uint32_t gen_bits_mask(uint_t mask)
503 {
504         uint_t ret = random();
505         return ret & mask;
506 }
507
508 /*
509   generate a bitmask with high probability of the first mask
510   and low of the second
511 */
512 static uint32_t gen_bits_mask2(uint32_t mask1, uint32_t mask2)
513 {
514         if (!options.valid && gen_chance(10)) return gen_bits_mask(mask2);
515         return gen_bits_mask(mask1);
516 }
517
518 /*
519   generate reserved values
520  */
521 static uint64_t gen_reserved8(void)
522 {
523         if (options.valid) return 0;
524         return gen_bits_mask(0xFF);
525 }
526
527 static uint64_t gen_reserved16(void)
528 {
529         if (options.valid) return 0;
530         return gen_bits_mask(0xFFFF);
531 }
532
533 static uint64_t gen_reserved32(void)
534 {
535         if (options.valid) return 0;
536         return gen_bits_mask(0xFFFFFFFF);
537 }
538
539 static uint64_t gen_reserved64(void)
540 {
541         if (options.valid) return 0;
542         return gen_bits_mask(0xFFFFFFFF) | (((uint64_t)gen_bits_mask(0xFFFFFFFF))<<32);
543 }
544
545
546
547 /*
548   generate a boolean
549 */
550 static bool gen_bool(void)
551 {
552         return gen_bits_mask2(0x1, 0xFF);
553 }
554
555 /*
556   return a set of lock flags
557 */
558 static uint16_t gen_lock_flags(void)
559 {
560         if (!options.valid && gen_chance(5))  return gen_bits_mask(0xFFFF);
561         if (gen_chance(20)) return gen_bits_mask(0x1F);
562         if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK;
563         return gen_bits_mask(SMB2_LOCK_FLAG_SHARED | 
564                              SMB2_LOCK_FLAG_EXCLUSIVE | 
565                              SMB2_LOCK_FLAG_FAIL_IMMEDIATELY);
566 }
567
568 /*
569   generate a lock count
570 */
571 static off_t gen_lock_count(void)
572 {
573         return gen_int_range(0, 3);
574 }
575
576 /*
577   generate a NT access mask
578 */
579 static uint32_t gen_access_mask(void)
580 {
581         uint32_t ret;
582         if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED;
583         if (gen_chance(70)) return SEC_FILE_ALL;
584         ret = gen_bits_mask(0xFFFFFFFF);
585         if (options.valid) ret &= ~SEC_MASK_INVALID;
586         return ret;
587 }
588
589 /*
590   generate a ntcreatex create options bitfield
591 */
592 static uint32_t gen_create_options(void)
593 {
594         if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
595         if (gen_chance(50)) return 0;
596         return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE | NTCREATEX_OPTIONS_DIRECTORY);
597 }
598
599 /*
600   generate a ntcreatex open disposition
601 */
602 static uint32_t gen_open_disp(void)
603 {
604         if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF;
605         if (!options.valid && gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
606         return gen_int_range(0, 5);
607 }
608
609 /*
610   generate a file attrib combination
611 */
612 static uint32_t gen_attrib(void)
613 {
614         uint32_t ret;
615         if (gen_chance(20)) {
616                 ret = gen_bits_mask(0xFFFFFFFF);
617                 if (options.valid) ret &= FILE_ATTRIBUTE_ALL_MASK;
618                 return ret;
619         }
620         return gen_bits_mask(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
621 }
622
623 /*
624   generate a unix timestamp
625 */
626 static time_t gen_timet(void)
627 {
628         if (gen_chance(30)) return 0;
629         return (time_t)random();
630 }
631
632 /*
633   generate a timestamp
634 */
635 static NTTIME gen_nttime(void)
636 {
637         NTTIME ret;
638         unix_to_nt_time(&ret, gen_timet());
639         return ret;
640 }
641
642 /*
643   generate a timewarp value
644 */
645 static NTTIME gen_timewarp(void)
646 {
647         NTTIME ret = gen_nttime();
648         if (gen_chance(98)) ret = 0;
649         return ret;
650 }
651
652 /*
653   generate a file allocation size
654 */
655 static uint_t gen_alloc_size(void)
656 {
657         uint_t ret;
658
659         if (gen_chance(30)) return 0;
660
661         ret = random() % 4*1024*1024;
662         /* give a high chance of a round number */
663         if (gen_chance(60)) {
664                 ret &= ~(1024*1024 - 1);
665         }
666         return ret;
667 }
668
669 /*
670   generate an ea_struct
671 */
672 static struct ea_struct gen_ea_struct(void)
673 {
674         struct ea_struct ea;
675         const char *names[] = {"EAONE", 
676                                "", 
677                                "FOO!", 
678                                " WITH SPACES ", 
679                                ".", 
680                                "AVERYLONGATTRIBUTENAME"};
681         const char *values[] = {"VALUE1", 
682                                "", 
683                                "NOT MUCH FOO", 
684                                " LEADING SPACES ", 
685                                ":", 
686                                "ASOMEWHATLONGERATTRIBUTEVALUE"};
687         int i;
688
689         ZERO_STRUCT(ea);
690
691         do {
692                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
693         } while (ignore_pattern(names[i]));
694
695         ea.name.s = names[i];
696
697         do {
698                 i = gen_int_range(0, ARRAY_SIZE(values)-1);
699         } while (ignore_pattern(values[i]));
700
701         ea.value = data_blob(values[i], strlen(values[i]));
702
703         if (gen_chance(10)) ea.flags = gen_bits_mask(0xFF);
704         ea.flags = 0;
705
706         return ea;
707 }
708
709 /*
710   generate an ea_struct
711 */
712 static struct smb_ea_list gen_ea_list(void)
713 {
714         struct smb_ea_list eas;
715         int i;
716         if (options.no_eas) {
717                 ZERO_STRUCT(eas);
718                 return eas;
719         }
720         eas.num_eas = gen_int_range(0, 3);
721         eas.eas = talloc_array(current_op.mem_ctx, struct ea_struct, eas.num_eas);
722         for (i=0;i<eas.num_eas;i++) {
723                 eas.eas[i] = gen_ea_struct();
724         }
725         return eas;
726 }
727
728 static void oplock_handler_close_recv(struct smb2_request *req)
729 {
730         NTSTATUS status;
731         struct smb2_close io;
732         status = smb2_close_recv(req, &io);
733         if (!NT_STATUS_IS_OK(status)) {
734                 printf("close failed in oplock_handler\n");
735                 smb_panic("close failed in oplock_handler");
736         }
737 }
738
739 static void oplock_handler_ack_callback(struct smb2_request *req)
740 {
741         NTSTATUS status;
742         struct smb2_break br;
743
744         status = smb2_break_recv(req, &br);
745         if (!NT_STATUS_IS_OK(status)) {
746                 printf("oplock break ack failed in oplock_handler\n");
747                 smb_panic("oplock break ack failed in oplock_handler");
748         }
749 }
750
751 static bool send_oplock_ack(struct smb2_tree *tree, struct smb2_handle handle, 
752                             uint8_t level)
753 {
754         struct smb2_break br;
755         struct smb2_request *req;
756
757         ZERO_STRUCT(br);
758         br.in.file.handle       = handle;
759         br.in.oplock_level      = level;
760         br.in.reserved          = gen_reserved8();
761         br.in.reserved2         = gen_reserved32();
762
763         req = smb2_break_send(tree, &br);
764         if (req == NULL) return false;
765         req->async.fn = oplock_handler_ack_callback;
766         req->async.private_data = NULL;
767         return true;
768 }
769
770 /*
771   the oplock handler will either ack the break or close the file
772 */
773 static bool oplock_handler(struct smb2_transport *transport, const struct smb2_handle *handle, 
774                            uint8_t level, void *private_data)
775 {
776         struct smb2_close io;
777         unsigned i, j;
778         bool do_close;
779         struct smb2_tree *tree = NULL;
780         struct smb2_request *req;
781
782         srandom(current_op.seed);
783         do_close = gen_chance(50);
784
785         i = ((uintptr_t)private_data) >> 8;
786         j = ((uintptr_t)private_data) & 0xFF;
787
788         if (i >= NSERVERS || j >= NINSTANCES) {
789                 printf("Bad private_data in oplock_handler\n");
790                 return false;
791         }
792
793         oplocks[i][j].got_break = true;
794         oplocks[i][j].server_handle = *handle;
795         oplocks[i][j].handle = fnum_to_handle(i, j, *handle);
796         oplocks[i][j].level = level;
797         oplocks[i][j].do_close = do_close;
798         tree = talloc_get_type(servers[i].tree[j], struct smb2_tree);
799
800         if (!tree) {
801                 printf("Oplock break not for one of our trees!?\n");
802                 return false;
803         }
804
805         if (!do_close) {
806                 printf("oplock ack handle=%d\n", oplocks[i][j].handle);
807                 return send_oplock_ack(tree, *handle, level);
808         }
809
810         printf("oplock close fnum=%d\n", oplocks[i][j].handle);
811
812         ZERO_STRUCT(io);
813         io.in.file.handle = *handle;
814         io.in.flags = 0;
815         req = smb2_close_send(tree, &io);
816
817         if (req == NULL) {
818                 printf("WARNING: close failed in oplock_handler_close\n");
819                 return false;
820         }
821
822         req->async.fn = oplock_handler_close_recv;
823         req->async.private_data = NULL;
824
825         return true;
826 }
827
828
829 /*
830   the idle function tries to cope with getting an oplock break on a connection, and
831   an operation on another connection blocking until that break is acked
832   we check for operations on all transports in the idle function
833 */
834 static void idle_func(struct smb2_transport *transport, void *private)
835 {
836         int i, j;
837         for (i=0;i<NSERVERS;i++) {
838                 for (j=0;j<NINSTANCES;j++) {
839                         if (servers[i].tree[j] &&
840                             transport != servers[i].tree[j]->session->transport) {
841                                 // smb2_transport_process(servers[i].tree[j]->session->transport);
842                         }
843                 }
844         }
845
846 }
847
848
849 /*
850   compare NTSTATUS, using checking ignored patterns
851 */
852 static bool compare_status(NTSTATUS status1, NTSTATUS status2)
853 {
854         if (NT_STATUS_EQUAL(status1, status2)) return true;
855
856         /* one code being an error and the other OK is always an error */
857         if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) return false;
858
859         /* if we are ignoring one of the status codes then consider this a match */
860         if (ignore_pattern(nt_errstr(status1)) ||
861             ignore_pattern(nt_errstr(status2))) {
862                 return true;
863         }
864         return false;
865 }
866
867 #if 0
868 /*
869   check for pending packets on all connections
870 */
871 static void check_pending(void)
872 {
873         int i, j;
874
875         msleep(20);
876
877         for (j=0;j<NINSTANCES;j++) {
878                 for (i=0;i<NSERVERS;i++) {
879                         // smb2_transport_process(servers[i].tree[j]->session->transport);
880                 }
881         }       
882 }
883 #endif
884
885 /*
886   check that the same oplock breaks have been received by all instances
887 */
888 static bool check_oplocks(const char *call)
889 {
890 #if 0
891         int i, j;
892         int tries = 0;
893
894 again:
895         check_pending();
896
897         for (j=0;j<NINSTANCES;j++) {
898                 for (i=1;i<NSERVERS;i++) {
899                         if (oplocks[0][j].got_break != oplocks[i][j].got_break ||
900                             oplocks[0][j].handle != oplocks[i][j].handle ||
901                             oplocks[0][j].level != oplocks[i][j].level) {
902                                 if (tries++ < 10) goto again;
903                                 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
904                                        oplocks[0][j].got_break, 
905                                        oplocks[0][j].handle, 
906                                        oplocks[0][j].level, 
907                                        oplocks[i][j].got_break, 
908                                        oplocks[i][j].handle, 
909                                        oplocks[i][j].level);
910                                 return false;
911                         }
912                 }
913         }
914
915         /* if we got a break and closed then remove the handle */
916         for (j=0;j<NINSTANCES;j++) {
917                 if (oplocks[0][j].got_break &&
918                     oplocks[0][j].do_close) {
919                         uint16_t fnums[NSERVERS];
920                         for (i=0;i<NSERVERS;i++) {
921                                 fnums[i] = oplocks[i][j].fnum;
922                         }
923                         gen_remove_handle(j, fnums);
924                         break;
925                 }
926         }       
927 #endif
928         return true;
929 }
930
931
932 /*
933   check that the same change notify info has been received by all instances
934 */
935 static bool check_notifies(const char *call)
936 {
937 #if 0
938         int i, j;
939         int tries = 0;
940
941 again:
942         check_pending();
943
944         for (j=0;j<NINSTANCES;j++) {
945                 for (i=1;i<NSERVERS;i++) {
946                         int n;
947                         union smb_notify not1, not2;
948
949                         if (notifies[0][j].notify_count != notifies[i][j].notify_count) {
950                                 if (tries++ < 10) goto again;
951                                 printf("Notify count inconsistent %d %d\n",
952                                        notifies[0][j].notify_count,
953                                        notifies[i][j].notify_count);
954                                 return false;
955                         }
956
957                         if (notifies[0][j].notify_count == 0) continue;
958
959                         if (!NT_STATUS_EQUAL(notifies[0][j].status,
960                                              notifies[i][j].status)) {
961                                 printf("Notify status mismatch - %s - %s\n",
962                                        nt_errstr(notifies[0][j].status),
963                                        nt_errstr(notifies[i][j].status));
964                                 return false;
965                         }
966
967                         if (!NT_STATUS_IS_OK(notifies[0][j].status)) {
968                                 continue;
969                         }
970
971                         not1 = notifies[0][j].notify;
972                         not2 = notifies[i][j].notify;
973
974                         for (n=0;n<not1.nttrans.out.num_changes;n++) {
975                                 if (not1.nttrans.out.changes[n].action != 
976                                     not2.nttrans.out.changes[n].action) {
977                                         printf("Notify action %d inconsistent %d %d\n", n,
978                                                not1.nttrans.out.changes[n].action,
979                                                not2.nttrans.out.changes[n].action);
980                                         return false;
981                                 }
982                                 if (strcmp(not1.nttrans.out.changes[n].name.s,
983                                            not2.nttrans.out.changes[n].name.s)) {
984                                         printf("Notify name %d inconsistent %s %s\n", n,
985                                                not1.nttrans.out.changes[n].name.s,
986                                                not2.nttrans.out.changes[n].name.s);
987                                         return false;
988                                 }
989                                 if (not1.nttrans.out.changes[n].name.private_length !=
990                                     not2.nttrans.out.changes[n].name.private_length) {
991                                         printf("Notify name length %d inconsistent %d %d\n", n,
992                                                not1.nttrans.out.changes[n].name.private_length,
993                                                not2.nttrans.out.changes[n].name.private_length);
994                                         return false;
995                                 }
996                         }
997                 }
998         }
999
1000         ZERO_STRUCT(notifies);
1001
1002 #endif
1003         return true;
1004 }
1005
1006 #define GEN_COPY_PARM do { \
1007         int i; \
1008         for (i=1;i<NSERVERS;i++) { \
1009                 parm[i] = parm[0]; \
1010         } \
1011 } while (0)
1012
1013 #define GEN_CALL(call) do { \
1014         int i; \
1015         ZERO_STRUCT(oplocks); \
1016         ZERO_STRUCT(notifies); \
1017         for (i=0;i<NSERVERS;i++) { \
1018                 struct smb2_tree *tree = servers[i].tree[instance]; \
1019                 status[i] = call; \
1020         } \
1021         current_op.status = status[0]; \
1022         for (i=1;i<NSERVERS;i++) { \
1023                 if (!compare_status(status[i], status[0])) { \
1024                         printf("status different in %s - %s %s\n", #call, \
1025                                nt_errstr(status[0]), nt_errstr(status[i])); \
1026                         return false; \
1027                 } \
1028         } \
1029         if (!check_oplocks(#call)) return false;        \
1030         if (!check_notifies(#call)) return false;       \
1031         if (!NT_STATUS_IS_OK(status[0])) { \
1032                 return true; \
1033         } \
1034 } while(0)
1035
1036 #define ADD_HANDLE(name, field) do { \
1037         struct smb2_handle handles[NSERVERS]; \
1038         int i; \
1039         for (i=0;i<NSERVERS;i++) { \
1040                 handles[i] = parm[i].field; \
1041         } \
1042         gen_add_handle(instance, name, handles); \
1043 } while(0)
1044
1045 #define REMOVE_HANDLE(field) do { \
1046         struct smb2_handle handles[NSERVERS]; \
1047         int i; \
1048         for (i=0;i<NSERVERS;i++) { \
1049                 handles[i] = parm[i].field; \
1050         } \
1051         gen_remove_handle(instance, handles); \
1052 } while(0)
1053
1054 #define GEN_SET_FNUM(field) do { \
1055         int i; \
1056         for (i=0;i<NSERVERS;i++) { \
1057                 parm[i].field = gen_lookup_handle(i, parm[i].field.data[0]); \
1058         } \
1059 } while(0)
1060
1061 #define CHECK_EQUAL(field) do { \
1062         if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1063                 printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \
1064                        (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \
1065                 return false; \
1066         } \
1067 } while(0)
1068
1069 #define CHECK_ATTRIB(field) do { \
1070                 if (!options.mask_indexing) { \
1071                 CHECK_EQUAL(field); \
1072         } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \
1073                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1074                        (int)parm[0].field, (int)parm[1].field); \
1075                 return false; \
1076         } \
1077 } while(0)
1078
1079 #define CHECK_WSTR_EQUAL(field) do { \
1080         if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1081                 printf("%s is NULL!\n", #field); \
1082                 return false; \
1083         } \
1084         if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1085                 printf("Mismatch in %s - %s %s\n", #field, \
1086                        parm[0].field.s, parm[1].field.s); \
1087                 return false; \
1088         } \
1089         CHECK_EQUAL(field.private_length); \
1090 } while(0)
1091
1092 #define CHECK_BLOB_EQUAL(field) do { \
1093         if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
1094                 printf("Mismatch in %s\n", #field); \
1095                 return false; \
1096         } \
1097         CHECK_EQUAL(field.length); \
1098 } while(0)
1099
1100 #define CHECK_NTTIMES_EQUAL(field) do { \
1101         if (labs(nt_time_to_unix(parm[0].field) - \
1102                 nt_time_to_unix(parm[1].field)) > time_skew() && \
1103             !ignore_pattern(#field)) { \
1104                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1105                        (int)nt_time_to_unix(parm[0].field), \
1106                        (int)nt_time_to_unix(parm[1].field)); \
1107                 return false; \
1108         } \
1109 } while(0)
1110
1111 /*
1112   generate ntcreatex operations
1113 */
1114 static bool handler_create(int instance)
1115 {
1116         struct smb2_create parm[NSERVERS];
1117         NTSTATUS status[NSERVERS];
1118
1119         ZERO_STRUCT(parm[0]);
1120         parm[0].in.security_flags             = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF);
1121         parm[0].in.oplock_level               = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF);
1122         parm[0].in.impersonation_level        = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF);
1123         parm[0].in.create_flags               = gen_reserved64();
1124         parm[0].in.reserved                   = gen_reserved64();
1125         parm[0].in.desired_access             = gen_access_mask();
1126         parm[0].in.file_attributes            = gen_attrib();
1127         parm[0].in.share_access               = gen_bits_mask2(0x7, 0xFFFFFFFF);
1128         parm[0].in.create_disposition         = gen_open_disp();
1129         parm[0].in.create_options             = gen_create_options();
1130         parm[0].in.fname                      = gen_fname_open(instance);
1131         parm[0].in.eas                        = gen_ea_list();
1132         parm[0].in.alloc_size                 = gen_alloc_size();
1133         parm[0].in.durable_open               = gen_bool();
1134         parm[0].in.query_maximal_access       = gen_bool();
1135         parm[0].in.timewarp                   = gen_timewarp();
1136         parm[0].in.query_on_disk_id           = gen_bool();
1137
1138         if (!options.use_oplocks) {
1139                 /* mask out oplocks */
1140                 parm[0].in.oplock_level = 0;
1141         }
1142
1143         if (options.valid) {
1144                 parm[0].in.security_flags   &= 3;
1145                 parm[0].in.oplock_level     &= 9;
1146                 parm[0].in.impersonation_level &= 3;
1147         }
1148
1149         GEN_COPY_PARM;
1150         GEN_CALL(smb2_create(tree, current_op.mem_ctx, &parm[i]));
1151
1152         CHECK_EQUAL(out.oplock_level);
1153         CHECK_EQUAL(out.reserved);
1154         CHECK_EQUAL(out.create_action);
1155         CHECK_NTTIMES_EQUAL(out.create_time);
1156         CHECK_NTTIMES_EQUAL(out.access_time);
1157         CHECK_NTTIMES_EQUAL(out.write_time);
1158         CHECK_NTTIMES_EQUAL(out.change_time);
1159         CHECK_EQUAL(out.alloc_size);
1160         CHECK_EQUAL(out.size);
1161         CHECK_ATTRIB(out.file_attr);
1162         CHECK_EQUAL(out.reserved2);
1163         CHECK_EQUAL(out.maximal_access);
1164
1165         /* ntcreatex creates a new file handle */
1166         ADD_HANDLE(parm[0].in.fname, out.file.handle);
1167
1168         return true;
1169 }
1170
1171 /*
1172   generate close operations
1173 */
1174 static bool handler_close(int instance)
1175 {
1176         struct smb2_close parm[NSERVERS];
1177         NTSTATUS status[NSERVERS];
1178
1179         ZERO_STRUCT(parm[0]);
1180         parm[0].in.file.handle.data[0] = gen_fnum_close(instance);
1181         parm[0].in.flags               = gen_bits_mask2(0x1, 0xFFFF);
1182
1183         GEN_COPY_PARM;
1184         GEN_SET_FNUM(in.file.handle);
1185         GEN_CALL(smb2_close(tree, &parm[i]));
1186
1187         CHECK_EQUAL(out.flags);
1188         CHECK_EQUAL(out._pad);
1189         CHECK_NTTIMES_EQUAL(out.create_time);
1190         CHECK_NTTIMES_EQUAL(out.access_time);
1191         CHECK_NTTIMES_EQUAL(out.write_time);
1192         CHECK_NTTIMES_EQUAL(out.change_time);
1193         CHECK_EQUAL(out.alloc_size);
1194         CHECK_EQUAL(out.size);
1195         CHECK_ATTRIB(out.file_attr);
1196
1197         REMOVE_HANDLE(in.file.handle);
1198
1199         return true;
1200 }
1201
1202 /*
1203   generate read operations
1204 */
1205 static bool handler_read(int instance)
1206 {
1207         struct smb2_read parm[NSERVERS];
1208         NTSTATUS status[NSERVERS];
1209
1210         parm[0].in.file.handle.data[0] = gen_fnum(instance);
1211         parm[0].in.reserved    = gen_reserved8();
1212         parm[0].in.length      = gen_io_count();
1213         parm[0].in.offset      = gen_offset();
1214         parm[0].in.min_count   = gen_io_count();
1215         parm[0].in.channel     = gen_bits_mask2(0x0, 0xFFFFFFFF);
1216         parm[0].in.remaining   = gen_bits_mask2(0x0, 0xFFFFFFFF);
1217         parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF);
1218         parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF);
1219
1220         GEN_COPY_PARM;
1221         GEN_SET_FNUM(in.file.handle);
1222         GEN_CALL(smb2_read(tree, current_op.mem_ctx, &parm[i]));
1223
1224         CHECK_EQUAL(out.remaining);
1225         CHECK_EQUAL(out.reserved);
1226         CHECK_EQUAL(out.data.length);
1227
1228         return true;
1229 }
1230
1231 /*
1232   generate write operations
1233 */
1234 static bool handler_write(int instance)
1235 {
1236         struct smb2_write parm[NSERVERS];
1237         NTSTATUS status[NSERVERS];
1238
1239         parm[0].in.file.handle.data[0] = gen_fnum(instance);
1240         parm[0].in.offset = gen_offset();
1241         parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF);
1242         parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF);
1243         parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL,
1244                                             gen_io_count());
1245
1246         GEN_COPY_PARM;
1247         GEN_SET_FNUM(in.file.handle);
1248         GEN_CALL(smb2_write(tree, &parm[i]));
1249
1250         CHECK_EQUAL(out._pad);
1251         CHECK_EQUAL(out.nwritten);
1252         CHECK_EQUAL(out.unknown1);
1253
1254         return true;
1255 }
1256
1257 /*
1258   generate lockingx operations
1259 */
1260 static bool handler_lock(int instance)
1261 {
1262         struct smb2_lock parm[NSERVERS];
1263         NTSTATUS status[NSERVERS];
1264         int n;
1265
1266         parm[0].level = RAW_LOCK_LOCKX;
1267         parm[0].in.file.handle.data[0] = gen_fnum(instance);
1268         parm[0].in.lock_count = gen_lock_count();
1269         parm[0].in.reserved = gen_reserved32();
1270         
1271         parm[0].in.locks = talloc_array(current_op.mem_ctx,
1272                                         struct smb2_lock_element,
1273                                         parm[0].in.lock_count);
1274         for (n=0;n<parm[0].in.lock_count;n++) {
1275                 parm[0].in.locks[n].offset = gen_offset();
1276                 parm[0].in.locks[n].length = gen_io_count();
1277                 /* don't yet cope with async replies */
1278                 parm[0].in.locks[n].flags  = gen_lock_flags() | 
1279                         SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
1280                 parm[0].in.locks[n].reserved = gen_bits_mask2(0x0, 0xFFFFFFFF);
1281         }
1282
1283         GEN_COPY_PARM;
1284         GEN_SET_FNUM(in.file.handle);
1285         GEN_CALL(smb2_lock(tree, &parm[i]));
1286
1287         return true;
1288 }
1289
1290 /*
1291   generate flush operations
1292 */
1293 static bool handler_flush(int instance)
1294 {
1295         struct smb2_flush parm[NSERVERS];
1296         NTSTATUS status[NSERVERS];
1297
1298         ZERO_STRUCT(parm[0]);
1299         parm[0].in.file.handle.data[0] = gen_fnum(instance);
1300         parm[0].in.reserved1  = gen_reserved16();
1301         parm[0].in.reserved2  = gen_reserved32();
1302
1303         GEN_COPY_PARM;
1304         GEN_SET_FNUM(in.file.handle);
1305         GEN_CALL(smb2_flush(tree, &parm[i]));
1306
1307         CHECK_EQUAL(out.reserved);
1308
1309         return true;
1310 }
1311
1312 /*
1313   generate echo operations
1314 */
1315 static bool handler_echo(int instance)
1316 {
1317         NTSTATUS status[NSERVERS];
1318
1319         GEN_CALL(smb2_keepalive(tree->session->transport));
1320
1321         return true;
1322 }
1323
1324
1325
1326 /*
1327   generate a fileinfo query structure
1328 */
1329 static void gen_fileinfo(int instance, union smb_fileinfo *info)
1330 {
1331         int i;
1332         #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
1333         struct {
1334                 enum smb_fileinfo_level level;
1335                 const char *name;
1336         }  levels[] = {
1337                 LVL(BASIC_INFORMATION),
1338                 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
1339                 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
1340                 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION),
1341                 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
1342                 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION),
1343                 LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION),
1344         };
1345         do {
1346                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
1347         } while (ignore_pattern(levels[i].name));
1348
1349         info->generic.level = levels[i].level;
1350 }
1351
1352 /*
1353   compare returned fileinfo structures
1354 */
1355 static bool cmp_fileinfo(int instance, 
1356                          union smb_fileinfo parm[NSERVERS],
1357                          NTSTATUS status[NSERVERS])
1358 {
1359         int i;
1360
1361         switch (parm[0].generic.level) {
1362         case RAW_FILEINFO_GENERIC:
1363                 return false;
1364
1365                 /* SMB1 specific values */
1366         case RAW_FILEINFO_GETATTR:
1367         case RAW_FILEINFO_GETATTRE:
1368         case RAW_FILEINFO_STANDARD:
1369         case RAW_FILEINFO_EA_SIZE:
1370         case RAW_FILEINFO_ALL_EAS:
1371         case RAW_FILEINFO_IS_NAME_VALID:
1372         case RAW_FILEINFO_BASIC_INFO:
1373         case RAW_FILEINFO_STANDARD_INFO:
1374         case RAW_FILEINFO_EA_INFO:
1375         case RAW_FILEINFO_NAME_INFO:
1376         case RAW_FILEINFO_ALL_INFO:
1377         case RAW_FILEINFO_ALT_NAME_INFO:
1378         case RAW_FILEINFO_STREAM_INFO:
1379         case RAW_FILEINFO_COMPRESSION_INFO:
1380                 return false;
1381
1382         case RAW_FILEINFO_BASIC_INFORMATION:
1383                 CHECK_NTTIMES_EQUAL(basic_info.out.create_time);
1384                 CHECK_NTTIMES_EQUAL(basic_info.out.access_time);
1385                 CHECK_NTTIMES_EQUAL(basic_info.out.write_time);
1386                 CHECK_NTTIMES_EQUAL(basic_info.out.change_time);
1387                 CHECK_ATTRIB(basic_info.out.attrib);
1388                 break;
1389
1390         case RAW_FILEINFO_STANDARD_INFORMATION:
1391                 CHECK_EQUAL(standard_info.out.alloc_size);
1392                 CHECK_EQUAL(standard_info.out.size);
1393                 CHECK_EQUAL(standard_info.out.nlink);
1394                 CHECK_EQUAL(standard_info.out.delete_pending);
1395                 CHECK_EQUAL(standard_info.out.directory);
1396                 break;
1397
1398         case RAW_FILEINFO_EA_INFORMATION:
1399                 CHECK_EQUAL(ea_info.out.ea_size);
1400                 break;
1401
1402         case RAW_FILEINFO_NAME_INFORMATION:
1403                 CHECK_WSTR_EQUAL(name_info.out.fname);
1404                 break;
1405
1406         case RAW_FILEINFO_ALT_NAME_INFORMATION:
1407                 CHECK_WSTR_EQUAL(alt_name_info.out.fname);
1408                 break;
1409
1410         case RAW_FILEINFO_STREAM_INFORMATION:
1411                 CHECK_EQUAL(stream_info.out.num_streams);
1412                 for (i=0;i<parm[0].stream_info.out.num_streams;i++) {
1413                         CHECK_EQUAL(stream_info.out.streams[i].size);
1414                         CHECK_EQUAL(stream_info.out.streams[i].alloc_size);
1415                         CHECK_WSTR_EQUAL(stream_info.out.streams[i].stream_name);
1416                 }
1417                 break;
1418
1419         case RAW_FILEINFO_COMPRESSION_INFORMATION:
1420                 CHECK_EQUAL(compression_info.out.compressed_size);
1421                 CHECK_EQUAL(compression_info.out.format);
1422                 CHECK_EQUAL(compression_info.out.unit_shift);
1423                 CHECK_EQUAL(compression_info.out.chunk_shift);
1424                 CHECK_EQUAL(compression_info.out.cluster_shift);
1425                 break;
1426
1427         case RAW_FILEINFO_INTERNAL_INFORMATION:
1428                 CHECK_EQUAL(internal_information.out.file_id);
1429                 break;
1430
1431         case RAW_FILEINFO_ACCESS_INFORMATION:
1432                 CHECK_EQUAL(access_information.out.access_flags);
1433                 break;
1434
1435         case RAW_FILEINFO_POSITION_INFORMATION:
1436                 CHECK_EQUAL(position_information.out.position);
1437                 break;
1438
1439         case RAW_FILEINFO_MODE_INFORMATION:
1440                 CHECK_EQUAL(mode_information.out.mode);
1441                 break;
1442
1443         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
1444                 CHECK_EQUAL(alignment_information.out.alignment_requirement);
1445                 break;
1446
1447         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
1448                 CHECK_NTTIMES_EQUAL(network_open_information.out.create_time);
1449                 CHECK_NTTIMES_EQUAL(network_open_information.out.access_time);
1450                 CHECK_NTTIMES_EQUAL(network_open_information.out.write_time);
1451                 CHECK_NTTIMES_EQUAL(network_open_information.out.change_time);
1452                 CHECK_EQUAL(network_open_information.out.alloc_size);
1453                 CHECK_EQUAL(network_open_information.out.size);
1454                 CHECK_ATTRIB(network_open_information.out.attrib);
1455                 break;
1456
1457         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
1458                 CHECK_ATTRIB(attribute_tag_information.out.attrib);
1459                 CHECK_EQUAL(attribute_tag_information.out.reparse_tag);
1460                 break;
1461
1462         case RAW_FILEINFO_ALL_INFORMATION:
1463         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
1464                 CHECK_NTTIMES_EQUAL(all_info2.out.create_time);
1465                 CHECK_NTTIMES_EQUAL(all_info2.out.access_time);
1466                 CHECK_NTTIMES_EQUAL(all_info2.out.write_time);
1467                 CHECK_NTTIMES_EQUAL(all_info2.out.change_time);
1468                 CHECK_ATTRIB(all_info2.out.attrib);
1469                 CHECK_EQUAL(all_info2.out.unknown1);
1470                 CHECK_EQUAL(all_info2.out.alloc_size);
1471                 CHECK_EQUAL(all_info2.out.size);
1472                 CHECK_EQUAL(all_info2.out.nlink);
1473                 CHECK_EQUAL(all_info2.out.delete_pending);
1474                 CHECK_EQUAL(all_info2.out.directory);
1475                 CHECK_EQUAL(all_info2.out.file_id);
1476                 CHECK_EQUAL(all_info2.out.ea_size);
1477                 CHECK_EQUAL(all_info2.out.access_mask);
1478                 CHECK_EQUAL(all_info2.out.position);
1479                 CHECK_EQUAL(all_info2.out.mode);
1480                 CHECK_EQUAL(all_info2.out.alignment_requirement);
1481                 CHECK_WSTR_EQUAL(all_info2.out.fname);
1482                 break;
1483
1484         case RAW_FILEINFO_SMB2_ALL_EAS:
1485                 CHECK_EQUAL(all_eas.out.num_eas);
1486                 for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
1487                         CHECK_EQUAL(all_eas.out.eas[i].flags);
1488                         CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
1489                         CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
1490                 }
1491                 break;
1492
1493                 /* Unhandled levels */
1494
1495         case RAW_FILEINFO_SEC_DESC:
1496         case RAW_FILEINFO_EA_LIST:
1497         case RAW_FILEINFO_UNIX_BASIC:
1498         case RAW_FILEINFO_UNIX_LINK:
1499         case RAW_FILEINFO_UNIX_INFO2:
1500                 break;
1501         }
1502
1503         return true;
1504 }
1505
1506 /*
1507   generate qfileinfo operations
1508 */
1509 static bool handler_qfileinfo(int instance)
1510 {
1511         union smb_fileinfo parm[NSERVERS];
1512         NTSTATUS status[NSERVERS];
1513
1514         parm[0].generic.in.file.handle.data[0] = gen_fnum(instance);
1515
1516         gen_fileinfo(instance, &parm[0]);
1517
1518         GEN_COPY_PARM;
1519         GEN_SET_FNUM(generic.in.file.handle);
1520         GEN_CALL(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i]));
1521
1522         return cmp_fileinfo(instance, parm, status);
1523 }
1524
1525
1526 /*
1527   generate a fileinfo query structure
1528 */
1529 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
1530 {
1531         int i;
1532         #undef LVL
1533         #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
1534         struct {
1535                 enum smb_setfileinfo_level level;
1536                 const char *name;
1537         }  levels[] = {
1538                 LVL(BASIC_INFORMATION),
1539                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
1540                 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
1541                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
1542                 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
1543         };
1544         do {
1545                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
1546         } while (ignore_pattern(levels[i].name));
1547
1548         info->generic.level = levels[i].level;
1549
1550         switch (info->generic.level) {
1551         case RAW_SFILEINFO_SETATTR:
1552         case RAW_SFILEINFO_SETATTRE:
1553         case RAW_SFILEINFO_STANDARD:
1554         case RAW_SFILEINFO_EA_SET:
1555         case RAW_SFILEINFO_BASIC_INFO:
1556         case RAW_SFILEINFO_DISPOSITION_INFO:
1557         case RAW_SFILEINFO_END_OF_FILE_INFO:
1558         case RAW_SFILEINFO_ALLOCATION_INFO:
1559                 break;
1560
1561         case RAW_SFILEINFO_BASIC_INFORMATION:
1562                 info->basic_info.in.create_time = gen_nttime();
1563                 info->basic_info.in.access_time = gen_nttime();
1564                 info->basic_info.in.write_time = gen_nttime();
1565                 info->basic_info.in.change_time = gen_nttime();
1566                 info->basic_info.in.attrib = gen_attrib();
1567                 break;
1568         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
1569                 info->disposition_info.in.delete_on_close = gen_bool();
1570                 break;
1571         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
1572                 info->allocation_info.in.alloc_size = gen_alloc_size();
1573                 break;
1574         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
1575                 info->end_of_file_info.in.size = gen_offset();
1576                 break;
1577         case RAW_SFILEINFO_RENAME_INFORMATION:
1578         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
1579                 info->rename_information.in.overwrite = gen_bool();
1580                 info->rename_information.in.root_fid = gen_root_fid(instance);
1581                 info->rename_information.in.new_name = gen_fname_open(instance);
1582                 break;
1583         case RAW_SFILEINFO_POSITION_INFORMATION:
1584                 info->position_information.in.position = gen_offset();
1585                 break;
1586         case RAW_SFILEINFO_MODE_INFORMATION:
1587                 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
1588                 break;
1589         case RAW_SFILEINFO_GENERIC:
1590         case RAW_SFILEINFO_SEC_DESC:
1591         case RAW_SFILEINFO_1023:
1592         case RAW_SFILEINFO_1025:
1593         case RAW_SFILEINFO_1029:
1594         case RAW_SFILEINFO_1032:
1595         case RAW_SFILEINFO_1039:
1596         case RAW_SFILEINFO_1040:
1597         case RAW_SFILEINFO_UNIX_BASIC:
1598         case RAW_SFILEINFO_UNIX_INFO2:
1599         case RAW_SFILEINFO_UNIX_LINK:
1600         case RAW_SFILEINFO_UNIX_HLINK:
1601                 /* Untested */
1602                 break;
1603         }
1604 }
1605
1606 /*
1607   generate setfileinfo operations
1608 */
1609 static bool handler_sfileinfo(int instance)
1610 {
1611         union smb_setfileinfo parm[NSERVERS];
1612         NTSTATUS status[NSERVERS];
1613
1614         parm[0].generic.in.file.fnum = gen_fnum(instance);
1615
1616         gen_setfileinfo(instance, &parm[0]);
1617
1618         GEN_COPY_PARM;
1619         GEN_SET_FNUM(generic.in.file.handle);
1620         GEN_CALL(smb2_setinfo_file(tree, &parm[i]));
1621
1622         return true;
1623 }
1624
1625 /*
1626   wipe any relevant files
1627 */
1628 static void wipe_files(void)
1629 {
1630         int i;
1631         NTSTATUS status;
1632
1633         if (options.skip_cleanup) {
1634                 return;
1635         }
1636
1637         for (i=0;i<NSERVERS;i++) {
1638                 int n = smb2_deltree(servers[i].tree[0], "gentest");
1639                 if (n == -1) {
1640                         printf("Failed to wipe tree on server %d\n", i);
1641                         exit(1);
1642                 }
1643                 status = smb2_util_mkdir(servers[i].tree[0], "gentest");
1644                 if (NT_STATUS_IS_ERR(status)) {
1645                         printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status));
1646                         exit(1);
1647                 }
1648                 if (n > 0) {
1649                         printf("Deleted %d files on server %d\n", n, i);
1650                 }
1651         }
1652 }
1653
1654 /*
1655   dump the current seeds - useful for continuing a backtrack
1656 */
1657 static void dump_seeds(void)
1658 {
1659         int i;
1660         FILE *f;
1661
1662         if (!options.seeds_file) {
1663                 return;
1664         }
1665         f = fopen("seeds.tmp", "w");
1666         if (!f) return;
1667
1668         for (i=0;i<options.numops;i++) {
1669                 fprintf(f, "%u\n", op_parms[i].seed);
1670         }
1671         fclose(f);
1672         rename("seeds.tmp", options.seeds_file);
1673 }
1674
1675
1676
1677 /*
1678   the list of top-level operations that we will generate
1679 */
1680 static struct {
1681         const char *name;
1682         bool (*handler)(int instance);
1683         int count, success_count;
1684 } gen_ops[] = {
1685         {"CREATE",     handler_create},
1686         {"CLOSE",      handler_close},
1687         {"READ",       handler_read},
1688         {"WRITE",      handler_write},
1689         {"LOCK",       handler_lock},
1690         {"FLUSH",      handler_flush},
1691         {"ECHO",       handler_echo},
1692         {"QFILEINFO",  handler_qfileinfo},
1693         {"SFILEINFO",  handler_sfileinfo},
1694 };
1695
1696
1697 /*
1698   run the test with the current set of op_parms parameters
1699   return the number of operations that completed successfully
1700 */
1701 static int run_test(struct event_context *ev, struct loadparm_context *lp_ctx)
1702 {
1703         int op, i;
1704
1705         if (!connect_servers(ev, lp_ctx)) {
1706                 printf("Failed to connect to servers\n");
1707                 exit(1);
1708         }
1709
1710         dump_seeds();
1711
1712         /* wipe any leftover files from old runs */
1713         wipe_files();
1714
1715         /* reset the open handles array */
1716         memset(open_handles, 0, options.max_open_handles * sizeof(open_handles[0]));
1717         num_open_handles = 0;
1718
1719         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
1720                 gen_ops[i].count = 0;
1721                 gen_ops[i].success_count = 0;
1722         }
1723
1724         for (op=0; op<options.numops; op++) {
1725                 int instance, which_op;
1726                 bool ret;
1727
1728                 if (op_parms[op].disabled) continue;
1729
1730                 srandom(op_parms[op].seed);
1731
1732                 instance = gen_int_range(0, NINSTANCES-1);
1733
1734                 /* generate a non-ignored operation */
1735                 do {
1736                         which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1);
1737                 } while (ignore_pattern(gen_ops[which_op].name));
1738
1739                 DEBUG(3,("Generating op %s on instance %d\n",
1740                          gen_ops[which_op].name, instance));
1741
1742                 current_op.seed = op_parms[op].seed;
1743                 current_op.opnum = op;
1744                 current_op.name = gen_ops[which_op].name;
1745                 current_op.status = NT_STATUS_OK;
1746                 current_op.mem_ctx = talloc_named(NULL, 0, "%s", current_op.name);
1747
1748                 ret = gen_ops[which_op].handler(instance);
1749
1750                 talloc_free(current_op.mem_ctx);
1751
1752                 gen_ops[which_op].count++;
1753                 if (NT_STATUS_IS_OK(current_op.status)) {
1754                         gen_ops[which_op].success_count++;                      
1755                 }
1756
1757                 if (!ret) {
1758                         printf("Failed at operation %d - %s\n",
1759                                op, gen_ops[which_op].name);
1760                         return op;
1761                 }
1762
1763                 if (op % 100 == 0) {
1764                         printf("%d\n", op);
1765                 }
1766         }
1767
1768         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
1769                 printf("Op %-10s got %d/%d success\n", 
1770                        gen_ops[i].name,
1771                        gen_ops[i].success_count,
1772                        gen_ops[i].count);
1773         }
1774
1775         return op;
1776 }
1777
1778 /* 
1779    perform a backtracking analysis of the minimal set of operations
1780    to generate an error
1781 */
1782 static void backtrack_analyze(struct event_context *ev,
1783                               struct loadparm_context *lp_ctx)
1784 {
1785         int chunk, ret;
1786
1787         chunk = options.numops / 2;
1788
1789         do {
1790                 int base;
1791                 for (base=0; 
1792                      chunk > 0 && base+chunk < options.numops && options.numops > 1; ) {
1793                         int i, max;
1794
1795                         chunk = MIN(chunk, options.numops / 2);
1796
1797                         /* mark this range as disabled */
1798                         max = MIN(options.numops, base+chunk);
1799                         for (i=base;i<max; i++) {
1800                                 op_parms[i].disabled = true;
1801                         }
1802                         printf("Testing %d ops with %d-%d disabled\n", 
1803                                options.numops, base, max-1);
1804                         ret = run_test(ev, lp_ctx);
1805                         printf("Completed %d of %d ops\n", ret, options.numops);
1806                         for (i=base;i<max; i++) {
1807                                 op_parms[i].disabled = false;
1808                         }
1809                         if (ret == options.numops) {
1810                                 /* this chunk is needed */
1811                                 base += chunk;
1812                         } else if (ret < base) {
1813                                 printf("damn - inconsistent errors! found early error\n");
1814                                 options.numops = ret+1;
1815                                 base = 0;
1816                         } else {
1817                                 /* it failed - this chunk isn't needed for a failure */
1818                                 memmove(&op_parms[base], &op_parms[max], 
1819                                         sizeof(op_parms[0]) * (options.numops - max));
1820                                 options.numops = (ret+1) - (max - base);
1821                         }
1822                 }
1823
1824                 if (chunk == 2) {
1825                         chunk = 1;
1826                 } else {
1827                         chunk *= 0.4;
1828                 }
1829
1830                 if (options.analyze_continuous && chunk == 0 && options.numops != 1) {
1831                         chunk = 1;
1832                 }
1833         } while (chunk > 0);
1834
1835         printf("Reduced to %d ops\n", options.numops);
1836         ret = run_test(ev, lp_ctx);
1837         if (ret != options.numops - 1) {
1838                 printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops);
1839         }
1840 }
1841
1842 /* 
1843    start the main gentest process
1844 */
1845 static bool start_gentest(struct event_context *ev,
1846                           struct loadparm_context *lp_ctx)
1847 {
1848         int op;
1849         int ret;
1850
1851         /* allocate the open_handles array */
1852         open_handles = calloc(options.max_open_handles, sizeof(open_handles[0]));
1853
1854         srandom(options.seed);
1855         op_parms = calloc(options.numops, sizeof(op_parms[0]));
1856
1857         /* generate the seeds - after this everything is deterministic */
1858         if (options.use_preset_seeds) {
1859                 int numops;
1860                 char **preset = file_lines_load(options.seeds_file, &numops, NULL);
1861                 if (!preset) {
1862                         printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno));
1863                         exit(1);
1864                 }
1865                 if (numops < options.numops) {
1866                         options.numops = numops;
1867                 }
1868                 for (op=0;op<options.numops;op++) {
1869                         if (!preset[op]) {
1870                                 printf("Not enough seeds in %s\n", options.seeds_file);
1871                                 exit(1);
1872                         }
1873                         op_parms[op].seed = atoi(preset[op]);
1874                 }
1875                 printf("Loaded %d seeds from %s\n", options.numops, options.seeds_file);
1876         } else {
1877                 for (op=0; op<options.numops; op++) {
1878                         op_parms[op].seed = random();
1879                 }
1880         }
1881
1882         ret = run_test(ev, lp_ctx);
1883
1884         if (ret != options.numops && options.analyze) {
1885                 options.numops = ret+1;
1886                 backtrack_analyze(ev, lp_ctx);
1887         } else if (options.analyze_always) {
1888                 backtrack_analyze(ev, lp_ctx);
1889         } else if (options.analyze_continuous) {
1890                 while (run_test(ev, lp_ctx) == options.numops) ;
1891         }
1892
1893         return ret == options.numops;
1894 }
1895
1896
1897 static void usage(poptContext pc)
1898 {
1899         printf(
1900 "Usage:\n\
1901   gentest //server1/share1 //server2/share2 [options..]\n\
1902 ");
1903         poptPrintUsage(pc, stdout, 0);
1904 }
1905
1906 /**
1907   split a UNC name into server and share names
1908 */
1909 static bool split_unc_name(const char *unc, char **server, char **share)
1910 {
1911         char *p = strdup(unc);
1912         if (!p) return false;
1913         all_string_sub(p, "\\", "/", 0);
1914         if (strncmp(p, "//", 2) != 0) return false;
1915
1916         (*server) = p+2;
1917         p = strchr(*server, '/');
1918         if (!p) return false;
1919
1920         *p = 0;
1921         (*share) = p+1;
1922         
1923         return true;
1924 }
1925
1926
1927
1928 /****************************************************************************
1929   main program
1930 ****************************************************************************/
1931  int main(int argc, char *argv[])
1932 {
1933         int opt;
1934         int i, username_count=0;
1935         bool ret;
1936         char *ignore_file=NULL;
1937         struct event_context *ev;
1938         struct loadparm_context *lp_ctx;
1939         poptContext pc;
1940         int argc_new;
1941         char **argv_new;
1942         enum {OPT_UNCLIST=1000};
1943         struct poptOption long_options[] = {
1944                 POPT_AUTOHELP
1945                 {"seed",          0, POPT_ARG_INT,  &options.seed,      0,      "Seed to use for randomizer",   NULL},
1946                 {"num-ops",       0, POPT_ARG_INT,  &options.numops,    0,      "num ops",      NULL},
1947                 {"oplocks",       0, POPT_ARG_NONE, &options.use_oplocks,0,      "use oplocks", NULL},
1948                 {"showall",       0, POPT_ARG_NONE, &options.showall,    0,      "display all operations", NULL},
1949                 {"analyse",       0, POPT_ARG_NONE, &options.analyze,    0,      "do backtrack analysis", NULL},
1950                 {"analysealways", 0, POPT_ARG_NONE, &options.analyze_always,    0,      "analysis always", NULL},
1951                 {"analysecontinuous", 0, POPT_ARG_NONE, &options.analyze_continuous,    0,      "analysis continuous", NULL},
1952                 {"ignore",        0, POPT_ARG_STRING, &ignore_file,    0,      "ignore from file", NULL},
1953                 {"preset",        0, POPT_ARG_NONE, &options.use_preset_seeds,    0,      "use preset seeds", NULL},
1954                 {"fast",          0, POPT_ARG_NONE, &options.fast_reconnect,    0,      "use fast reconnect", NULL},
1955                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
1956                 {"seedsfile",     0, POPT_ARG_STRING,  &options.seeds_file, 0,  "seed file",    NULL},
1957                 { "user", 'U',       POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
1958                 {"maskindexing",  0, POPT_ARG_NONE,  &options.mask_indexing, 0, "mask out the indexed file attrib",     NULL},
1959                 {"noeas",  0, POPT_ARG_NONE,  &options.no_eas, 0,       "don't use extended attributes",        NULL},
1960                 {"skip-cleanup",  0, POPT_ARG_NONE,  &options.skip_cleanup, 0,  "don't delete files at start",  NULL},
1961                 {"valid",  0, POPT_ARG_NONE,  &options.valid, 0,        "generate only valid fields",   NULL},
1962                 POPT_COMMON_SAMBA
1963                 POPT_COMMON_CONNECTION
1964                 POPT_COMMON_CREDENTIALS
1965                 POPT_COMMON_VERSION
1966                 { NULL }
1967         };
1968
1969         memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle));
1970
1971         setlinebuf(stdout);
1972         options.seed = time(NULL);
1973         options.numops = 1000;
1974         options.max_open_handles = 20;
1975         options.seeds_file = "gentest_seeds.dat";
1976
1977         pc = poptGetContext("gentest", argc, (const char **) argv, long_options, 
1978                             POPT_CONTEXT_KEEP_FIRST);
1979
1980         poptSetOtherOptionHelp(pc, "<unc1> <unc2>");
1981
1982         lp_ctx = cmdline_lp_ctx;
1983         servers[0].credentials = cli_credentials_init(talloc_autofree_context());
1984         servers[1].credentials = cli_credentials_init(talloc_autofree_context());
1985         cli_credentials_guess(servers[0].credentials, lp_ctx);
1986         cli_credentials_guess(servers[1].credentials, lp_ctx);
1987
1988         while((opt = poptGetNextOpt(pc)) != -1) {
1989                 switch (opt) {
1990                 case OPT_UNCLIST:
1991                         lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
1992                         break;
1993                 case 'U':
1994                         if (username_count == 2) {
1995                                 usage(pc);
1996                                 exit(1);
1997                         }
1998                         cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED);
1999                         username_count++;
2000                         break;
2001                 }
2002         }
2003
2004         if (ignore_file) {
2005                 options.ignore_patterns = file_lines_load(ignore_file, NULL, NULL);
2006         }
2007
2008         argv_new = discard_const_p(char *, poptGetArgs(pc));
2009         argc_new = argc;
2010         for (i=0; i<argc; i++) {
2011                 if (argv_new[i] == NULL) {
2012                         argc_new = i;
2013                         break;
2014                 }
2015         }
2016
2017         if (!(argc_new >= 3)) {
2018                 usage(pc);
2019                 exit(1);
2020         }
2021
2022         setlinebuf(stdout);
2023
2024         setup_logging("gentest", DEBUG_STDOUT);
2025
2026         if (argc < 3 || argv[1][0] == '-') {
2027                 usage(pc);
2028                 exit(1);
2029         }
2030
2031         setup_logging(argv[0], DEBUG_STDOUT);
2032
2033         for (i=0;i<NSERVERS;i++) {
2034                 const char *share = argv[1+i];
2035                 if (!split_unc_name(share, &servers[i].server_name, &servers[i].share_name)) {
2036                         printf("Invalid share name '%s'\n", share);
2037                         return -1;
2038                 }
2039         }
2040
2041         if (username_count == 0) {
2042                 usage(pc);
2043                 return -1;
2044         }
2045         if (username_count == 1) {
2046                 servers[1].credentials = servers[0].credentials;
2047         }
2048
2049         printf("seed=%u\n", options.seed);
2050
2051         ev = event_context_init(talloc_autofree_context());
2052
2053         gensec_init(lp_ctx);
2054
2055         ret = start_gentest(ev, lp_ctx);
2056
2057         if (ret) {
2058                 printf("gentest completed - no errors\n");
2059         } else {
2060                 printf("gentest failed\n");
2061         }
2062
2063         return ret?0:-1;
2064 }