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