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