Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-defs
[kai/samba-autobuild/.git] / source / torture / gentest.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    generic testing tool - version with both SMB and 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 #include "libcli/raw/raw_proto.h"
41
42 #define NSERVERS 2
43 #define NINSTANCES 2
44
45 /* global options */
46 static struct gentest_options {
47         int showall;
48         int analyze;
49         int analyze_always;
50         int analyze_continuous;
51         uint_t max_open_handles;
52         uint_t seed;
53         uint_t numops;
54         int use_oplocks;
55         char **ignore_patterns;
56         const char *seeds_file;
57         int use_preset_seeds;
58         int fast_reconnect;
59         int mask_indexing;
60         int no_eas;
61         int no_acls;
62         int skip_cleanup;
63         int valid;
64         int smb2;
65 } options;
66
67 /* mapping between open handles on the server and local handles */
68 static struct {
69         bool active;
70         uint_t instance;
71         struct smb2_handle smb2_handle[NSERVERS]; /* SMB2 */
72         uint16_t smb_handle[NSERVERS];            /* SMB */
73         const char *name;
74 } *open_handles;
75 static uint_t num_open_handles;
76
77 /* state information for the servers. We open NINSTANCES connections to
78    each server */
79 static struct {
80         struct smb2_tree *smb2_tree[NINSTANCES];
81         struct smbcli_tree *smb_tree[NINSTANCES];
82         char *server_name;
83         char *share_name;
84         struct cli_credentials *credentials;
85 } servers[NSERVERS];
86
87 /* the seeds and flags for each operation */
88 static struct {
89         uint_t seed;
90         bool disabled;
91 } *op_parms;
92
93
94 /* oplock break info */
95 static struct {
96         bool got_break;
97         struct smb2_handle smb2_handle;
98         uint16_t smb_handle;
99         uint16_t handle;
100         uint8_t level;
101         bool do_close;
102 } oplocks[NSERVERS][NINSTANCES];
103
104 /* change notify reply info */
105 static struct {
106         int notify_count;
107         NTSTATUS status;
108         union smb_notify notify;
109 } notifies[NSERVERS][NINSTANCES];
110
111 /* info relevant to the current operation */
112 static struct {
113         const char *name;
114         uint_t seed;
115         NTSTATUS status;
116         uint_t opnum;
117         TALLOC_CTX *mem_ctx;
118         const char *mismatch;
119 } current_op;
120
121 static struct smb2_handle bad_smb2_handle;
122
123
124 #define BAD_HANDLE 0xFFFE
125
126 static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle,
127                                 uint8_t level, void *private_data);
128 static void idle_func_smb2(struct smb2_transport *transport, void *private);
129 static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private);
130 static void idle_func_smb(struct smbcli_transport *transport, void *private);
131
132 /*
133   check if a string should be ignored. This is used as the basis
134   for all error ignore settings
135 */
136 static bool ignore_pattern(const char *str)
137 {
138         int i;
139         if (!options.ignore_patterns) return false;
140
141         for (i=0;options.ignore_patterns[i];i++) {
142                 if (strcmp(options.ignore_patterns[i], str) == 0 ||
143                     gen_fnmatch(options.ignore_patterns[i], str) == 0) {
144                         DEBUG(2,("Ignoring '%s'\n", str));
145                         return true;
146                 }
147         }
148         return false;
149 }
150
151 /***************************************************** 
152 connect to the servers
153 *******************************************************/
154 static bool connect_servers_fast(void)
155 {
156         int h, i;
157
158         /* close all open files */
159         for (h=0;h<options.max_open_handles;h++) {
160                 if (!open_handles[h].active) continue;
161                 for (i=0;i<NSERVERS;i++) {
162                         NTSTATUS status;
163                         if (options.smb2) {
164                                 status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance],
165                                                          open_handles[h].smb2_handle[i]);
166                         } else {
167                                 status = smbcli_close(servers[i].smb_tree[open_handles[h].instance],
168                                                       open_handles[h].smb_handle[i]);
169                         }
170                         if (NT_STATUS_IS_ERR(status)) {
171                                 return false;
172                         }
173                         open_handles[h].active = false;
174                 }
175         }
176
177         return true;
178 }
179
180
181
182
183 /***************************************************** 
184 connect to the servers
185 *******************************************************/
186 static bool connect_servers(struct event_context *ev,
187                             struct loadparm_context *lp_ctx)
188 {
189         int i, j;
190
191         if (options.fast_reconnect && servers[0].smb2_tree[0]) {
192                 if (connect_servers_fast()) {
193                         return true;
194                 }
195         }
196
197         /* close any existing connections */
198         for (i=0;i<NSERVERS;i++) {
199                 for (j=0;j<NINSTANCES;j++) {
200                         if (servers[i].smb2_tree[j]) {
201                                 smb2_tdis(servers[i].smb2_tree[j]);
202                                 talloc_free(servers[i].smb2_tree[j]);
203                                 servers[i].smb2_tree[j] = NULL;
204                         }
205                         if (servers[i].smb_tree[j]) {
206                                 smb_tree_disconnect(servers[i].smb_tree[j]);
207                                 talloc_free(servers[i].smb_tree[j]);
208                                 servers[i].smb_tree[j] = NULL;
209                         }
210                 }
211         }
212
213         for (i=0;i<NSERVERS;i++) {
214                 for (j=0;j<NINSTANCES;j++) {
215                         NTSTATUS status;
216                         struct smbcli_options smb_options;
217                         lp_smbcli_options(lp_ctx, &smb_options);
218
219                         printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
220                                servers[i].server_name, servers[i].share_name, 
221                                servers[i].credentials->username, j);
222
223                         cli_credentials_set_workstation(servers[i].credentials, 
224                                                         "gentest", CRED_SPECIFIED);
225
226                         if (options.smb2) {
227                                 status = smb2_connect(NULL, servers[i].server_name, 
228                                                       servers[i].share_name,
229                                                       lp_resolve_context(lp_ctx),
230                                                       servers[i].credentials,
231                                                       &servers[i].smb2_tree[j],
232                                                       ev, &smb_options);
233                         } else {
234                                 status = smbcli_tree_full_connection(NULL,
235                                                                      &servers[i].smb_tree[j], 
236                                                                      servers[i].server_name, 
237                                                                      lp_smb_ports(lp_ctx),
238                                                                      servers[i].share_name, "A:",
239                                                                      servers[i].credentials,
240                                                                      lp_resolve_context(lp_ctx), ev,
241                                                                      &smb_options);
242                         }
243                         if (!NT_STATUS_IS_OK(status)) {
244                                 printf("Failed to connect to \\\\%s\\%s - %s\n",
245                                        servers[i].server_name, servers[i].share_name,
246                                        nt_errstr(status));
247                                 return false;
248                         }
249
250                         if (options.smb2) {
251                                 servers[i].smb2_tree[j]->session->transport->oplock.handler = oplock_handler_smb2;
252                                 servers[i].smb2_tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j);
253                                 smb2_transport_idle_handler(servers[i].smb2_tree[j]->session->transport, 
254                                                             idle_func_smb2, 50000, NULL);
255                         } else {
256                                 smbcli_oplock_handler(servers[i].smb_tree[j]->session->transport, oplock_handler_smb, 
257                                                       (void *)(uintptr_t)((i<<8)|j));
258                                 smbcli_transport_idle_handler(servers[i].smb_tree[j]->session->transport, idle_func_smb, 
259                                                               50000, (void *)(uintptr_t)((i<<8)|j));
260                         }
261                 }
262         }
263
264         return true;
265 }
266
267 /*
268   work out the time skew between the servers - be conservative
269 */
270 static uint_t time_skew(void)
271 {
272         uint_t ret;
273         if (options.smb2) {
274                 ret = labs(servers[0].smb2_tree[0]->session->transport->negotiate.system_time -
275                            servers[1].smb2_tree[0]->session->transport->negotiate.system_time);
276         } else {
277                 ret = labs(servers[0].smb_tree[0]->session->transport->negotiate.server_time -
278                            servers[1].smb_tree[0]->session->transport->negotiate.server_time);
279         }
280         return ret + 300;
281 }
282
283
284 static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2)
285 {
286         return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0;
287 }
288
289 /*
290   turn a server handle into a local handle
291 */
292 static uint_t fnum_to_handle_smb2(int server, int instance, struct smb2_handle server_handle)
293 {
294         uint_t i;
295         for (i=0;i<options.max_open_handles;i++) {
296                 if (!open_handles[i].active ||
297                     instance != open_handles[i].instance) continue;
298                 if (smb2_handle_equal(&open_handles[i].smb2_handle[server], &server_handle)) {
299                         return i;
300                 }
301         }
302         printf("Invalid server handle in fnum_to_handle on server %d instance %d\n", 
303                server, instance);
304         return BAD_HANDLE;
305 }
306
307 /*
308   turn a server handle into a local handle
309 */
310 static uint_t fnum_to_handle_smb(int server, int instance, uint16_t server_handle)
311 {
312         uint_t i;
313         for (i=0;i<options.max_open_handles;i++) {
314                 if (!open_handles[i].active ||
315                     instance != open_handles[i].instance) continue;
316                 if (open_handles[i].smb_handle[server] == server_handle) {
317                         return i;
318                 }
319         }
320         printf("Invalid server handle in fnum_to_handle on server %d instance %d\n", 
321                server, instance);
322         return BAD_HANDLE;
323 }
324
325 /*
326   add some newly opened handles
327 */
328 static void gen_add_handle_smb2(int instance, const char *name, struct smb2_handle handles[NSERVERS])
329 {
330         int i, h;
331         for (h=0;h<options.max_open_handles;h++) {
332                 if (!open_handles[h].active) break;
333         }
334         if (h == options.max_open_handles) {
335                 /* we have to force close a random handle */
336                 h = random() % options.max_open_handles;
337                 for (i=0;i<NSERVERS;i++) {
338                         NTSTATUS status;
339                         status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance], 
340                                                  open_handles[h].smb2_handle[i]);
341                         if (NT_STATUS_IS_ERR(status)) {
342                                 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
343                                        nt_errstr(status));
344                         }
345                 }
346                 printf("Recovered handle %d\n", h);
347                 num_open_handles--;
348         }
349         for (i=0;i<NSERVERS;i++) {
350                 open_handles[h].smb2_handle[i] = handles[i];
351                 open_handles[h].instance = instance;
352                 open_handles[h].active = true;
353                 open_handles[h].name = name;
354         }
355         num_open_handles++;
356
357         printf("OPEN num_open_handles=%d h=%d (%s)\n", 
358                num_open_handles, h, name);
359 }
360
361 /*
362   add some newly opened handles
363 */
364 static void gen_add_handle_smb(int instance, const char *name, uint16_t handles[NSERVERS])
365 {
366         int i, h;
367         for (h=0;h<options.max_open_handles;h++) {
368                 if (!open_handles[h].active) break;
369         }
370         if (h == options.max_open_handles) {
371                 /* we have to force close a random handle */
372                 h = random() % options.max_open_handles;
373                 for (i=0;i<NSERVERS;i++) {
374                         NTSTATUS status;
375                         status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], 
376                                               open_handles[h].smb_handle[i]);
377                         if (NT_STATUS_IS_ERR(status)) {
378                                 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
379                                        nt_errstr(status));
380                         }
381                 }
382                 printf("Recovered handle %d\n", h);
383                 num_open_handles--;
384         }
385         for (i=0;i<NSERVERS;i++) {
386                 open_handles[h].smb_handle[i] = handles[i];
387                 open_handles[h].instance = instance;
388                 open_handles[h].active = true;
389                 open_handles[h].name = name;
390         }
391         num_open_handles++;
392
393         printf("OPEN num_open_handles=%d h=%d (%s)\n", 
394                num_open_handles, h, name);
395 }
396
397
398 /*
399   remove a closed handle
400 */
401 static void gen_remove_handle_smb2(int instance, struct smb2_handle handles[NSERVERS])
402 {
403         int h;
404         for (h=0;h<options.max_open_handles;h++) {
405                 if (instance == open_handles[h].instance &&
406                     smb2_handle_equal(&open_handles[h].smb2_handle[0], &handles[0])) {
407                         open_handles[h].active = false;                 
408                         num_open_handles--;
409                         printf("CLOSE num_open_handles=%d h=%d (%s)\n", 
410                                num_open_handles, h, 
411                                open_handles[h].name);
412                         return;
413                 }
414         }
415         printf("Removing invalid handle!?\n");
416         exit(1);
417 }
418
419 /*
420   remove a closed handle
421 */
422 static void gen_remove_handle_smb(int instance, uint16_t handles[NSERVERS])
423 {
424         int h;
425         for (h=0;h<options.max_open_handles;h++) {
426                 if (instance == open_handles[h].instance &&
427                     open_handles[h].smb_handle[0] == handles[0]) {
428                         open_handles[h].active = false;                 
429                         num_open_handles--;
430                         printf("CLOSE num_open_handles=%d h=%d (%s)\n", 
431                                num_open_handles, h, 
432                                open_handles[h].name);
433                         return;
434                 }
435         }
436         printf("Removing invalid handle!?\n");
437         exit(1);
438 }
439
440 /*
441   return true with 'chance' probability as a percentage
442 */
443 static bool gen_chance(uint_t chance)
444 {
445         return ((random() % 100) <= chance);
446 }
447
448 /*
449   map an internal handle number to a server handle
450 */
451 static struct smb2_handle gen_lookup_handle_smb2(int server, uint16_t handle)
452 {
453         if (handle == BAD_HANDLE) return bad_smb2_handle;
454         return open_handles[handle].smb2_handle[server];
455 }
456
457 /*
458   map an internal handle number to a server handle
459 */
460 static uint16_t gen_lookup_handle_smb(int server, uint16_t handle)
461 {
462         if (handle == BAD_HANDLE) return BAD_HANDLE;
463         return open_handles[handle].smb_handle[server];
464 }
465
466 /*
467   return a file handle
468 */
469 static uint16_t gen_fnum(int instance)
470 {
471         uint16_t h;
472         int count = 0;
473
474         if (gen_chance(20)) return BAD_HANDLE;
475
476         while (num_open_handles > 0 && count++ < 10*options.max_open_handles) {
477                 h = random() % options.max_open_handles;
478                 if (open_handles[h].active && 
479                     open_handles[h].instance == instance) {
480                         return h;
481                 }
482         }
483         return BAD_HANDLE;
484 }
485
486 /*
487   return a file handle, but skewed so we don't close the last
488   couple of handles too readily
489 */
490 static uint16_t gen_fnum_close(int instance)
491 {
492         if (num_open_handles < 5) {
493                 if (gen_chance(90)) return BAD_HANDLE;
494         }
495
496         return gen_fnum(instance);
497 }
498
499 /*
500   generate an integer in a specified range
501 */
502 static int gen_int_range(uint64_t min, uint64_t max)
503 {
504         uint_t r = random();
505         return min + (r % (1+max-min));
506 }
507
508 /*
509   return a fnum for use as a root fid
510   be careful to call GEN_SET_FNUM() when you use this!
511 */
512 static uint16_t gen_root_fid(int instance)
513 {
514         if (gen_chance(5)) return gen_fnum(instance);
515         return 0;
516 }
517
518 /*
519   generate a file offset
520 */
521 static int gen_offset(void)
522 {
523         if (gen_chance(20)) return 0;
524 //      if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
525         return gen_int_range(0, 1024*1024);
526 }
527
528 /*
529   generate a io count
530 */
531 static int gen_io_count(void)
532 {
533         if (gen_chance(20)) return 0;
534 //      if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
535         return gen_int_range(0, 4096);
536 }
537
538 /*
539   generate a filename
540 */
541 static const char *gen_fname(void)
542 {
543         const char *names[] = {"gentest\\gentest.dat", 
544                                "gentest\\foo", 
545                                "gentest\\foo2.sym", 
546                                "gentest\\foo3.dll", 
547                                "gentest\\foo4", 
548                                "gentest\\foo4:teststream1", 
549                                "gentest\\foo4:teststream2", 
550                                "gentest\\foo5.exe", 
551                                "gentest\\foo5.exe:teststream3", 
552                                "gentest\\foo5.exe:teststream4", 
553                                "gentest\\foo6.com", 
554                                "gentest\\blah", 
555                                "gentest\\blah\\blergh.txt", 
556                                "gentest\\blah\\blergh2", 
557                                "gentest\\blah\\blergh3.txt", 
558                                "gentest\\blah\\blergh4", 
559                                "gentest\\blah\\blergh5.txt", 
560                                "gentest\\blah\\blergh5", 
561                                "gentest\\blah\\.", 
562                                "gentest\\blah\\..", 
563                                "gentest\\a_very_long_name.bin", 
564                                "gentest\\x.y", 
565                                "gentest\\blah"};
566         int i;
567
568         do {
569                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
570         } while (ignore_pattern(names[i]));
571
572         return names[i];
573 }
574
575 /*
576   generate a filename with a higher chance of choosing an already 
577   open file
578 */
579 static const char *gen_fname_open(int instance)
580 {
581         uint16_t h;
582         h = gen_fnum(instance);
583         if (h == BAD_HANDLE) {
584                 return gen_fname();
585         }
586         return open_handles[h].name;
587 }
588
589 /*
590   generate a wildcard pattern
591 */
592 static const char *gen_pattern(void)
593 {
594         int i;
595         const char *names[] = {"gentest\\*.dat", 
596                                "gentest\\*", 
597                                "gentest\\*.*", 
598                                "gentest\\blah\\*.*", 
599                                "gentest\\blah\\*", 
600                                "gentest\\?"};
601
602         if (gen_chance(50)) return gen_fname();
603
604         do {
605                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
606         } while (ignore_pattern(names[i]));
607
608         return names[i];
609 }
610
611 static uint32_t gen_bits_levels(int nlevels, ...)
612 {
613         va_list ap;
614         uint32_t pct;
615         uint32_t mask;
616         int i;
617         va_start(ap, nlevels);
618         for (i=0;i<nlevels;i++) {
619                 pct = va_arg(ap, uint32_t);
620                 mask = va_arg(ap, uint32_t);
621                 if (pct == 100 || gen_chance(pct)) {
622                         va_end(ap);
623                         return mask & random();
624                 }
625         }
626         va_end(ap);
627         return 0;
628 }
629
630 /*
631   generate a bitmask
632 */
633 static uint32_t gen_bits_mask(uint_t mask)
634 {
635         uint_t ret = random();
636         return ret & mask;
637 }
638
639 /*
640   generate a bitmask with high probability of the first mask
641   and low of the second
642 */
643 static uint32_t gen_bits_mask2(uint32_t mask1, uint32_t mask2)
644 {
645         if (!options.valid && gen_chance(10)) return gen_bits_mask(mask2);
646         return gen_bits_mask(mask1);
647 }
648
649 /*
650   generate reserved values
651  */
652 static uint64_t gen_reserved8(void)
653 {
654         if (options.valid) return 0;
655         return gen_bits_mask(0xFF);
656 }
657
658 static uint64_t gen_reserved16(void)
659 {
660         if (options.valid) return 0;
661         return gen_bits_mask(0xFFFF);
662 }
663
664 static uint64_t gen_reserved32(void)
665 {
666         if (options.valid) return 0;
667         return gen_bits_mask(0xFFFFFFFF);
668 }
669
670 static uint64_t gen_reserved64(void)
671 {
672         if (options.valid) return 0;
673         return gen_bits_mask(0xFFFFFFFF) | (((uint64_t)gen_bits_mask(0xFFFFFFFF))<<32);
674 }
675
676
677
678 /*
679   generate a boolean
680 */
681 static bool gen_bool(void)
682 {
683         return gen_bits_mask2(0x1, 0xFF);
684 }
685
686 /*
687   generate ntrename flags
688 */
689 static uint16_t gen_rename_flags(void)
690 {
691         if (gen_chance(30)) return RENAME_FLAG_RENAME;
692         if (gen_chance(30)) return RENAME_FLAG_HARD_LINK;
693         if (gen_chance(30)) return RENAME_FLAG_COPY;
694         return gen_bits_mask(0xFFFF);
695 }
696
697 /*
698   generate a pid 
699 */
700 static uint16_t gen_pid(void)
701 {
702         if (gen_chance(10)) return gen_bits_mask(0xFFFF);
703         return getpid();
704 }
705
706 /*
707   return a set of lock flags
708 */
709 static uint16_t gen_lock_flags_smb2(void)
710 {
711         if (!options.valid && gen_chance(5))  return gen_bits_mask(0xFFFF);
712         if (gen_chance(20)) return gen_bits_mask(0x1F);
713         if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK;
714         return gen_bits_mask(SMB2_LOCK_FLAG_SHARED | 
715                              SMB2_LOCK_FLAG_EXCLUSIVE | 
716                              SMB2_LOCK_FLAG_FAIL_IMMEDIATELY);
717 }
718
719 /*
720   generate a lock count
721 */
722 static off_t gen_lock_count(void)
723 {
724         return gen_int_range(0, 3);
725 }
726
727 /*
728   generate a NT access mask
729 */
730 static uint32_t gen_access_mask(void)
731 {
732         uint32_t ret;
733         if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED;
734         if (gen_chance(70)) return SEC_FILE_ALL;
735         ret = gen_bits_mask(0xFFFFFFFF);
736         if (options.valid) ret &= ~SEC_MASK_INVALID;
737         return ret;
738 }
739
740 /*
741   return a lockingx lock mode
742 */
743 static uint16_t gen_lock_mode(void)
744 {
745         if (!options.valid && gen_chance(5))  return gen_bits_mask(0xFFFF);
746         if (gen_chance(20)) return gen_bits_mask(0x1F);
747         return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES);
748 }
749
750 /*
751   generate a ntcreatex flags field
752 */
753 static uint32_t gen_ntcreatex_flags(void)
754 {
755         if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED;
756         return gen_bits_mask2(0x1F, 0xFFFFFFFF);
757 }
758
759 /*
760   generate a ntcreatex create options bitfield
761 */
762 static uint32_t gen_create_options(void)
763 {
764         if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
765         if (gen_chance(50)) return 0;
766         return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE | NTCREATEX_OPTIONS_DIRECTORY);
767 }
768
769 /*
770   generate a ntcreatex open disposition
771 */
772 static uint32_t gen_open_disp(void)
773 {
774         if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF;
775         if (!options.valid && gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
776         return gen_int_range(0, 5);
777 }
778
779 /*
780   generate an openx open mode
781 */
782 static uint16_t gen_openx_mode(void)
783 {
784         if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
785         if (gen_chance(20)) return gen_bits_mask(0xFF);
786         return OPENX_MODE_DENY_NONE | gen_bits_mask(0x3);
787 }
788
789 /*
790   generate an openx flags field
791 */
792 static uint16_t gen_openx_flags(void)
793 {
794         if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
795         return gen_bits_mask(0x7);
796 }
797
798 /*
799   generate an openx open function
800 */
801 static uint16_t gen_openx_func(void)
802 {
803         if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
804         return gen_bits_mask(0x13);
805 }
806
807 /*
808   generate a file attrib combination
809 */
810 static uint32_t gen_attrib(void)
811 {
812         uint32_t ret;
813         if (gen_chance(20)) {
814                 ret = gen_bits_mask(0xFFFFFFFF);
815                 if (options.valid) ret &= FILE_ATTRIBUTE_ALL_MASK;
816                 return ret;
817         }
818         return gen_bits_mask(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
819 }
820
821 /*
822   generate a unix timestamp
823 */
824 static time_t gen_timet(void)
825 {
826         if (gen_chance(30)) return 0;
827         return (time_t)random();
828 }
829
830 /*
831   generate a milliseconds protocol timeout
832 */
833 static uint32_t gen_timeout(void)
834 {
835         if (gen_chance(98)) return 0;
836         return random() % 50;
837 }
838
839 /*
840   generate a timestamp
841 */
842 static NTTIME gen_nttime(void)
843 {
844         NTTIME ret;
845         unix_to_nt_time(&ret, gen_timet());
846         return ret;
847 }
848
849 /*
850   generate a timewarp value
851 */
852 static NTTIME gen_timewarp(void)
853 {
854         NTTIME ret = gen_nttime();
855         if (gen_chance(98)) ret = 0;
856         return ret;
857 }
858
859 /*
860   generate a file allocation size
861 */
862 static uint_t gen_alloc_size(void)
863 {
864         uint_t ret;
865
866         if (gen_chance(30)) return 0;
867
868         ret = random() % 4*1024*1024;
869         /* give a high chance of a round number */
870         if (gen_chance(60)) {
871                 ret &= ~(1024*1024 - 1);
872         }
873         return ret;
874 }
875
876 /*
877   generate an ea_struct
878 */
879 static struct ea_struct gen_ea_struct(void)
880 {
881         struct ea_struct ea;
882         const char *names[] = {"EAONE", 
883                                "", 
884                                "FOO!", 
885                                " WITH SPACES ", 
886                                ".", 
887                                "AVERYLONGATTRIBUTENAME"};
888         const char *values[] = {"VALUE1", 
889                                "", 
890                                "NOT MUCH FOO", 
891                                " LEADING SPACES ", 
892                                ":", 
893                                "ASOMEWHATLONGERATTRIBUTEVALUE"};
894         int i;
895
896         ZERO_STRUCT(ea);
897
898         do {
899                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
900         } while (ignore_pattern(names[i]));
901
902         ea.name.s = names[i];
903
904         do {
905                 i = gen_int_range(0, ARRAY_SIZE(values)-1);
906         } while (ignore_pattern(values[i]));
907
908         ea.value = data_blob(values[i], strlen(values[i]));
909
910         if (gen_chance(10)) ea.flags = gen_bits_mask(0xFF);
911         ea.flags = 0;
912
913         return ea;
914 }
915
916 /*
917   generate an ea_struct
918 */
919 static struct smb_ea_list gen_ea_list(void)
920 {
921         struct smb_ea_list eas;
922         int i;
923         if (options.no_eas) {
924                 ZERO_STRUCT(eas);
925                 return eas;
926         }
927         eas.num_eas = gen_int_range(0, 3);
928         eas.eas = talloc_array(current_op.mem_ctx, struct ea_struct, eas.num_eas);
929         for (i=0;i<eas.num_eas;i++) {
930                 eas.eas[i] = gen_ea_struct();
931         }
932         return eas;
933 }
934
935 /* generate a security descriptor */
936 static struct security_descriptor *gen_sec_desc(void)
937 {
938         struct security_descriptor *sd;
939         if (options.no_acls || gen_chance(90)) return NULL;
940
941         sd = security_descriptor_dacl_create(current_op.mem_ctx,
942                                              0, NULL, NULL,
943                                              NULL,
944                                              SEC_ACE_TYPE_ACCESS_ALLOWED,
945                                              SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
946                                              SEC_ACE_FLAG_OBJECT_INHERIT,
947                                              SID_WORLD,
948                                              SEC_ACE_TYPE_ACCESS_ALLOWED,
949                                              SEC_FILE_ALL | SEC_STD_ALL,
950                                              0,
951                                              NULL);
952         return sd;
953 }
954
955
956 static void oplock_handler_close_recv_smb(struct smbcli_request *req)
957 {
958         NTSTATUS status;
959         status = smbcli_request_simple_recv(req);
960         if (!NT_STATUS_IS_OK(status)) {
961                 printf("close failed in oplock_handler\n");
962                 smb_panic("close failed in oplock_handler");
963         }
964 }
965
966 /*
967   the oplock handler will either ack the break or close the file
968 */
969 static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private)
970 {
971         union smb_close io;
972         int i, j;
973         bool do_close;
974         struct smbcli_tree *tree = NULL;
975         struct smbcli_request *req;
976
977         srandom(current_op.seed);
978         do_close = gen_chance(50);
979
980         for (i=0;i<NSERVERS;i++) {
981                 for (j=0;j<NINSTANCES;j++) {
982                         if (transport == servers[i].smb_tree[j]->session->transport &&
983                             tid == servers[i].smb_tree[j]->tid) {
984                                 oplocks[i][j].got_break = true;
985                                 oplocks[i][j].smb_handle = fnum;
986                                 oplocks[i][j].handle = fnum_to_handle_smb(i, j, fnum);
987                                 oplocks[i][j].level = level;
988                                 oplocks[i][j].do_close = do_close;
989                                 tree = servers[i].smb_tree[j];
990                         }
991                 }
992         }
993
994         if (!tree) {
995                 printf("Oplock break not for one of our trees!?\n");
996                 return false;
997         }
998
999         if (!do_close) {
1000                 printf("oplock ack fnum=%d\n", fnum);
1001                 return smbcli_oplock_ack(tree, fnum, level);
1002         }
1003
1004         printf("oplock close fnum=%d\n", fnum);
1005
1006         io.close.level = RAW_CLOSE_CLOSE;
1007         io.close.in.file.fnum = fnum;
1008         io.close.in.write_time = 0;
1009         req = smb_raw_close_send(tree, &io);
1010
1011         if (req == NULL) {
1012                 printf("WARNING: close failed in oplock_handler_close\n");
1013                 return false;
1014         }
1015
1016         req->async.fn = oplock_handler_close_recv_smb;
1017         req->async.private = NULL;
1018
1019         return true;
1020 }
1021
1022
1023 /*
1024   the idle function tries to cope with getting an oplock break on a connection, and
1025   an operation on another connection blocking until that break is acked
1026   we check for operations on all transports in the idle function
1027 */
1028 static void idle_func_smb(struct smbcli_transport *transport, void *private)
1029 {
1030         int i, j;
1031         for (i=0;i<NSERVERS;i++) {
1032                 for (j=0;j<NINSTANCES;j++) {
1033                         if (servers[i].smb_tree[j] &&
1034                             transport != servers[i].smb_tree[j]->session->transport) {
1035                                 smbcli_transport_process(servers[i].smb_tree[j]->session->transport);
1036                         }
1037                 }
1038         }
1039
1040 }
1041
1042 static void oplock_handler_close_recv_smb2(struct smb2_request *req)
1043 {
1044         NTSTATUS status;
1045         struct smb2_close io;
1046         status = smb2_close_recv(req, &io);
1047         if (!NT_STATUS_IS_OK(status)) {
1048                 printf("close failed in oplock_handler\n");
1049                 smb_panic("close failed in oplock_handler");
1050         }
1051 }
1052
1053 static void oplock_handler_ack_callback_smb2(struct smb2_request *req)
1054 {
1055         NTSTATUS status;
1056         struct smb2_break br;
1057
1058         status = smb2_break_recv(req, &br);
1059         if (!NT_STATUS_IS_OK(status)) {
1060                 printf("oplock break ack failed in oplock_handler\n");
1061                 smb_panic("oplock break ack failed in oplock_handler");
1062         }
1063 }
1064
1065 static bool send_oplock_ack_smb2(struct smb2_tree *tree, struct smb2_handle handle, 
1066                                  uint8_t level)
1067 {
1068         struct smb2_break br;
1069         struct smb2_request *req;
1070
1071         ZERO_STRUCT(br);
1072         br.in.file.handle       = handle;
1073         br.in.oplock_level      = level;
1074         br.in.reserved          = gen_reserved8();
1075         br.in.reserved2         = gen_reserved32();
1076
1077         req = smb2_break_send(tree, &br);
1078         if (req == NULL) return false;
1079         req->async.fn = oplock_handler_ack_callback_smb2;
1080         req->async.private_data = NULL;
1081         return true;
1082 }
1083
1084 /*
1085   the oplock handler will either ack the break or close the file
1086 */
1087 static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, 
1088                                 uint8_t level, void *private_data)
1089 {
1090         struct smb2_close io;
1091         unsigned i, j;
1092         bool do_close;
1093         struct smb2_tree *tree = NULL;
1094         struct smb2_request *req;
1095
1096         srandom(current_op.seed);
1097         do_close = gen_chance(50);
1098
1099         i = ((uintptr_t)private_data) >> 8;
1100         j = ((uintptr_t)private_data) & 0xFF;
1101
1102         if (i >= NSERVERS || j >= NINSTANCES) {
1103                 printf("Bad private_data in oplock_handler\n");
1104                 return false;
1105         }
1106
1107         oplocks[i][j].got_break = true;
1108         oplocks[i][j].smb2_handle = *handle;
1109         oplocks[i][j].handle = fnum_to_handle_smb2(i, j, *handle);
1110         oplocks[i][j].level = level;
1111         oplocks[i][j].do_close = do_close;
1112         tree = talloc_get_type(servers[i].smb2_tree[j], struct smb2_tree);
1113
1114         if (!tree) {
1115                 printf("Oplock break not for one of our trees!?\n");
1116                 return false;
1117         }
1118
1119         if (!do_close) {
1120                 printf("oplock ack handle=%d\n", oplocks[i][j].handle);
1121                 return send_oplock_ack_smb2(tree, *handle, level);
1122         }
1123
1124         printf("oplock close fnum=%d\n", oplocks[i][j].handle);
1125
1126         ZERO_STRUCT(io);
1127         io.in.file.handle = *handle;
1128         io.in.flags = 0;
1129         req = smb2_close_send(tree, &io);
1130
1131         if (req == NULL) {
1132                 printf("WARNING: close failed in oplock_handler_close\n");
1133                 return false;
1134         }
1135
1136         req->async.fn = oplock_handler_close_recv_smb2;
1137         req->async.private_data = NULL;
1138
1139         return true;
1140 }
1141
1142
1143 /*
1144   the idle function tries to cope with getting an oplock break on a connection, and
1145   an operation on another connection blocking until that break is acked
1146   we check for operations on all transports in the idle function
1147 */
1148 static void idle_func_smb2(struct smb2_transport *transport, void *private)
1149 {
1150         int i, j;
1151         for (i=0;i<NSERVERS;i++) {
1152                 for (j=0;j<NINSTANCES;j++) {
1153                         if (servers[i].smb2_tree[j] &&
1154                             transport != servers[i].smb2_tree[j]->session->transport) {
1155                                 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1156                         }
1157                 }
1158         }
1159
1160 }
1161
1162
1163 /*
1164   compare NTSTATUS, using checking ignored patterns
1165 */
1166 static bool compare_status(NTSTATUS status1, NTSTATUS status2)
1167 {
1168         if (NT_STATUS_EQUAL(status1, status2)) return true;
1169
1170         /* one code being an error and the other OK is always an error */
1171         if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) {
1172                 current_op.mismatch = nt_errstr(status1);
1173                 return false;
1174         }
1175
1176         /* if we are ignoring one of the status codes then consider this a match */
1177         if (ignore_pattern(nt_errstr(status1)) ||
1178             ignore_pattern(nt_errstr(status2))) {
1179                 return true;
1180         }
1181         current_op.mismatch = nt_errstr(status1);
1182         return false;
1183 }
1184
1185 /*
1186   check for pending packets on all connections
1187 */
1188 static void check_pending(void)
1189 {
1190         int i, j;
1191
1192         msleep(20);
1193
1194         for (j=0;j<NINSTANCES;j++) {
1195                 for (i=0;i<NSERVERS;i++) {
1196                         // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1197                 }
1198         }       
1199 }
1200
1201 /*
1202   check that the same oplock breaks have been received by all instances
1203 */
1204 static bool check_oplocks(const char *call)
1205 {
1206         int i, j;
1207         int tries = 0;
1208
1209         if (!options.use_oplocks || options.smb2) {
1210                 /* no smb2 oplocks in gentest yet */
1211                 return true;
1212         }
1213
1214 again:
1215         check_pending();
1216
1217         for (j=0;j<NINSTANCES;j++) {
1218                 for (i=1;i<NSERVERS;i++) {
1219                         if (oplocks[0][j].got_break != oplocks[i][j].got_break ||
1220                             oplocks[0][j].handle != oplocks[i][j].handle ||
1221                             oplocks[0][j].level != oplocks[i][j].level) {
1222                                 if (tries++ < 10) goto again;
1223                                 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
1224                                        oplocks[0][j].got_break, 
1225                                        oplocks[0][j].handle, 
1226                                        oplocks[0][j].level, 
1227                                        oplocks[i][j].got_break, 
1228                                        oplocks[i][j].handle, 
1229                                        oplocks[i][j].level);
1230                                 current_op.mismatch = "oplock break";
1231                                 return false;
1232                         }
1233                 }
1234         }
1235
1236         /* if we got a break and closed then remove the handle */
1237         for (j=0;j<NINSTANCES;j++) {
1238                 if (oplocks[0][j].got_break &&
1239                     oplocks[0][j].do_close) {
1240                         uint16_t fnums[NSERVERS];
1241                         for (i=0;i<NSERVERS;i++) {
1242                                 fnums[i] = oplocks[i][j].smb_handle;
1243                         }
1244                         gen_remove_handle_smb(j, fnums);
1245                         break;
1246                 }
1247         }       
1248         return true;
1249 }
1250
1251
1252 /*
1253   check that the same change notify info has been received by all instances
1254 */
1255 static bool check_notifies(const char *call)
1256 {
1257         int i, j;
1258         int tries = 0;
1259
1260         if (options.smb2) {
1261                 /* no smb2 notifies in gentest yet */
1262                 return true;
1263         }
1264
1265 again:
1266         check_pending();
1267
1268         for (j=0;j<NINSTANCES;j++) {
1269                 for (i=1;i<NSERVERS;i++) {
1270                         int n;
1271                         union smb_notify not1, not2;
1272
1273                         if (notifies[0][j].notify_count != notifies[i][j].notify_count) {
1274                                 if (tries++ < 10) goto again;
1275                                 printf("Notify count inconsistent %d %d\n",
1276                                        notifies[0][j].notify_count,
1277                                        notifies[i][j].notify_count);
1278                                 current_op.mismatch = "notify count";
1279                                 return false;
1280                         }
1281
1282                         if (notifies[0][j].notify_count == 0) continue;
1283
1284                         if (!NT_STATUS_EQUAL(notifies[0][j].status,
1285                                              notifies[i][j].status)) {
1286                                 printf("Notify status mismatch - %s - %s\n",
1287                                        nt_errstr(notifies[0][j].status),
1288                                        nt_errstr(notifies[i][j].status));
1289                                 current_op.mismatch = "Notify status";
1290                                 return false;
1291                         }
1292
1293                         if (!NT_STATUS_IS_OK(notifies[0][j].status)) {
1294                                 continue;
1295                         }
1296
1297                         not1 = notifies[0][j].notify;
1298                         not2 = notifies[i][j].notify;
1299
1300                         for (n=0;n<not1.nttrans.out.num_changes;n++) {
1301                                 if (not1.nttrans.out.changes[n].action != 
1302                                     not2.nttrans.out.changes[n].action) {
1303                                         printf("Notify action %d inconsistent %d %d\n", n,
1304                                                not1.nttrans.out.changes[n].action,
1305                                                not2.nttrans.out.changes[n].action);
1306                                         current_op.mismatch = "notify action";
1307                                         return false;
1308                                 }
1309                                 if (strcmp(not1.nttrans.out.changes[n].name.s,
1310                                            not2.nttrans.out.changes[n].name.s)) {
1311                                         printf("Notify name %d inconsistent %s %s\n", n,
1312                                                not1.nttrans.out.changes[n].name.s,
1313                                                not2.nttrans.out.changes[n].name.s);
1314                                         current_op.mismatch = "notify name";
1315                                         return false;
1316                                 }
1317                                 if (not1.nttrans.out.changes[n].name.private_length !=
1318                                     not2.nttrans.out.changes[n].name.private_length) {
1319                                         printf("Notify name length %d inconsistent %d %d\n", n,
1320                                                not1.nttrans.out.changes[n].name.private_length,
1321                                                not2.nttrans.out.changes[n].name.private_length);
1322                                         current_op.mismatch = "notify name length";
1323                                         return false;
1324                                 }
1325                         }
1326                 }
1327         }
1328
1329         ZERO_STRUCT(notifies);
1330
1331         return true;
1332 }
1333
1334 #define GEN_COPY_PARM do { \
1335         int i; \
1336         for (i=1;i<NSERVERS;i++) { \
1337                 parm[i] = parm[0]; \
1338         } \
1339 } while (0)
1340
1341 #define GEN_CALL(call, treetype, treefield) do {                \
1342         int i; \
1343         ZERO_STRUCT(oplocks); \
1344         ZERO_STRUCT(notifies); \
1345         for (i=0;i<NSERVERS;i++) { \
1346                 struct treetype *tree = servers[i].treefield[instance]; \
1347                 status[i] = call; \
1348         } \
1349         current_op.status = status[0]; \
1350         for (i=1;i<NSERVERS;i++) { \
1351                 if (!compare_status(status[i], status[0])) { \
1352                         printf("status different in %s - %s %s\n", #call, \
1353                                nt_errstr(status[0]), nt_errstr(status[i])); \
1354                         current_op.mismatch = nt_errstr(status[0]); \
1355                         return false; \
1356                 } \
1357         } \
1358         if (!check_oplocks(#call)) return false;        \
1359         if (!check_notifies(#call)) return false;       \
1360         if (!NT_STATUS_IS_OK(status[0])) { \
1361                 return true; \
1362         } \
1363 } while(0)
1364
1365 #define GEN_CALL_SMB(call) GEN_CALL(call, smbcli_tree, smb_tree)
1366 #define GEN_CALL_SMB2(call) GEN_CALL(call, smb2_tree, smb2_tree)
1367
1368 #define ADD_HANDLE_SMB2(name, field) do { \
1369         struct smb2_handle handles[NSERVERS]; \
1370         int i; \
1371         for (i=0;i<NSERVERS;i++) { \
1372                 handles[i] = parm[i].field; \
1373         } \
1374         gen_add_handle_smb2(instance, name, handles); \
1375 } while(0)
1376
1377 #define REMOVE_HANDLE_SMB2(field) do { \
1378         struct smb2_handle handles[NSERVERS]; \
1379         int i; \
1380         for (i=0;i<NSERVERS;i++) { \
1381                 handles[i] = parm[i].field; \
1382         } \
1383         gen_remove_handle_smb2(instance, handles); \
1384 } while(0)
1385
1386 #define ADD_HANDLE_SMB(name, field) do { \
1387         uint16_t handles[NSERVERS]; \
1388         int i; \
1389         for (i=0;i<NSERVERS;i++) { \
1390                 handles[i] = parm[i].field; \
1391         } \
1392         gen_add_handle_smb(instance, name, handles); \
1393 } while(0)
1394
1395 #define REMOVE_HANDLE_SMB(field) do { \
1396         uint16_t handles[NSERVERS]; \
1397         int i; \
1398         for (i=0;i<NSERVERS;i++) { \
1399                 handles[i] = parm[i].field; \
1400         } \
1401         gen_remove_handle_smb(instance, handles); \
1402 } while(0)
1403
1404 #define GEN_SET_FNUM_SMB2(field) do { \
1405         int i; \
1406         for (i=0;i<NSERVERS;i++) { \
1407                 parm[i].field = gen_lookup_handle_smb2(i, parm[i].field.data[0]); \
1408         } \
1409 } while(0)
1410
1411 #define GEN_SET_FNUM_SMB(field) do { \
1412         int i; \
1413         for (i=0;i<NSERVERS;i++) { \
1414                 parm[i].field = gen_lookup_handle_smb(i, parm[i].field); \
1415         } \
1416 } while(0)
1417
1418 #define CHECK_EQUAL(field) do { \
1419         if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1420                 current_op.mismatch = #field; \
1421                 printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \
1422                        (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \
1423                 return false; \
1424         } \
1425 } while(0)
1426
1427 #define CHECK_SECDESC(field) do { \
1428         if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \
1429                 current_op.mismatch = #field; \
1430                 printf("Mismatch in %s\n", #field); \
1431                 return false;                       \
1432         } \
1433 } while(0)
1434
1435 #define CHECK_ATTRIB(field) do { \
1436                 if (!options.mask_indexing) { \
1437                 CHECK_EQUAL(field); \
1438         } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \
1439                 current_op.mismatch = #field; \
1440                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1441                        (int)parm[0].field, (int)parm[1].field); \
1442                 return false; \
1443         } \
1444 } while(0)
1445
1446 #define CHECK_WSTR_EQUAL(field) do { \
1447         if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1448                 current_op.mismatch = #field; \
1449                 printf("%s is NULL!\n", #field); \
1450                 return false; \
1451         } \
1452         if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1453                 current_op.mismatch = #field; \
1454                 printf("Mismatch in %s - %s %s\n", #field, \
1455                        parm[0].field.s, parm[1].field.s); \
1456                 return false; \
1457         } \
1458         CHECK_EQUAL(field.private_length); \
1459 } while(0)
1460
1461 #define CHECK_BLOB_EQUAL(field) do { \
1462         if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
1463                 current_op.mismatch = #field; \
1464                 printf("Mismatch in %s\n", #field); \
1465                 return false; \
1466         } \
1467         CHECK_EQUAL(field.length); \
1468 } while(0)
1469
1470 #define CHECK_TIMES_EQUAL(field) do { \
1471         if (labs(parm[0].field - parm[1].field) > time_skew() && \
1472             !ignore_pattern(#field)) { \
1473                 current_op.mismatch = #field; \
1474                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1475                        (int)parm[0].field, (int)parm[1].field); \
1476                 return false; \
1477         } \
1478 } while(0)
1479
1480 #define CHECK_NTTIMES_EQUAL(field) do { \
1481         if (labs(nt_time_to_unix(parm[0].field) - \
1482                 nt_time_to_unix(parm[1].field)) > time_skew() && \
1483             !ignore_pattern(#field)) { \
1484                 current_op.mismatch = #field; \
1485                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1486                        (int)nt_time_to_unix(parm[0].field), \
1487                        (int)nt_time_to_unix(parm[1].field)); \
1488                 return false; \
1489         } \
1490 } while(0)
1491
1492
1493 /*
1494   compare returned fileinfo structures
1495 */
1496 static bool cmp_fileinfo(int instance, 
1497                          union smb_fileinfo parm[NSERVERS],
1498                          NTSTATUS status[NSERVERS])
1499 {
1500         int i;
1501         enum smb_fileinfo_level level = parm[0].generic.level;
1502
1503         if (level == RAW_FILEINFO_ALL_INFORMATION &&
1504             options.smb2) {
1505                 level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
1506         }
1507
1508         switch (level) {
1509         case RAW_FILEINFO_GENERIC:
1510                 return false;
1511
1512         case RAW_FILEINFO_GETATTR:
1513                 CHECK_ATTRIB(getattr.out.attrib);
1514                 CHECK_EQUAL(getattr.out.size);
1515                 CHECK_TIMES_EQUAL(getattr.out.write_time);
1516                 break;
1517
1518         case RAW_FILEINFO_GETATTRE:
1519                 CHECK_TIMES_EQUAL(getattre.out.create_time);
1520                 CHECK_TIMES_EQUAL(getattre.out.access_time);
1521                 CHECK_TIMES_EQUAL(getattre.out.write_time);
1522                 CHECK_EQUAL(getattre.out.size);
1523                 CHECK_EQUAL(getattre.out.alloc_size);
1524                 CHECK_ATTRIB(getattre.out.attrib);
1525                 break;
1526
1527         case RAW_FILEINFO_STANDARD:
1528                 CHECK_TIMES_EQUAL(standard.out.create_time);
1529                 CHECK_TIMES_EQUAL(standard.out.access_time);
1530                 CHECK_TIMES_EQUAL(standard.out.write_time);
1531                 CHECK_EQUAL(standard.out.size);
1532                 CHECK_EQUAL(standard.out.alloc_size);
1533                 CHECK_ATTRIB(standard.out.attrib);
1534                 break;
1535
1536         case RAW_FILEINFO_EA_SIZE:
1537                 CHECK_TIMES_EQUAL(ea_size.out.create_time);
1538                 CHECK_TIMES_EQUAL(ea_size.out.access_time);
1539                 CHECK_TIMES_EQUAL(ea_size.out.write_time);
1540                 CHECK_EQUAL(ea_size.out.size);
1541                 CHECK_EQUAL(ea_size.out.alloc_size);
1542                 CHECK_ATTRIB(ea_size.out.attrib);
1543                 CHECK_EQUAL(ea_size.out.ea_size);
1544                 break;
1545
1546         case RAW_FILEINFO_ALL_EAS:
1547                 CHECK_EQUAL(all_eas.out.num_eas);
1548                 for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
1549                         CHECK_EQUAL(all_eas.out.eas[i].flags);
1550                         CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
1551                         CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
1552                 }
1553                 break;
1554
1555         case RAW_FILEINFO_IS_NAME_VALID:
1556                 break;
1557                 
1558         case RAW_FILEINFO_BASIC_INFO:
1559         case RAW_FILEINFO_BASIC_INFORMATION:
1560                 CHECK_NTTIMES_EQUAL(basic_info.out.create_time);
1561                 CHECK_NTTIMES_EQUAL(basic_info.out.access_time);
1562                 CHECK_NTTIMES_EQUAL(basic_info.out.write_time);
1563                 CHECK_NTTIMES_EQUAL(basic_info.out.change_time);
1564                 CHECK_ATTRIB(basic_info.out.attrib);
1565                 break;
1566
1567         case RAW_FILEINFO_STANDARD_INFO:
1568         case RAW_FILEINFO_STANDARD_INFORMATION:
1569                 CHECK_EQUAL(standard_info.out.alloc_size);
1570                 CHECK_EQUAL(standard_info.out.size);
1571                 CHECK_EQUAL(standard_info.out.nlink);
1572                 CHECK_EQUAL(standard_info.out.delete_pending);
1573                 CHECK_EQUAL(standard_info.out.directory);
1574                 break;
1575
1576         case RAW_FILEINFO_EA_INFO:
1577         case RAW_FILEINFO_EA_INFORMATION:
1578                 CHECK_EQUAL(ea_info.out.ea_size);
1579                 break;
1580
1581         case RAW_FILEINFO_NAME_INFO:
1582         case RAW_FILEINFO_NAME_INFORMATION:
1583                 CHECK_WSTR_EQUAL(name_info.out.fname);
1584                 break;
1585
1586         case RAW_FILEINFO_ALL_INFO:
1587         case RAW_FILEINFO_ALL_INFORMATION:
1588                 CHECK_NTTIMES_EQUAL(all_info.out.create_time);
1589                 CHECK_NTTIMES_EQUAL(all_info.out.access_time);
1590                 CHECK_NTTIMES_EQUAL(all_info.out.write_time);
1591                 CHECK_NTTIMES_EQUAL(all_info.out.change_time);
1592                 CHECK_ATTRIB(all_info.out.attrib);
1593                 CHECK_EQUAL(all_info.out.alloc_size);
1594                 CHECK_EQUAL(all_info.out.size);
1595                 CHECK_EQUAL(all_info.out.nlink);
1596                 CHECK_EQUAL(all_info.out.delete_pending);
1597                 CHECK_EQUAL(all_info.out.directory);
1598                 CHECK_EQUAL(all_info.out.ea_size);
1599                 CHECK_WSTR_EQUAL(all_info.out.fname);
1600                 break;
1601
1602         case RAW_FILEINFO_ALT_NAME_INFO:
1603         case RAW_FILEINFO_ALT_NAME_INFORMATION:
1604                 CHECK_WSTR_EQUAL(alt_name_info.out.fname);
1605                 break;
1606
1607         case RAW_FILEINFO_STREAM_INFO:
1608         case RAW_FILEINFO_STREAM_INFORMATION:
1609                 CHECK_EQUAL(stream_info.out.num_streams);
1610                 for (i=0;i<parm[0].stream_info.out.num_streams;i++) {
1611                         CHECK_EQUAL(stream_info.out.streams[i].size);
1612                         CHECK_EQUAL(stream_info.out.streams[i].alloc_size);
1613                         CHECK_WSTR_EQUAL(stream_info.out.streams[i].stream_name);
1614                 }
1615                 break;
1616
1617         case RAW_FILEINFO_COMPRESSION_INFO:
1618         case RAW_FILEINFO_COMPRESSION_INFORMATION:
1619                 CHECK_EQUAL(compression_info.out.compressed_size);
1620                 CHECK_EQUAL(compression_info.out.format);
1621                 CHECK_EQUAL(compression_info.out.unit_shift);
1622                 CHECK_EQUAL(compression_info.out.chunk_shift);
1623                 CHECK_EQUAL(compression_info.out.cluster_shift);
1624                 break;
1625
1626         case RAW_FILEINFO_INTERNAL_INFORMATION:
1627                 CHECK_EQUAL(internal_information.out.file_id);
1628                 break;
1629
1630         case RAW_FILEINFO_ACCESS_INFORMATION:
1631                 CHECK_EQUAL(access_information.out.access_flags);
1632                 break;
1633
1634         case RAW_FILEINFO_POSITION_INFORMATION:
1635                 CHECK_EQUAL(position_information.out.position);
1636                 break;
1637
1638         case RAW_FILEINFO_MODE_INFORMATION:
1639                 CHECK_EQUAL(mode_information.out.mode);
1640                 break;
1641
1642         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
1643                 CHECK_EQUAL(alignment_information.out.alignment_requirement);
1644                 break;
1645
1646         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
1647                 CHECK_NTTIMES_EQUAL(network_open_information.out.create_time);
1648                 CHECK_NTTIMES_EQUAL(network_open_information.out.access_time);
1649                 CHECK_NTTIMES_EQUAL(network_open_information.out.write_time);
1650                 CHECK_NTTIMES_EQUAL(network_open_information.out.change_time);
1651                 CHECK_EQUAL(network_open_information.out.alloc_size);
1652                 CHECK_EQUAL(network_open_information.out.size);
1653                 CHECK_ATTRIB(network_open_information.out.attrib);
1654                 break;
1655
1656         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
1657                 CHECK_ATTRIB(attribute_tag_information.out.attrib);
1658                 CHECK_EQUAL(attribute_tag_information.out.reparse_tag);
1659                 break;
1660
1661         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
1662                 CHECK_NTTIMES_EQUAL(all_info2.out.create_time);
1663                 CHECK_NTTIMES_EQUAL(all_info2.out.access_time);
1664                 CHECK_NTTIMES_EQUAL(all_info2.out.write_time);
1665                 CHECK_NTTIMES_EQUAL(all_info2.out.change_time);
1666                 CHECK_ATTRIB(all_info2.out.attrib);
1667                 CHECK_EQUAL(all_info2.out.unknown1);
1668                 CHECK_EQUAL(all_info2.out.alloc_size);
1669                 CHECK_EQUAL(all_info2.out.size);
1670                 CHECK_EQUAL(all_info2.out.nlink);
1671                 CHECK_EQUAL(all_info2.out.delete_pending);
1672                 CHECK_EQUAL(all_info2.out.directory);
1673                 CHECK_EQUAL(all_info2.out.file_id);
1674                 CHECK_EQUAL(all_info2.out.ea_size);
1675                 CHECK_EQUAL(all_info2.out.access_mask);
1676                 CHECK_EQUAL(all_info2.out.position);
1677                 CHECK_EQUAL(all_info2.out.mode);
1678                 CHECK_EQUAL(all_info2.out.alignment_requirement);
1679                 CHECK_WSTR_EQUAL(all_info2.out.fname);
1680                 break;
1681
1682         case RAW_FILEINFO_SMB2_ALL_EAS:
1683                 CHECK_EQUAL(all_eas.out.num_eas);
1684                 for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
1685                         CHECK_EQUAL(all_eas.out.eas[i].flags);
1686                         CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
1687                         CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
1688                 }
1689                 break;
1690
1691         case RAW_FILEINFO_SEC_DESC:
1692                 CHECK_SECDESC(query_secdesc.out.sd);
1693                 break;
1694
1695                 /* Unhandled levels */
1696         case RAW_FILEINFO_EA_LIST:
1697         case RAW_FILEINFO_UNIX_BASIC:
1698         case RAW_FILEINFO_UNIX_LINK:
1699         case RAW_FILEINFO_UNIX_INFO2:
1700                 break;
1701         }
1702
1703         return true;
1704 }
1705
1706
1707
1708 /*
1709   generate openx operations
1710 */
1711 static bool handler_smb_openx(int instance)
1712 {
1713         union smb_open parm[NSERVERS];
1714         NTSTATUS status[NSERVERS];
1715
1716         parm[0].openx.level = RAW_OPEN_OPENX;
1717         parm[0].openx.in.flags = gen_openx_flags();
1718         parm[0].openx.in.open_mode = gen_openx_mode();
1719         parm[0].openx.in.search_attrs = gen_attrib();
1720         parm[0].openx.in.file_attrs = gen_attrib();
1721         parm[0].openx.in.write_time = gen_timet();
1722         parm[0].openx.in.open_func = gen_openx_func();
1723         parm[0].openx.in.size = gen_io_count();
1724         parm[0].openx.in.timeout = gen_timeout();
1725         parm[0].openx.in.fname = gen_fname_open(instance);
1726
1727         if (!options.use_oplocks) {
1728                 /* mask out oplocks */
1729                 parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1730                                             OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1731         }
1732         
1733         GEN_COPY_PARM;
1734         GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1735
1736         CHECK_ATTRIB(openx.out.attrib);
1737         CHECK_EQUAL(openx.out.size);
1738         CHECK_EQUAL(openx.out.access);
1739         CHECK_EQUAL(openx.out.ftype);
1740         CHECK_EQUAL(openx.out.devstate);
1741         CHECK_EQUAL(openx.out.action);
1742         CHECK_EQUAL(openx.out.access_mask);
1743         CHECK_EQUAL(openx.out.unknown);
1744         CHECK_TIMES_EQUAL(openx.out.write_time);
1745
1746         /* open creates a new file handle */
1747         ADD_HANDLE_SMB(parm[0].openx.in.fname, openx.out.file.fnum);
1748
1749         return true;
1750 }
1751
1752
1753 /*
1754   generate open operations
1755 */
1756 static bool handler_smb_open(int instance)
1757 {
1758         union smb_open parm[NSERVERS];
1759         NTSTATUS status[NSERVERS];
1760
1761         parm[0].openold.level = RAW_OPEN_OPEN;
1762         parm[0].openold.in.open_mode = gen_bits_mask2(0xF, 0xFFFF);
1763         parm[0].openold.in.search_attrs = gen_attrib();
1764         parm[0].openold.in.fname = gen_fname_open(instance);
1765
1766         if (!options.use_oplocks) {
1767                 /* mask out oplocks */
1768                 parm[0].openold.in.open_mode &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1769                                                   OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1770         }
1771         
1772         GEN_COPY_PARM;
1773         GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1774
1775         CHECK_ATTRIB(openold.out.attrib);
1776         CHECK_TIMES_EQUAL(openold.out.write_time);
1777         CHECK_EQUAL(openold.out.size);
1778         CHECK_EQUAL(openold.out.rmode);
1779
1780         /* open creates a new file handle */
1781         ADD_HANDLE_SMB(parm[0].openold.in.fname, openold.out.file.fnum);
1782
1783         return true;
1784 }
1785
1786
1787 /*
1788   generate ntcreatex operations
1789 */
1790 static bool handler_smb_ntcreatex(int instance)
1791 {
1792         union smb_open parm[NSERVERS];
1793         NTSTATUS status[NSERVERS];
1794
1795         parm[0].ntcreatex.level = RAW_OPEN_NTCREATEX;
1796         parm[0].ntcreatex.in.flags = gen_ntcreatex_flags();
1797         parm[0].ntcreatex.in.root_fid = gen_root_fid(instance);
1798         parm[0].ntcreatex.in.access_mask = gen_access_mask();
1799         parm[0].ntcreatex.in.alloc_size = gen_alloc_size();
1800         parm[0].ntcreatex.in.file_attr = gen_attrib();
1801         parm[0].ntcreatex.in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF);
1802         parm[0].ntcreatex.in.open_disposition = gen_open_disp();
1803         parm[0].ntcreatex.in.create_options = gen_create_options();
1804         parm[0].ntcreatex.in.impersonation = gen_bits_mask2(0, 0xFFFFFFFF);
1805         parm[0].ntcreatex.in.security_flags = gen_bits_mask2(0, 0xFF);
1806         parm[0].ntcreatex.in.fname = gen_fname_open(instance);
1807
1808         if (!options.use_oplocks) {
1809                 /* mask out oplocks */
1810                 parm[0].ntcreatex.in.flags &= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK|
1811                                                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK);
1812         }
1813         
1814         GEN_COPY_PARM;
1815         if (parm[0].ntcreatex.in.root_fid != 0) {
1816                 GEN_SET_FNUM_SMB(ntcreatex.in.root_fid);
1817         }
1818         GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1819
1820         CHECK_EQUAL(ntcreatex.out.oplock_level);
1821         CHECK_EQUAL(ntcreatex.out.create_action);
1822         CHECK_NTTIMES_EQUAL(ntcreatex.out.create_time);
1823         CHECK_NTTIMES_EQUAL(ntcreatex.out.access_time);
1824         CHECK_NTTIMES_EQUAL(ntcreatex.out.write_time);
1825         CHECK_NTTIMES_EQUAL(ntcreatex.out.change_time);
1826         CHECK_ATTRIB(ntcreatex.out.attrib);
1827         CHECK_EQUAL(ntcreatex.out.alloc_size);
1828         CHECK_EQUAL(ntcreatex.out.size);
1829         CHECK_EQUAL(ntcreatex.out.file_type);
1830         CHECK_EQUAL(ntcreatex.out.ipc_state);
1831         CHECK_EQUAL(ntcreatex.out.is_directory);
1832
1833         /* ntcreatex creates a new file handle */
1834         ADD_HANDLE_SMB(parm[0].ntcreatex.in.fname, ntcreatex.out.file.fnum);
1835
1836         return true;
1837 }
1838
1839 /*
1840   generate close operations
1841 */
1842 static bool handler_smb_close(int instance)
1843 {
1844         union smb_close parm[NSERVERS];
1845         NTSTATUS status[NSERVERS];
1846
1847         parm[0].close.level = RAW_CLOSE_CLOSE;
1848         parm[0].close.in.file.fnum = gen_fnum_close(instance);
1849         parm[0].close.in.write_time = gen_timet();
1850
1851         GEN_COPY_PARM;
1852         GEN_SET_FNUM_SMB(close.in.file.fnum);
1853         GEN_CALL_SMB(smb_raw_close(tree, &parm[i]));
1854
1855         REMOVE_HANDLE_SMB(close.in.file.fnum);
1856
1857         return true;
1858 }
1859
1860 /*
1861   generate unlink operations
1862 */
1863 static bool handler_smb_unlink(int instance)
1864 {
1865         union smb_unlink parm[NSERVERS];
1866         NTSTATUS status[NSERVERS];
1867
1868         parm[0].unlink.in.pattern = gen_pattern();
1869         parm[0].unlink.in.attrib = gen_attrib();
1870
1871         GEN_COPY_PARM;
1872         GEN_CALL_SMB(smb_raw_unlink(tree, &parm[i]));
1873
1874         return true;
1875 }
1876
1877 /*
1878   generate chkpath operations
1879 */
1880 static bool handler_smb_chkpath(int instance)
1881 {
1882         union smb_chkpath parm[NSERVERS];
1883         NTSTATUS status[NSERVERS];
1884
1885         parm[0].chkpath.in.path = gen_fname_open(instance);
1886
1887         GEN_COPY_PARM;
1888         GEN_CALL_SMB(smb_raw_chkpath(tree, &parm[i]));
1889
1890         return true;
1891 }
1892
1893 /*
1894   generate mkdir operations
1895 */
1896 static bool handler_smb_mkdir(int instance)
1897 {
1898         union smb_mkdir parm[NSERVERS];
1899         NTSTATUS status[NSERVERS];
1900
1901         parm[0].mkdir.level = RAW_MKDIR_MKDIR;
1902         parm[0].mkdir.in.path = gen_fname_open(instance);
1903
1904         GEN_COPY_PARM;
1905         GEN_CALL_SMB(smb_raw_mkdir(tree, &parm[i]));
1906
1907         return true;
1908 }
1909
1910 /*
1911   generate rmdir operations
1912 */
1913 static bool handler_smb_rmdir(int instance)
1914 {
1915         struct smb_rmdir parm[NSERVERS];
1916         NTSTATUS status[NSERVERS];
1917
1918         parm[0].in.path = gen_fname_open(instance);
1919
1920         GEN_COPY_PARM;
1921         GEN_CALL_SMB(smb_raw_rmdir(tree, &parm[i]));
1922
1923         return true;
1924 }
1925
1926 /*
1927   generate rename operations
1928 */
1929 static bool handler_smb_rename(int instance)
1930 {
1931         union smb_rename parm[NSERVERS];
1932         NTSTATUS status[NSERVERS];
1933
1934         parm[0].generic.level = RAW_RENAME_RENAME;
1935         parm[0].rename.in.pattern1 = gen_pattern();
1936         parm[0].rename.in.pattern2 = gen_pattern();
1937         parm[0].rename.in.attrib = gen_attrib();
1938
1939         GEN_COPY_PARM;
1940         GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
1941
1942         return true;
1943 }
1944
1945 /*
1946   generate ntrename operations
1947 */
1948 static bool handler_smb_ntrename(int instance)
1949 {
1950         union smb_rename parm[NSERVERS];
1951         NTSTATUS status[NSERVERS];
1952
1953         parm[0].generic.level = RAW_RENAME_NTRENAME;
1954         parm[0].ntrename.in.old_name = gen_fname();
1955         parm[0].ntrename.in.new_name = gen_fname();
1956         parm[0].ntrename.in.attrib = gen_attrib();
1957         parm[0].ntrename.in.cluster_size = gen_bits_mask2(0, 0xFFFFFFF);
1958         parm[0].ntrename.in.flags = gen_rename_flags();
1959
1960         GEN_COPY_PARM;
1961         GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
1962
1963         return true;
1964 }
1965
1966
1967 /*
1968   generate seek operations
1969 */
1970 static bool handler_smb_seek(int instance)
1971 {
1972         union smb_seek parm[NSERVERS];
1973         NTSTATUS status[NSERVERS];
1974
1975         parm[0].lseek.in.file.fnum = gen_fnum(instance);
1976         parm[0].lseek.in.mode = gen_bits_mask2(0x3, 0xFFFF);
1977         parm[0].lseek.in.offset = gen_offset();
1978
1979         GEN_COPY_PARM;
1980         GEN_SET_FNUM_SMB(lseek.in.file.fnum);
1981         GEN_CALL_SMB(smb_raw_seek(tree, &parm[i]));
1982
1983         CHECK_EQUAL(lseek.out.offset);
1984
1985         return true;
1986 }
1987
1988
1989 /*
1990   generate readx operations
1991 */
1992 static bool handler_smb_readx(int instance)
1993 {
1994         union smb_read parm[NSERVERS];
1995         NTSTATUS status[NSERVERS];
1996
1997         parm[0].readx.level = RAW_READ_READX;
1998         parm[0].readx.in.file.fnum = gen_fnum(instance);
1999         parm[0].readx.in.offset = gen_offset();
2000         parm[0].readx.in.mincnt = gen_io_count();
2001         parm[0].readx.in.maxcnt = gen_io_count();
2002         parm[0].readx.in.remaining = gen_io_count();
2003         parm[0].readx.in.read_for_execute = gen_bool();
2004         parm[0].readx.out.data = talloc_array(current_op.mem_ctx, uint8_t,
2005                                              MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt));
2006
2007         GEN_COPY_PARM;
2008         GEN_SET_FNUM_SMB(readx.in.file.fnum);
2009         GEN_CALL_SMB(smb_raw_read(tree, &parm[i]));
2010
2011         CHECK_EQUAL(readx.out.remaining);
2012         CHECK_EQUAL(readx.out.compaction_mode);
2013         CHECK_EQUAL(readx.out.nread);
2014
2015         return true;
2016 }
2017
2018 /*
2019   generate writex operations
2020 */
2021 static bool handler_smb_writex(int instance)
2022 {
2023         union smb_write parm[NSERVERS];
2024         NTSTATUS status[NSERVERS];
2025
2026         parm[0].writex.level = RAW_WRITE_WRITEX;
2027         parm[0].writex.in.file.fnum = gen_fnum(instance);
2028         parm[0].writex.in.offset = gen_offset();
2029         parm[0].writex.in.wmode = gen_bits_mask(0xFFFF);
2030         parm[0].writex.in.remaining = gen_io_count();
2031         parm[0].writex.in.count = gen_io_count();
2032         parm[0].writex.in.data = talloc_zero_array(current_op.mem_ctx, uint8_t, parm[0].writex.in.count);
2033
2034         GEN_COPY_PARM;
2035         GEN_SET_FNUM_SMB(writex.in.file.fnum);
2036         GEN_CALL_SMB(smb_raw_write(tree, &parm[i]));
2037
2038         CHECK_EQUAL(writex.out.nwritten);
2039         CHECK_EQUAL(writex.out.remaining);
2040
2041         return true;
2042 }
2043
2044 /*
2045   generate lockingx operations
2046 */
2047 static bool handler_smb_lockingx(int instance)
2048 {
2049         union smb_lock parm[NSERVERS];
2050         NTSTATUS status[NSERVERS];
2051         int n, nlocks;
2052
2053         parm[0].lockx.level = RAW_LOCK_LOCKX;
2054         parm[0].lockx.in.file.fnum = gen_fnum(instance);
2055         parm[0].lockx.in.mode = gen_lock_mode();
2056         parm[0].lockx.in.timeout = gen_timeout();
2057         do {
2058                 /* make sure we don't accidentially generate an oplock
2059                    break ack - otherwise the server can just block forever */
2060                 parm[0].lockx.in.ulock_cnt = gen_lock_count();
2061                 parm[0].lockx.in.lock_cnt = gen_lock_count();
2062                 nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt;
2063         } while (nlocks == 0);
2064
2065         if (nlocks > 0) {
2066                 parm[0].lockx.in.locks = talloc_array(current_op.mem_ctx,
2067                                                         struct smb_lock_entry,
2068                                                         nlocks);
2069                 for (n=0;n<nlocks;n++) {
2070                         parm[0].lockx.in.locks[n].pid = gen_pid();
2071                         parm[0].lockx.in.locks[n].offset = gen_offset();
2072                         parm[0].lockx.in.locks[n].count = gen_io_count();
2073                 }
2074         }
2075
2076         GEN_COPY_PARM;
2077         GEN_SET_FNUM_SMB(lockx.in.file.fnum);
2078         GEN_CALL_SMB(smb_raw_lock(tree, &parm[i]));
2079
2080         return true;
2081 }
2082
2083 #if 0
2084 /*
2085   generate a fileinfo query structure
2086 */
2087 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
2088 {
2089         int i;
2090         #undef LVL
2091         #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2092         struct {
2093                 enum smb_setfileinfo_level level;
2094                 const char *name;
2095         }  levels[] = {
2096 #if 0
2097                 /* disabled until win2003 can handle them ... */
2098                 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), 
2099                 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), 
2100 #endif
2101                 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
2102                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
2103                 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
2104                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
2105                 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
2106         };
2107         do {
2108                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2109         } while (ignore_pattern(levels[i].name));
2110
2111         info->generic.level = levels[i].level;
2112
2113         switch (info->generic.level) {
2114         case RAW_SFILEINFO_SETATTR:
2115                 info->setattr.in.attrib = gen_attrib();
2116                 info->setattr.in.write_time = gen_timet();
2117                 break;
2118         case RAW_SFILEINFO_SETATTRE:
2119                 info->setattre.in.create_time = gen_timet();
2120                 info->setattre.in.access_time = gen_timet();
2121                 info->setattre.in.write_time = gen_timet();
2122                 break;
2123         case RAW_SFILEINFO_STANDARD:
2124                 info->standard.in.create_time = gen_timet();
2125                 info->standard.in.access_time = gen_timet();
2126                 info->standard.in.write_time = gen_timet();
2127                 break;
2128         case RAW_SFILEINFO_EA_SET: {
2129                 static struct ea_struct ea;
2130                 info->ea_set.in.num_eas = 1;
2131                 info->ea_set.in.eas = &ea;
2132                 info->ea_set.in.eas[0] = gen_ea_struct();
2133         }
2134                 break;
2135         case RAW_SFILEINFO_BASIC_INFO:
2136         case RAW_SFILEINFO_BASIC_INFORMATION:
2137                 info->basic_info.in.create_time = gen_nttime();
2138                 info->basic_info.in.access_time = gen_nttime();
2139                 info->basic_info.in.write_time = gen_nttime();
2140                 info->basic_info.in.change_time = gen_nttime();
2141                 info->basic_info.in.attrib = gen_attrib();
2142                 break;
2143         case RAW_SFILEINFO_DISPOSITION_INFO:
2144         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
2145                 info->disposition_info.in.delete_on_close = gen_bool();
2146                 break;
2147         case RAW_SFILEINFO_ALLOCATION_INFO:
2148         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
2149                 info->allocation_info.in.alloc_size = gen_alloc_size();
2150                 break;
2151         case RAW_SFILEINFO_END_OF_FILE_INFO:
2152         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
2153                 info->end_of_file_info.in.size = gen_offset();
2154                 break;
2155         case RAW_SFILEINFO_RENAME_INFORMATION:
2156         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
2157                 info->rename_information.in.overwrite = gen_bool();
2158                 info->rename_information.in.root_fid = gen_root_fid(instance);
2159                 info->rename_information.in.new_name = gen_fname_open(instance);
2160                 break;
2161         case RAW_SFILEINFO_POSITION_INFORMATION:
2162                 info->position_information.in.position = gen_offset();
2163                 break;
2164         case RAW_SFILEINFO_MODE_INFORMATION:
2165                 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
2166                 break;
2167         case RAW_SFILEINFO_GENERIC:
2168         case RAW_SFILEINFO_SEC_DESC:
2169         case RAW_SFILEINFO_UNIX_BASIC:
2170         case RAW_SFILEINFO_UNIX_LINK:
2171         case RAW_SFILEINFO_UNIX_HLINK:
2172         case RAW_SFILEINFO_1023:
2173         case RAW_SFILEINFO_1025:
2174         case RAW_SFILEINFO_1029:
2175         case RAW_SFILEINFO_1032:
2176         case RAW_SFILEINFO_1039:
2177         case RAW_SFILEINFO_1040:
2178         case RAW_SFILEINFO_UNIX_INFO2:
2179                 /* Untested */
2180                 break;
2181         }
2182 }
2183 #endif
2184
2185 /*
2186   generate a fileinfo query structure
2187 */
2188 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
2189 {
2190         int i;
2191         #undef LVL
2192         #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2193         struct levels {
2194                 enum smb_setfileinfo_level level;
2195                 const char *name;
2196         };
2197         struct levels smb_levels[] = {
2198                 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), 
2199                 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), 
2200                 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
2201                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
2202                 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
2203                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
2204                 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040),
2205         };
2206         struct levels smb2_levels[] = {
2207                 LVL(BASIC_INFORMATION),
2208                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
2209                 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
2210                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
2211                 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
2212         };
2213         struct levels *levels = options.smb2?smb2_levels:smb_levels;
2214         uint32_t num_levels = options.smb2?ARRAY_SIZE(smb2_levels):ARRAY_SIZE(smb_levels);
2215
2216         do {
2217                 i = gen_int_range(0, num_levels-1);
2218         } while (ignore_pattern(levels[i].name));
2219         
2220         info->generic.level = levels[i].level;
2221
2222         switch (info->generic.level) {
2223         case RAW_SFILEINFO_SETATTR:
2224                 info->setattr.in.attrib = gen_attrib();
2225                 info->setattr.in.write_time = gen_timet();
2226                 break;
2227         case RAW_SFILEINFO_SETATTRE:
2228                 info->setattre.in.create_time = gen_timet();
2229                 info->setattre.in.access_time = gen_timet();
2230                 info->setattre.in.write_time = gen_timet();
2231                 break;
2232         case RAW_SFILEINFO_STANDARD:
2233                 info->standard.in.create_time = gen_timet();
2234                 info->standard.in.access_time = gen_timet();
2235                 info->standard.in.write_time = gen_timet();
2236                 break;
2237         case RAW_SFILEINFO_EA_SET: {
2238                 static struct ea_struct ea;
2239                 info->ea_set.in.num_eas = 1;
2240                 info->ea_set.in.eas = &ea;
2241                 info->ea_set.in.eas[0] = gen_ea_struct();
2242                 break;
2243         }
2244         case RAW_SFILEINFO_BASIC_INFO:
2245         case RAW_SFILEINFO_BASIC_INFORMATION:
2246                 info->basic_info.in.create_time = gen_nttime();
2247                 info->basic_info.in.access_time = gen_nttime();
2248                 info->basic_info.in.write_time = gen_nttime();
2249                 info->basic_info.in.change_time = gen_nttime();
2250                 info->basic_info.in.attrib = gen_attrib();
2251                 break;
2252         case RAW_SFILEINFO_DISPOSITION_INFO:
2253         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
2254                 info->disposition_info.in.delete_on_close = gen_bool();
2255                 break;
2256         case RAW_SFILEINFO_ALLOCATION_INFO:
2257         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
2258                 info->allocation_info.in.alloc_size = gen_alloc_size();
2259                 break;
2260         case RAW_SFILEINFO_END_OF_FILE_INFO:
2261         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
2262                 info->end_of_file_info.in.size = gen_offset();
2263                 break;
2264         case RAW_SFILEINFO_RENAME_INFORMATION:
2265         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
2266                 info->rename_information.in.overwrite = gen_bool();
2267                 info->rename_information.in.root_fid = gen_root_fid(instance);
2268                 info->rename_information.in.new_name = gen_fname_open(instance);
2269                 break;
2270         case RAW_SFILEINFO_POSITION_INFORMATION:
2271                 info->position_information.in.position = gen_offset();
2272                 break;
2273         case RAW_SFILEINFO_MODE_INFORMATION:
2274                 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
2275                 break;
2276
2277         case RAW_SFILEINFO_GENERIC:
2278         case RAW_SFILEINFO_SEC_DESC:
2279         case RAW_SFILEINFO_1023:
2280         case RAW_SFILEINFO_1025:
2281         case RAW_SFILEINFO_1029:
2282         case RAW_SFILEINFO_1032:
2283         case RAW_SFILEINFO_1039:
2284         case RAW_SFILEINFO_1040:
2285         case RAW_SFILEINFO_UNIX_BASIC:
2286         case RAW_SFILEINFO_UNIX_INFO2:
2287         case RAW_SFILEINFO_UNIX_LINK:
2288         case RAW_SFILEINFO_UNIX_HLINK:
2289                 /* Untested */
2290                 break;
2291         }
2292 }
2293
2294
2295
2296 /*
2297   generate a fileinfo query structure
2298 */
2299 static void gen_fileinfo_smb(int instance, union smb_fileinfo *info)
2300 {
2301         int i;
2302         #undef LVL
2303         #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2304         struct {
2305                 enum smb_fileinfo_level level;
2306                 const char *name;
2307         }  levels[] = {
2308                 LVL(GETATTR), LVL(GETATTRE), LVL(STANDARD),
2309                 LVL(EA_SIZE), LVL(ALL_EAS), LVL(IS_NAME_VALID),
2310                 LVL(BASIC_INFO), LVL(STANDARD_INFO), LVL(EA_INFO),
2311                 LVL(NAME_INFO), LVL(ALL_INFO), LVL(ALT_NAME_INFO),
2312                 LVL(STREAM_INFO), LVL(COMPRESSION_INFO), LVL(BASIC_INFORMATION),
2313                 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
2314                 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
2315                 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(ALL_INFORMATION),
2316                 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
2317                 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION)
2318         };
2319         do {
2320                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2321         } while (ignore_pattern(levels[i].name));
2322
2323         info->generic.level = levels[i].level;
2324 }
2325
2326 /*
2327   generate qpathinfo operations
2328 */
2329 static bool handler_smb_qpathinfo(int instance)
2330 {
2331         union smb_fileinfo parm[NSERVERS];
2332         NTSTATUS status[NSERVERS];
2333
2334         parm[0].generic.in.file.path = gen_fname_open(instance);
2335
2336         gen_fileinfo_smb(instance, &parm[0]);
2337
2338         GEN_COPY_PARM;
2339         GEN_CALL_SMB(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i]));
2340
2341         return cmp_fileinfo(instance, parm, status);
2342 }
2343
2344 /*
2345   generate qfileinfo operations
2346 */
2347 static bool handler_smb_qfileinfo(int instance)
2348 {
2349         union smb_fileinfo parm[NSERVERS];
2350         NTSTATUS status[NSERVERS];
2351
2352         parm[0].generic.in.file.fnum = gen_fnum(instance);
2353
2354         gen_fileinfo_smb(instance, &parm[0]);
2355
2356         GEN_COPY_PARM;
2357         GEN_SET_FNUM_SMB(generic.in.file.fnum);
2358         GEN_CALL_SMB(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i]));
2359
2360         return cmp_fileinfo(instance, parm, status);
2361 }
2362
2363
2364 /*
2365   generate setpathinfo operations
2366 */
2367 static bool handler_smb_spathinfo(int instance)
2368 {
2369         union smb_setfileinfo parm[NSERVERS];
2370         NTSTATUS status[NSERVERS];
2371
2372         parm[0].generic.in.file.path = gen_fname_open(instance);
2373
2374         gen_setfileinfo(instance, &parm[0]);
2375
2376         GEN_COPY_PARM;
2377
2378         /* a special case for the fid in a RENAME */
2379         if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION &&
2380             parm[0].rename_information.in.root_fid != 0) {
2381                 GEN_SET_FNUM_SMB(rename_information.in.root_fid);
2382         }
2383
2384         GEN_CALL_SMB(smb_raw_setpathinfo(tree, &parm[i]));
2385
2386         return true;
2387 }
2388
2389
2390 /*
2391   generate setfileinfo operations
2392 */
2393 static bool handler_smb_sfileinfo(int instance)
2394 {
2395         union smb_setfileinfo parm[NSERVERS];
2396         NTSTATUS status[NSERVERS];
2397
2398         parm[0].generic.in.file.fnum = gen_fnum(instance);
2399
2400         gen_setfileinfo(instance, &parm[0]);
2401
2402         GEN_COPY_PARM;
2403         GEN_SET_FNUM_SMB(generic.in.file.fnum);
2404         GEN_CALL_SMB(smb_raw_setfileinfo(tree, &parm[i]));
2405
2406         return true;
2407 }
2408
2409
2410 /*
2411   this is called when a change notify reply comes in
2412 */
2413 static void async_notify_smb(struct smbcli_request *req)
2414 {
2415         union smb_notify notify;
2416         NTSTATUS status;
2417         int i, j;
2418         uint16_t tid;
2419         struct smbcli_transport *transport = req->transport;
2420
2421         tid = SVAL(req->in.hdr, HDR_TID);
2422
2423         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
2424         status = smb_raw_changenotify_recv(req, current_op.mem_ctx, &notify);
2425         if (NT_STATUS_IS_OK(status) && notify.nttrans.out.num_changes > 0) {
2426                 printf("notify tid=%d num_changes=%d action=%d name=%s\n", 
2427                        tid, 
2428                        notify.nttrans.out.num_changes,
2429                        notify.nttrans.out.changes[0].action,
2430                        notify.nttrans.out.changes[0].name.s);
2431         }
2432
2433         for (i=0;i<NSERVERS;i++) {
2434                 for (j=0;j<NINSTANCES;j++) {
2435                         if (transport == servers[i].smb_tree[j]->session->transport &&
2436                             tid == servers[i].smb_tree[j]->tid) {
2437                                 notifies[i][j].notify_count++;
2438                                 notifies[i][j].status = status;
2439                                 notifies[i][j].notify = notify;
2440                         }
2441                 }
2442         }
2443 }
2444
2445 /*
2446   generate change notify operations
2447 */
2448 static bool handler_smb_notify(int instance)
2449 {
2450         union smb_notify parm[NSERVERS];
2451         int n;
2452
2453         ZERO_STRUCT(parm[0]);
2454         parm[0].nttrans.level                   = RAW_NOTIFY_NTTRANS;
2455         parm[0].nttrans.in.buffer_size          = gen_io_count();
2456         parm[0].nttrans.in.completion_filter    = gen_bits_mask(0xFF);
2457         parm[0].nttrans.in.file.fnum            = gen_fnum(instance);
2458         parm[0].nttrans.in.recursive            = gen_bool();
2459
2460         GEN_COPY_PARM;
2461         GEN_SET_FNUM_SMB(nttrans.in.file.fnum);
2462
2463         for (n=0;n<NSERVERS;n++) {
2464                 struct smbcli_request *req;
2465                 req = smb_raw_changenotify_send(servers[n].smb_tree[instance], &parm[n]);
2466                 req->async.fn = async_notify_smb;
2467         }
2468
2469         return true;
2470 }
2471
2472
2473 /*
2474   generate ntcreatex operations
2475 */
2476 static bool handler_smb2_create(int instance)
2477 {
2478         struct smb2_create parm[NSERVERS];
2479         NTSTATUS status[NSERVERS];
2480
2481         ZERO_STRUCT(parm[0]);
2482         parm[0].in.security_flags             = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF);
2483         parm[0].in.oplock_level               = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF);
2484         parm[0].in.impersonation_level        = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF);
2485         parm[0].in.create_flags               = gen_reserved64();
2486         parm[0].in.reserved                   = gen_reserved64();
2487         parm[0].in.desired_access             = gen_access_mask();
2488         parm[0].in.file_attributes            = gen_attrib();
2489         parm[0].in.share_access               = gen_bits_mask2(0x7, 0xFFFFFFFF);
2490         parm[0].in.create_disposition         = gen_open_disp();
2491         parm[0].in.create_options             = gen_create_options();
2492         parm[0].in.fname                      = gen_fname_open(instance);
2493         parm[0].in.eas                        = gen_ea_list();
2494         parm[0].in.alloc_size                 = gen_alloc_size();
2495         parm[0].in.durable_open               = gen_bool();
2496         parm[0].in.query_maximal_access       = gen_bool();
2497         parm[0].in.timewarp                   = gen_timewarp();
2498         parm[0].in.query_on_disk_id           = gen_bool();
2499         parm[0].in.sec_desc                   = gen_sec_desc();
2500
2501         if (!options.use_oplocks) {
2502                 /* mask out oplocks */
2503                 parm[0].in.oplock_level = 0;
2504         }
2505
2506         if (options.valid) {
2507                 parm[0].in.security_flags   &= 3;
2508                 parm[0].in.oplock_level     &= 9;
2509                 parm[0].in.impersonation_level &= 3;
2510         }
2511
2512         GEN_COPY_PARM;
2513         GEN_CALL_SMB2(smb2_create(tree, current_op.mem_ctx, &parm[i]));
2514
2515         CHECK_EQUAL(out.oplock_level);
2516         CHECK_EQUAL(out.reserved);
2517         CHECK_EQUAL(out.create_action);
2518         CHECK_NTTIMES_EQUAL(out.create_time);
2519         CHECK_NTTIMES_EQUAL(out.access_time);
2520         CHECK_NTTIMES_EQUAL(out.write_time);
2521         CHECK_NTTIMES_EQUAL(out.change_time);
2522         CHECK_EQUAL(out.alloc_size);
2523         CHECK_EQUAL(out.size);
2524         CHECK_ATTRIB(out.file_attr);
2525         CHECK_EQUAL(out.reserved2);
2526         CHECK_EQUAL(out.maximal_access);
2527
2528         /* ntcreatex creates a new file handle */
2529         ADD_HANDLE_SMB2(parm[0].in.fname, out.file.handle);
2530
2531         return true;
2532 }
2533
2534 /*
2535   generate close operations
2536 */
2537 static bool handler_smb2_close(int instance)
2538 {
2539         struct smb2_close parm[NSERVERS];
2540         NTSTATUS status[NSERVERS];
2541
2542         ZERO_STRUCT(parm[0]);
2543         parm[0].in.file.handle.data[0] = gen_fnum_close(instance);
2544         parm[0].in.flags               = gen_bits_mask2(0x1, 0xFFFF);
2545
2546         GEN_COPY_PARM;
2547         GEN_SET_FNUM_SMB2(in.file.handle);
2548         GEN_CALL_SMB2(smb2_close(tree, &parm[i]));
2549
2550         CHECK_EQUAL(out.flags);
2551         CHECK_EQUAL(out._pad);
2552         CHECK_NTTIMES_EQUAL(out.create_time);
2553         CHECK_NTTIMES_EQUAL(out.access_time);
2554         CHECK_NTTIMES_EQUAL(out.write_time);
2555         CHECK_NTTIMES_EQUAL(out.change_time);
2556         CHECK_EQUAL(out.alloc_size);
2557         CHECK_EQUAL(out.size);
2558         CHECK_ATTRIB(out.file_attr);
2559
2560         REMOVE_HANDLE_SMB2(in.file.handle);
2561
2562         return true;
2563 }
2564
2565 /*
2566   generate read operations
2567 */
2568 static bool handler_smb2_read(int instance)
2569 {
2570         struct smb2_read parm[NSERVERS];
2571         NTSTATUS status[NSERVERS];
2572
2573         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2574         parm[0].in.reserved    = gen_reserved8();
2575         parm[0].in.length      = gen_io_count();
2576         parm[0].in.offset      = gen_offset();
2577         parm[0].in.min_count   = gen_io_count();
2578         parm[0].in.channel     = gen_bits_mask2(0x0, 0xFFFFFFFF);
2579         parm[0].in.remaining   = gen_bits_mask2(0x0, 0xFFFFFFFF);
2580         parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF);
2581         parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF);
2582
2583         GEN_COPY_PARM;
2584         GEN_SET_FNUM_SMB2(in.file.handle);
2585         GEN_CALL_SMB2(smb2_read(tree, current_op.mem_ctx, &parm[i]));
2586
2587         CHECK_EQUAL(out.remaining);
2588         CHECK_EQUAL(out.reserved);
2589         CHECK_EQUAL(out.data.length);
2590
2591         return true;
2592 }
2593
2594 /*
2595   generate write operations
2596 */
2597 static bool handler_smb2_write(int instance)
2598 {
2599         struct smb2_write parm[NSERVERS];
2600         NTSTATUS status[NSERVERS];
2601
2602         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2603         parm[0].in.offset = gen_offset();
2604         parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF);
2605         parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF);
2606         parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL,
2607                                             gen_io_count());
2608
2609         GEN_COPY_PARM;
2610         GEN_SET_FNUM_SMB2(in.file.handle);
2611         GEN_CALL_SMB2(smb2_write(tree, &parm[i]));
2612
2613         CHECK_EQUAL(out._pad);
2614         CHECK_EQUAL(out.nwritten);
2615         CHECK_EQUAL(out.unknown1);
2616
2617         return true;
2618 }
2619
2620 /*
2621   generate lockingx operations
2622 */
2623 static bool handler_smb2_lock(int instance)
2624 {
2625         struct smb2_lock parm[NSERVERS];
2626         NTSTATUS status[NSERVERS];
2627         int n;
2628
2629         parm[0].level = RAW_LOCK_LOCKX;
2630         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2631         parm[0].in.lock_count = gen_lock_count();
2632         parm[0].in.reserved = gen_reserved32();
2633         
2634         parm[0].in.locks = talloc_array(current_op.mem_ctx,
2635                                         struct smb2_lock_element,
2636                                         parm[0].in.lock_count);
2637         for (n=0;n<parm[0].in.lock_count;n++) {
2638                 parm[0].in.locks[n].offset = gen_offset();
2639                 parm[0].in.locks[n].length = gen_io_count();
2640                 /* don't yet cope with async replies */
2641                 parm[0].in.locks[n].flags  = gen_lock_flags_smb2() | 
2642                         SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2643                 parm[0].in.locks[n].reserved = gen_bits_mask2(0x0, 0xFFFFFFFF);
2644         }
2645
2646         GEN_COPY_PARM;
2647         GEN_SET_FNUM_SMB2(in.file.handle);
2648         GEN_CALL_SMB2(smb2_lock(tree, &parm[i]));
2649
2650         return true;
2651 }
2652
2653 /*
2654   generate flush operations
2655 */
2656 static bool handler_smb2_flush(int instance)
2657 {
2658         struct smb2_flush parm[NSERVERS];
2659         NTSTATUS status[NSERVERS];
2660
2661         ZERO_STRUCT(parm[0]);
2662         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2663         parm[0].in.reserved1  = gen_reserved16();
2664         parm[0].in.reserved2  = gen_reserved32();
2665
2666         GEN_COPY_PARM;
2667         GEN_SET_FNUM_SMB2(in.file.handle);
2668         GEN_CALL_SMB2(smb2_flush(tree, &parm[i]));
2669
2670         CHECK_EQUAL(out.reserved);
2671
2672         return true;
2673 }
2674
2675 /*
2676   generate echo operations
2677 */
2678 static bool handler_smb2_echo(int instance)
2679 {
2680         NTSTATUS status[NSERVERS];
2681
2682         GEN_CALL_SMB2(smb2_keepalive(tree->session->transport));
2683
2684         return true;
2685 }
2686
2687
2688
2689 /*
2690   generate a fileinfo query structure
2691 */
2692 static void gen_fileinfo_smb2(int instance, union smb_fileinfo *info)
2693 {
2694         int i;
2695         #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2696         struct {
2697                 enum smb_fileinfo_level level;
2698                 const char *name;
2699         }  levels[] = {
2700                 LVL(BASIC_INFORMATION),
2701                 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
2702                 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
2703                 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION),
2704                 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
2705                 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION),
2706                 LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC),
2707         };
2708         do {
2709                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2710         } while (ignore_pattern(levels[i].name));
2711
2712         info->generic.level = levels[i].level;
2713 }
2714
2715 /*
2716   generate qfileinfo operations
2717 */
2718 static bool handler_smb2_qfileinfo(int instance)
2719 {
2720         union smb_fileinfo parm[NSERVERS];
2721         NTSTATUS status[NSERVERS];
2722
2723         parm[0].generic.in.file.handle.data[0] = gen_fnum(instance);
2724
2725         gen_fileinfo_smb2(instance, &parm[0]);
2726
2727         GEN_COPY_PARM;
2728         GEN_SET_FNUM_SMB2(generic.in.file.handle);
2729         GEN_CALL_SMB2(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i]));
2730
2731         return cmp_fileinfo(instance, parm, status);
2732 }
2733
2734
2735 /*
2736   generate setfileinfo operations
2737 */
2738 static bool handler_smb2_sfileinfo(int instance)
2739 {
2740         union smb_setfileinfo parm[NSERVERS];
2741         NTSTATUS status[NSERVERS];
2742
2743         parm[0].generic.in.file.fnum = gen_fnum(instance);
2744
2745         gen_setfileinfo(instance, &parm[0]);
2746
2747         GEN_COPY_PARM;
2748         GEN_SET_FNUM_SMB2(generic.in.file.handle);
2749         GEN_CALL_SMB2(smb2_setinfo_file(tree, &parm[i]));
2750
2751         return true;
2752 }
2753
2754 /*
2755   wipe any relevant files
2756 */
2757 static void wipe_files(void)
2758 {
2759         int i;
2760         NTSTATUS status;
2761
2762         if (options.skip_cleanup) {
2763                 return;
2764         }
2765
2766         for (i=0;i<NSERVERS;i++) {
2767                 int n;
2768                 if (options.smb2) {
2769                         n = smb2_deltree(servers[i].smb2_tree[0], "gentest");
2770                 } else {
2771                         n = smbcli_deltree(servers[i].smb_tree[0], "gentest");
2772                 }
2773                 if (n == -1) {
2774                         printf("Failed to wipe tree on server %d\n", i);
2775                         exit(1);
2776                 }
2777                 if (options.smb2) {
2778                         status = smb2_util_mkdir(servers[i].smb2_tree[0], "gentest");
2779                 } else {
2780                         status = smbcli_mkdir(servers[i].smb_tree[0], "gentest");
2781                 }
2782                 if (NT_STATUS_IS_ERR(status)) {
2783                         printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status));
2784                         exit(1);
2785                 }
2786                 if (n > 0) {
2787                         printf("Deleted %d files on server %d\n", n, i);
2788                 }
2789         }
2790 }
2791
2792 /*
2793   dump the current seeds - useful for continuing a backtrack
2794 */
2795 static void dump_seeds(void)
2796 {
2797         int i;
2798         FILE *f;
2799
2800         if (!options.seeds_file) {
2801                 return;
2802         }
2803         f = fopen("seeds.tmp", "w");
2804         if (!f) return;
2805
2806         for (i=0;i<options.numops;i++) {
2807                 fprintf(f, "%u\n", op_parms[i].seed);
2808         }
2809         fclose(f);
2810         rename("seeds.tmp", options.seeds_file);
2811 }
2812
2813
2814
2815 /*
2816   the list of top-level operations that we will generate
2817 */
2818 static struct {
2819         const char *name;
2820         bool (*handler)(int instance);
2821         bool smb2;
2822         int count, success_count;
2823 } gen_ops[] = {
2824         {"CREATE",     handler_smb2_create,     true},
2825         {"CLOSE",      handler_smb2_close,      true},
2826         {"READ",       handler_smb2_read,       true},
2827         {"WRITE",      handler_smb2_write,      true},
2828         {"LOCK",       handler_smb2_lock,       true},
2829         {"FLUSH",      handler_smb2_flush,      true},
2830         {"ECHO",       handler_smb2_echo,       true},
2831         {"QFILEINFO",  handler_smb2_qfileinfo,  true},
2832         {"SFILEINFO",  handler_smb2_sfileinfo,  true},
2833
2834         {"OPEN",       handler_smb_open,        false},
2835         {"OPENX",      handler_smb_openx,       false},
2836         {"NTCREATEX",  handler_smb_ntcreatex,   false},
2837         {"CLOSE",      handler_smb_close,       false},
2838         {"UNLINK",     handler_smb_unlink,      false},
2839         {"MKDIR",      handler_smb_mkdir,       false},
2840         {"RMDIR",      handler_smb_rmdir,       false},
2841         {"RENAME",     handler_smb_rename,      false},
2842         {"NTRENAME",   handler_smb_ntrename,    false},
2843         {"READX",      handler_smb_readx,       false},
2844         {"WRITEX",     handler_smb_writex,      false},
2845         {"CHKPATH",    handler_smb_chkpath,     false},
2846         {"SEEK",       handler_smb_seek,        false},
2847         {"LOCKINGX",   handler_smb_lockingx,    false},
2848         {"QPATHINFO",  handler_smb_qpathinfo,   false},
2849         {"QFILEINFO",  handler_smb_qfileinfo,   false},
2850         {"SPATHINFO",  handler_smb_spathinfo,   false},
2851         {"SFILEINFO",  handler_smb_sfileinfo,   false},
2852         {"NOTIFY",     handler_smb_notify,      false},
2853         {"SEEK",       handler_smb_seek,        false},
2854 };
2855
2856
2857 /*
2858   run the test with the current set of op_parms parameters
2859   return the number of operations that completed successfully
2860 */
2861 static int run_test(struct event_context *ev, struct loadparm_context *lp_ctx)
2862 {
2863         int op, i;
2864
2865         if (!connect_servers(ev, lp_ctx)) {
2866                 printf("Failed to connect to servers\n");
2867                 exit(1);
2868         }
2869
2870         dump_seeds();
2871
2872         /* wipe any leftover files from old runs */
2873         wipe_files();
2874
2875         /* reset the open handles array */
2876         memset(open_handles, 0, options.max_open_handles * sizeof(open_handles[0]));
2877         num_open_handles = 0;
2878
2879         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
2880                 gen_ops[i].count = 0;
2881                 gen_ops[i].success_count = 0;
2882         }
2883
2884         for (op=0; op<options.numops; op++) {
2885                 int instance, which_op;
2886                 bool ret;
2887
2888                 if (op_parms[op].disabled) continue;
2889
2890                 srandom(op_parms[op].seed);
2891
2892                 instance = gen_int_range(0, NINSTANCES-1);
2893
2894                 /* generate a non-ignored operation */
2895                 do {
2896                         which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1);
2897                 } while (ignore_pattern(gen_ops[which_op].name) ||
2898                          gen_ops[which_op].smb2 != options.smb2);
2899
2900                 DEBUG(3,("Generating op %s on instance %d\n",
2901                          gen_ops[which_op].name, instance));
2902
2903                 current_op.seed = op_parms[op].seed;
2904                 current_op.opnum = op;
2905                 current_op.name = gen_ops[which_op].name;
2906                 current_op.status = NT_STATUS_OK;
2907                 current_op.mem_ctx = talloc_named(NULL, 0, "%s", current_op.name);
2908
2909                 ret = gen_ops[which_op].handler(instance);
2910
2911                 talloc_free(current_op.mem_ctx);
2912
2913                 gen_ops[which_op].count++;
2914                 if (NT_STATUS_IS_OK(current_op.status)) {
2915                         gen_ops[which_op].success_count++;                      
2916                 }
2917
2918                 if (!ret) {
2919                         printf("Failed at operation %d - %s\n",
2920                                op, gen_ops[which_op].name);
2921                         return op;
2922                 }
2923
2924                 if (op % 100 == 0) {
2925                         printf("%d\n", op);
2926                 }
2927         }
2928
2929         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
2930                 printf("Op %-10s got %d/%d success\n", 
2931                        gen_ops[i].name,
2932                        gen_ops[i].success_count,
2933                        gen_ops[i].count);
2934         }
2935
2936         return op;
2937 }
2938
2939 /* 
2940    perform a backtracking analysis of the minimal set of operations
2941    to generate an error
2942 */
2943 static void backtrack_analyze(struct event_context *ev,
2944                               struct loadparm_context *lp_ctx)
2945 {
2946         int chunk, ret;
2947         const char *mismatch = current_op.mismatch;
2948
2949         chunk = options.numops / 2;
2950
2951         do {
2952                 int base;
2953                 for (base=0; 
2954                      chunk > 0 && base+chunk < options.numops && options.numops > 1; ) {
2955                         int i, max;
2956
2957                         chunk = MIN(chunk, options.numops / 2);
2958
2959                         /* mark this range as disabled */
2960                         max = MIN(options.numops, base+chunk);
2961                         for (i=base;i<max; i++) {
2962                                 op_parms[i].disabled = true;
2963                         }
2964                         printf("Testing %d ops with %d-%d disabled\n", 
2965                                options.numops, base, max-1);
2966                         ret = run_test(ev, lp_ctx);
2967                         printf("Completed %d of %d ops\n", ret, options.numops);
2968                         for (i=base;i<max; i++) {
2969                                 op_parms[i].disabled = false;
2970                         }
2971                         if (ret == options.numops) {
2972                                 /* this chunk is needed */
2973                                 base += chunk;
2974                         } else if (mismatch != current_op.mismatch &&
2975                                    strcmp(mismatch, current_op.mismatch)) {
2976                                 base += chunk;
2977                                 printf("Different error in backtracking\n");
2978                         } else if (ret < base) {
2979                                 printf("damn - inconsistent errors! found early error\n");
2980                                 options.numops = ret+1;
2981                                 base = 0;
2982                         } else {
2983                                 /* it failed - this chunk isn't needed for a failure */
2984                                 memmove(&op_parms[base], &op_parms[max], 
2985                                         sizeof(op_parms[0]) * (options.numops - max));
2986                                 options.numops = (ret+1) - (max - base);
2987                         }
2988                 }
2989
2990                 if (chunk == 2) {
2991                         chunk = 1;
2992                 } else {
2993                         chunk *= 0.4;
2994                 }
2995
2996                 if (options.analyze_continuous && chunk == 0 && options.numops != 1) {
2997                         chunk = 1;
2998                 }
2999         } while (chunk > 0);
3000
3001         printf("Reduced to %d ops\n", options.numops);
3002         ret = run_test(ev, lp_ctx);
3003         if (ret != options.numops - 1) {
3004                 printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops);
3005         }
3006 }
3007
3008 /* 
3009    start the main gentest process
3010 */
3011 static bool start_gentest(struct event_context *ev,
3012                           struct loadparm_context *lp_ctx)
3013 {
3014         int op;
3015         int ret;
3016
3017         /* allocate the open_handles array */
3018         open_handles = calloc(options.max_open_handles, sizeof(open_handles[0]));
3019
3020         srandom(options.seed);
3021         op_parms = calloc(options.numops, sizeof(op_parms[0]));
3022
3023         /* generate the seeds - after this everything is deterministic */
3024         if (options.use_preset_seeds) {
3025                 int numops;
3026                 char **preset = file_lines_load(options.seeds_file, &numops, NULL);
3027                 if (!preset) {
3028                         printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno));
3029                         exit(1);
3030                 }
3031                 if (numops < options.numops) {
3032                         options.numops = numops;
3033                 }
3034                 for (op=0;op<options.numops;op++) {
3035                         if (!preset[op]) {
3036                                 printf("Not enough seeds in %s\n", options.seeds_file);
3037                                 exit(1);
3038                         }
3039                         op_parms[op].seed = atoi(preset[op]);
3040                 }
3041                 printf("Loaded %d seeds from %s\n", options.numops, options.seeds_file);
3042         } else {
3043                 for (op=0; op<options.numops; op++) {
3044                         op_parms[op].seed = random();
3045                 }
3046         }
3047
3048         ret = run_test(ev, lp_ctx);
3049
3050         if (ret != options.numops && options.analyze) {
3051                 options.numops = ret+1;
3052                 backtrack_analyze(ev, lp_ctx);
3053         } else if (options.analyze_always) {
3054                 backtrack_analyze(ev, lp_ctx);
3055         } else if (options.analyze_continuous) {
3056                 while (run_test(ev, lp_ctx) == options.numops) ;
3057         }
3058
3059         return ret == options.numops;
3060 }
3061
3062
3063 static void usage(poptContext pc)
3064 {
3065         printf(
3066 "Usage:\n\
3067   gentest //server1/share1 //server2/share2 [options..]\n\
3068 ");
3069         poptPrintUsage(pc, stdout, 0);
3070 }
3071
3072 /**
3073   split a UNC name into server and share names
3074 */
3075 static bool split_unc_name(const char *unc, char **server, char **share)
3076 {
3077         char *p = strdup(unc);
3078         if (!p) return false;
3079         all_string_sub(p, "\\", "/", 0);
3080         if (strncmp(p, "//", 2) != 0) return false;
3081
3082         (*server) = p+2;
3083         p = strchr(*server, '/');
3084         if (!p) return false;
3085
3086         *p = 0;
3087         (*share) = p+1;
3088         
3089         return true;
3090 }
3091
3092
3093
3094 /****************************************************************************
3095   main program
3096 ****************************************************************************/
3097  int main(int argc, char *argv[])
3098 {
3099         int opt;
3100         int i, username_count=0;
3101         bool ret;
3102         char *ignore_file=NULL;
3103         struct event_context *ev;
3104         struct loadparm_context *lp_ctx;
3105         poptContext pc;
3106         int argc_new;
3107         char **argv_new;
3108         enum {OPT_UNCLIST=1000};
3109         struct poptOption long_options[] = {
3110                 POPT_AUTOHELP
3111                 {"smb2",          0, POPT_ARG_NONE, &options.smb2, 0,   "use SMB2 protocol",    NULL},
3112                 {"seed",          0, POPT_ARG_INT,  &options.seed,      0,      "Seed to use for randomizer",   NULL},
3113                 {"num-ops",       0, POPT_ARG_INT,  &options.numops,    0,      "num ops",      NULL},
3114                 {"oplocks",       0, POPT_ARG_NONE, &options.use_oplocks,0,      "use oplocks", NULL},
3115                 {"showall",       0, POPT_ARG_NONE, &options.showall,    0,      "display all operations", NULL},
3116                 {"analyse",       0, POPT_ARG_NONE, &options.analyze,    0,      "do backtrack analysis", NULL},
3117                 {"analysealways", 0, POPT_ARG_NONE, &options.analyze_always,    0,      "analysis always", NULL},
3118                 {"analysecontinuous", 0, POPT_ARG_NONE, &options.analyze_continuous,    0,      "analysis continuous", NULL},
3119                 {"ignore",        0, POPT_ARG_STRING, &ignore_file,    0,      "ignore from file", NULL},
3120                 {"preset",        0, POPT_ARG_NONE, &options.use_preset_seeds,    0,      "use preset seeds", NULL},
3121                 {"fast",          0, POPT_ARG_NONE, &options.fast_reconnect,    0,      "use fast reconnect", NULL},
3122                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
3123                 {"seedsfile",     0, POPT_ARG_STRING,  &options.seeds_file, 0,  "seed file",    NULL},
3124                 { "user", 'U',       POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
3125                 {"maskindexing",  0, POPT_ARG_NONE,  &options.mask_indexing, 0, "mask out the indexed file attrib",     NULL},
3126                 {"noeas",  0, POPT_ARG_NONE,  &options.no_eas, 0,       "don't use extended attributes",        NULL},
3127                 {"noacls",  0, POPT_ARG_NONE,  &options.no_acls, 0,     "don't use ACLs",       NULL},
3128                 {"skip-cleanup",  0, POPT_ARG_NONE,  &options.skip_cleanup, 0,  "don't delete files at start",  NULL},
3129                 {"valid",  0, POPT_ARG_NONE,  &options.valid, 0,        "generate only valid fields",   NULL},
3130                 POPT_COMMON_SAMBA
3131                 POPT_COMMON_CONNECTION
3132                 POPT_COMMON_CREDENTIALS
3133                 POPT_COMMON_VERSION
3134                 { NULL }
3135         };
3136
3137         memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle));
3138
3139         setlinebuf(stdout);
3140         options.seed = time(NULL);
3141         options.numops = 1000;
3142         options.max_open_handles = 20;
3143         options.seeds_file = "gentest_seeds.dat";
3144
3145         pc = poptGetContext("gentest", argc, (const char **) argv, long_options, 
3146                             POPT_CONTEXT_KEEP_FIRST);
3147
3148         poptSetOtherOptionHelp(pc, "<unc1> <unc2>");
3149
3150         lp_ctx = cmdline_lp_ctx;
3151         servers[0].credentials = cli_credentials_init(talloc_autofree_context());
3152         servers[1].credentials = cli_credentials_init(talloc_autofree_context());
3153         cli_credentials_guess(servers[0].credentials, lp_ctx);
3154         cli_credentials_guess(servers[1].credentials, lp_ctx);
3155
3156         while((opt = poptGetNextOpt(pc)) != -1) {
3157                 switch (opt) {
3158                 case OPT_UNCLIST:
3159                         lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
3160                         break;
3161                 case 'U':
3162                         if (username_count == 2) {
3163                                 usage(pc);
3164                                 exit(1);
3165                         }
3166                         cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED);
3167                         username_count++;
3168                         break;
3169                 }
3170         }
3171
3172         if (ignore_file) {
3173                 options.ignore_patterns = file_lines_load(ignore_file, NULL, NULL);
3174         }
3175
3176         argv_new = discard_const_p(char *, poptGetArgs(pc));
3177         argc_new = argc;
3178         for (i=0; i<argc; i++) {
3179                 if (argv_new[i] == NULL) {
3180                         argc_new = i;
3181                         break;
3182                 }
3183         }
3184
3185         if (!(argc_new >= 3)) {
3186                 usage(pc);
3187                 exit(1);
3188         }
3189
3190         setlinebuf(stdout);
3191
3192         setup_logging("gentest", DEBUG_STDOUT);
3193
3194         if (argc < 3 || argv[1][0] == '-') {
3195                 usage(pc);
3196                 exit(1);
3197         }
3198
3199         setup_logging(argv[0], DEBUG_STDOUT);
3200
3201         for (i=0;i<NSERVERS;i++) {
3202                 const char *share = argv[1+i];
3203                 if (!split_unc_name(share, &servers[i].server_name, &servers[i].share_name)) {
3204                         printf("Invalid share name '%s'\n", share);
3205                         return -1;
3206                 }
3207         }
3208
3209         if (username_count == 0) {
3210                 usage(pc);
3211                 return -1;
3212         }
3213         if (username_count == 1) {
3214                 servers[1].credentials = servers[0].credentials;
3215         }
3216
3217         printf("seed=%u\n", options.seed);
3218
3219         ev = event_context_init(talloc_autofree_context());
3220
3221         gensec_init(lp_ctx);
3222
3223         ret = start_gentest(ev, lp_ctx);
3224
3225         if (ret) {
3226                 printf("gentest completed - no errors\n");
3227         } else {
3228                 printf("gentest failed\n");
3229         }
3230
3231         return ret?0:-1;
3232 }