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