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