a832c597379d57474a80728efe602cbdc180c72b
[samba.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/cmdline.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         case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION:
1644                 CHECK_WSTR_EQUAL(alt_name_info.out.fname);
1645                 break;
1646
1647         case RAW_FILEINFO_STREAM_INFO:
1648         case RAW_FILEINFO_STREAM_INFORMATION:
1649                 CHECK_EQUAL(stream_info.out.num_streams);
1650                 for (i=0;i<parm[0].stream_info.out.num_streams;i++) {
1651                         CHECK_EQUAL(stream_info.out.streams[i].size);
1652                         CHECK_EQUAL(stream_info.out.streams[i].alloc_size);
1653                         CHECK_WSTR_EQUAL(stream_info.out.streams[i].stream_name);
1654                 }
1655                 break;
1656
1657         case RAW_FILEINFO_COMPRESSION_INFO:
1658         case RAW_FILEINFO_COMPRESSION_INFORMATION:
1659                 CHECK_EQUAL(compression_info.out.compressed_size);
1660                 CHECK_EQUAL(compression_info.out.format);
1661                 CHECK_EQUAL(compression_info.out.unit_shift);
1662                 CHECK_EQUAL(compression_info.out.chunk_shift);
1663                 CHECK_EQUAL(compression_info.out.cluster_shift);
1664                 break;
1665
1666         case RAW_FILEINFO_INTERNAL_INFORMATION:
1667                 CHECK_EQUAL(internal_information.out.file_id);
1668                 break;
1669
1670         case RAW_FILEINFO_ACCESS_INFORMATION:
1671                 CHECK_EQUAL(access_information.out.access_flags);
1672                 break;
1673
1674         case RAW_FILEINFO_POSITION_INFORMATION:
1675                 CHECK_EQUAL(position_information.out.position);
1676                 break;
1677
1678         case RAW_FILEINFO_MODE_INFORMATION:
1679                 CHECK_EQUAL(mode_information.out.mode);
1680                 break;
1681
1682         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
1683                 CHECK_EQUAL(alignment_information.out.alignment_requirement);
1684                 break;
1685
1686         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
1687                 CHECK_NTTIMES_EQUAL(network_open_information.out.create_time);
1688                 CHECK_NTTIMES_EQUAL(network_open_information.out.access_time);
1689                 CHECK_NTTIMES_EQUAL(network_open_information.out.write_time);
1690                 CHECK_NTTIMES_EQUAL(network_open_information.out.change_time);
1691                 CHECK_EQUAL(network_open_information.out.alloc_size);
1692                 CHECK_EQUAL(network_open_information.out.size);
1693                 CHECK_ATTRIB(network_open_information.out.attrib);
1694                 break;
1695
1696         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
1697                 CHECK_ATTRIB(attribute_tag_information.out.attrib);
1698                 CHECK_EQUAL(attribute_tag_information.out.reparse_tag);
1699                 break;
1700
1701         case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION:
1702                 CHECK_WSTR_EQUAL(normalized_name_info.out.fname);
1703                 break;
1704
1705         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
1706                 CHECK_NTTIMES_EQUAL(all_info2.out.create_time);
1707                 CHECK_NTTIMES_EQUAL(all_info2.out.access_time);
1708                 CHECK_NTTIMES_EQUAL(all_info2.out.write_time);
1709                 CHECK_NTTIMES_EQUAL(all_info2.out.change_time);
1710                 CHECK_ATTRIB(all_info2.out.attrib);
1711                 CHECK_EQUAL(all_info2.out.unknown1);
1712                 CHECK_EQUAL(all_info2.out.alloc_size);
1713                 CHECK_EQUAL(all_info2.out.size);
1714                 CHECK_EQUAL(all_info2.out.nlink);
1715                 CHECK_EQUAL(all_info2.out.delete_pending);
1716                 CHECK_EQUAL(all_info2.out.directory);
1717                 CHECK_EQUAL(all_info2.out.file_id);
1718                 CHECK_EQUAL(all_info2.out.ea_size);
1719                 CHECK_EQUAL(all_info2.out.access_mask);
1720                 CHECK_EQUAL(all_info2.out.position);
1721                 CHECK_EQUAL(all_info2.out.mode);
1722                 CHECK_EQUAL(all_info2.out.alignment_requirement);
1723                 CHECK_WSTR_EQUAL(all_info2.out.fname);
1724                 break;
1725
1726         case RAW_FILEINFO_SMB2_ALL_EAS:
1727                 CHECK_EQUAL(all_eas.out.num_eas);
1728                 for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
1729                         CHECK_EQUAL(all_eas.out.eas[i].flags);
1730                         CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
1731                         CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
1732                 }
1733                 break;
1734
1735         case RAW_FILEINFO_SEC_DESC:
1736                 CHECK_SECDESC(query_secdesc.out.sd);
1737                 break;
1738
1739                 /* Unhandled levels */
1740         case RAW_FILEINFO_EA_LIST:
1741         case RAW_FILEINFO_UNIX_BASIC:
1742         case RAW_FILEINFO_UNIX_LINK:
1743         case RAW_FILEINFO_UNIX_INFO2:
1744                 break;
1745         }
1746
1747         return true;
1748 }
1749
1750
1751
1752 /*
1753   generate openx operations
1754 */
1755 static bool handler_smb_openx(int instance)
1756 {
1757         union smb_open parm[NSERVERS];
1758         NTSTATUS status[NSERVERS];
1759
1760         parm[0].openx.level = RAW_OPEN_OPENX;
1761         parm[0].openx.in.flags = gen_openx_flags();
1762         parm[0].openx.in.open_mode = gen_openx_mode();
1763         parm[0].openx.in.search_attrs = gen_attrib();
1764         parm[0].openx.in.file_attrs = gen_attrib();
1765         parm[0].openx.in.write_time = gen_timet();
1766         parm[0].openx.in.open_func = gen_openx_func();
1767         parm[0].openx.in.size = gen_io_count();
1768         parm[0].openx.in.timeout = gen_timeout();
1769         parm[0].openx.in.fname = gen_fname_open(instance);
1770
1771         if (!options.use_oplocks) {
1772                 /* mask out oplocks */
1773                 parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1774                                             OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1775         }
1776         
1777         GEN_COPY_PARM;
1778         GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1779
1780         CHECK_ATTRIB(openx.out.attrib);
1781         CHECK_EQUAL(openx.out.size);
1782         CHECK_EQUAL(openx.out.access);
1783         CHECK_EQUAL(openx.out.ftype);
1784         CHECK_EQUAL(openx.out.devstate);
1785         CHECK_EQUAL(openx.out.action);
1786         CHECK_EQUAL(openx.out.access_mask);
1787         CHECK_EQUAL(openx.out.unknown);
1788         CHECK_TIMES_EQUAL(openx.out.write_time);
1789
1790         /* open creates a new file handle */
1791         ADD_HANDLE_SMB(parm[0].openx.in.fname, openx.out.file.fnum);
1792
1793         return true;
1794 }
1795
1796
1797 /*
1798   generate open operations
1799 */
1800 static bool handler_smb_open(int instance)
1801 {
1802         union smb_open parm[NSERVERS];
1803         NTSTATUS status[NSERVERS];
1804
1805         parm[0].openold.level = RAW_OPEN_OPEN;
1806         parm[0].openold.in.open_mode = gen_bits_mask2(0xF, 0xFFFF);
1807         parm[0].openold.in.search_attrs = gen_attrib();
1808         parm[0].openold.in.fname = gen_fname_open(instance);
1809
1810         if (!options.use_oplocks) {
1811                 /* mask out oplocks */
1812                 parm[0].openold.in.open_mode &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1813                                                   OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1814         }
1815         
1816         GEN_COPY_PARM;
1817         GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1818
1819         CHECK_ATTRIB(openold.out.attrib);
1820         CHECK_TIMES_EQUAL(openold.out.write_time);
1821         CHECK_EQUAL(openold.out.size);
1822         CHECK_EQUAL(openold.out.rmode);
1823
1824         /* open creates a new file handle */
1825         ADD_HANDLE_SMB(parm[0].openold.in.fname, openold.out.file.fnum);
1826
1827         return true;
1828 }
1829
1830
1831 /*
1832   generate ntcreatex operations
1833 */
1834 static bool handler_smb_ntcreatex(int instance)
1835 {
1836         union smb_open parm[NSERVERS];
1837         NTSTATUS status[NSERVERS];
1838
1839         parm[0].ntcreatex.level = RAW_OPEN_NTCREATEX;
1840         parm[0].ntcreatex.in.flags = gen_ntcreatex_flags();
1841         parm[0].ntcreatex.in.root_fid.fnum = gen_root_fid(instance);
1842         parm[0].ntcreatex.in.access_mask = gen_access_mask();
1843         parm[0].ntcreatex.in.alloc_size = gen_alloc_size();
1844         parm[0].ntcreatex.in.file_attr = gen_attrib();
1845         parm[0].ntcreatex.in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF);
1846         parm[0].ntcreatex.in.open_disposition = gen_open_disp();
1847         parm[0].ntcreatex.in.create_options = gen_create_options();
1848         parm[0].ntcreatex.in.impersonation = gen_bits_mask2(0, 0xFFFFFFFF);
1849         parm[0].ntcreatex.in.security_flags = gen_bits_mask2(0, 0xFF);
1850         parm[0].ntcreatex.in.fname = gen_fname_open(instance);
1851
1852         if (!options.use_oplocks) {
1853                 /* mask out oplocks */
1854                 parm[0].ntcreatex.in.flags &= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK|
1855                                                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK);
1856         }
1857         
1858         GEN_COPY_PARM;
1859         if (parm[0].ntcreatex.in.root_fid.fnum != 0) {
1860                 GEN_SET_FNUM_SMB(ntcreatex.in.root_fid.fnum);
1861         }
1862         GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1863
1864         CHECK_EQUAL(ntcreatex.out.oplock_level);
1865         CHECK_EQUAL(ntcreatex.out.create_action);
1866         CHECK_NTTIMES_EQUAL(ntcreatex.out.create_time);
1867         CHECK_NTTIMES_EQUAL(ntcreatex.out.access_time);
1868         CHECK_NTTIMES_EQUAL(ntcreatex.out.write_time);
1869         CHECK_NTTIMES_EQUAL(ntcreatex.out.change_time);
1870         CHECK_ATTRIB(ntcreatex.out.attrib);
1871         CHECK_EQUAL(ntcreatex.out.alloc_size);
1872         CHECK_EQUAL(ntcreatex.out.size);
1873         CHECK_EQUAL(ntcreatex.out.file_type);
1874         CHECK_EQUAL(ntcreatex.out.ipc_state);
1875         CHECK_EQUAL(ntcreatex.out.is_directory);
1876
1877         /* ntcreatex creates a new file handle */
1878         ADD_HANDLE_SMB(parm[0].ntcreatex.in.fname, ntcreatex.out.file.fnum);
1879
1880         return true;
1881 }
1882
1883 /*
1884   generate close operations
1885 */
1886 static bool handler_smb_close(int instance)
1887 {
1888         union smb_close parm[NSERVERS];
1889         NTSTATUS status[NSERVERS];
1890
1891         parm[0].close.level = RAW_CLOSE_CLOSE;
1892         parm[0].close.in.file.fnum = gen_fnum_close(instance);
1893         parm[0].close.in.write_time = gen_timet();
1894
1895         GEN_COPY_PARM;
1896         GEN_SET_FNUM_SMB(close.in.file.fnum);
1897         GEN_CALL_SMB(smb_raw_close(tree, &parm[i]));
1898
1899         REMOVE_HANDLE_SMB(close.in.file.fnum);
1900
1901         return true;
1902 }
1903
1904 /*
1905   generate unlink operations
1906 */
1907 static bool handler_smb_unlink(int instance)
1908 {
1909         union smb_unlink parm[NSERVERS];
1910         NTSTATUS status[NSERVERS];
1911
1912         parm[0].unlink.in.pattern = gen_pattern();
1913         parm[0].unlink.in.attrib = gen_attrib();
1914
1915         GEN_COPY_PARM;
1916         GEN_CALL_SMB(smb_raw_unlink(tree, &parm[i]));
1917
1918         return true;
1919 }
1920
1921 /*
1922   generate chkpath operations
1923 */
1924 static bool handler_smb_chkpath(int instance)
1925 {
1926         union smb_chkpath parm[NSERVERS];
1927         NTSTATUS status[NSERVERS];
1928
1929         parm[0].chkpath.in.path = gen_fname_open(instance);
1930
1931         GEN_COPY_PARM;
1932         GEN_CALL_SMB(smb_raw_chkpath(tree, &parm[i]));
1933
1934         return true;
1935 }
1936
1937 /*
1938   generate mkdir operations
1939 */
1940 static bool handler_smb_mkdir(int instance)
1941 {
1942         union smb_mkdir parm[NSERVERS];
1943         NTSTATUS status[NSERVERS];
1944
1945         parm[0].mkdir.level = RAW_MKDIR_MKDIR;
1946         parm[0].mkdir.in.path = gen_fname_open(instance);
1947
1948         GEN_COPY_PARM;
1949         GEN_CALL_SMB(smb_raw_mkdir(tree, &parm[i]));
1950
1951         return true;
1952 }
1953
1954 /*
1955   generate rmdir operations
1956 */
1957 static bool handler_smb_rmdir(int instance)
1958 {
1959         struct smb_rmdir parm[NSERVERS];
1960         NTSTATUS status[NSERVERS];
1961
1962         parm[0].in.path = gen_fname_open(instance);
1963
1964         GEN_COPY_PARM;
1965         GEN_CALL_SMB(smb_raw_rmdir(tree, &parm[i]));
1966
1967         return true;
1968 }
1969
1970 /*
1971   generate rename operations
1972 */
1973 static bool handler_smb_rename(int instance)
1974 {
1975         union smb_rename parm[NSERVERS];
1976         NTSTATUS status[NSERVERS];
1977
1978         parm[0].generic.level = RAW_RENAME_RENAME;
1979         parm[0].rename.in.pattern1 = gen_pattern();
1980         parm[0].rename.in.pattern2 = gen_pattern();
1981         parm[0].rename.in.attrib = gen_attrib();
1982
1983         GEN_COPY_PARM;
1984         GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
1985
1986         return true;
1987 }
1988
1989 /*
1990   generate ntrename operations
1991 */
1992 static bool handler_smb_ntrename(int instance)
1993 {
1994         union smb_rename parm[NSERVERS];
1995         NTSTATUS status[NSERVERS];
1996
1997         parm[0].generic.level = RAW_RENAME_NTRENAME;
1998         parm[0].ntrename.in.old_name = gen_fname();
1999         parm[0].ntrename.in.new_name = gen_fname();
2000         parm[0].ntrename.in.attrib = gen_attrib();
2001         parm[0].ntrename.in.cluster_size = gen_bits_mask2(0, 0xFFFFFFF);
2002         parm[0].ntrename.in.flags = gen_rename_flags();
2003
2004         GEN_COPY_PARM;
2005         GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
2006
2007         return true;
2008 }
2009
2010
2011 /*
2012   generate seek operations
2013 */
2014 static bool handler_smb_seek(int instance)
2015 {
2016         union smb_seek parm[NSERVERS];
2017         NTSTATUS status[NSERVERS];
2018
2019         parm[0].lseek.in.file.fnum = gen_fnum(instance);
2020         parm[0].lseek.in.mode = gen_bits_mask2(0x3, 0xFFFF);
2021         parm[0].lseek.in.offset = gen_offset();
2022
2023         GEN_COPY_PARM;
2024         GEN_SET_FNUM_SMB(lseek.in.file.fnum);
2025         GEN_CALL_SMB(smb_raw_seek(tree, &parm[i]));
2026
2027         CHECK_EQUAL(lseek.out.offset);
2028
2029         return true;
2030 }
2031
2032
2033 /*
2034   generate readx operations
2035 */
2036 static bool handler_smb_readx(int instance)
2037 {
2038         union smb_read parm[NSERVERS];
2039         NTSTATUS status[NSERVERS];
2040
2041         parm[0].readx.level = RAW_READ_READX;
2042         parm[0].readx.in.file.fnum = gen_fnum(instance);
2043         parm[0].readx.in.offset = gen_offset();
2044         parm[0].readx.in.mincnt = gen_io_count();
2045         parm[0].readx.in.maxcnt = gen_io_count();
2046         parm[0].readx.in.remaining = gen_io_count();
2047         parm[0].readx.in.read_for_execute = gen_bool();
2048         parm[0].readx.out.data = talloc_array(current_op.mem_ctx, uint8_t,
2049                                              MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt));
2050
2051         GEN_COPY_PARM;
2052         GEN_SET_FNUM_SMB(readx.in.file.fnum);
2053         GEN_CALL_SMB(smb_raw_read(tree, &parm[i]));
2054
2055         CHECK_EQUAL(readx.out.remaining);
2056         CHECK_EQUAL(readx.out.compaction_mode);
2057         CHECK_EQUAL(readx.out.nread);
2058
2059         return true;
2060 }
2061
2062 /*
2063   generate writex operations
2064 */
2065 static bool handler_smb_writex(int instance)
2066 {
2067         union smb_write parm[NSERVERS];
2068         NTSTATUS status[NSERVERS];
2069
2070         parm[0].writex.level = RAW_WRITE_WRITEX;
2071         parm[0].writex.in.file.fnum = gen_fnum(instance);
2072         parm[0].writex.in.offset = gen_offset();
2073         parm[0].writex.in.wmode = gen_bits_mask(0xFFFF);
2074         parm[0].writex.in.remaining = gen_io_count();
2075         parm[0].writex.in.count = gen_io_count();
2076         parm[0].writex.in.data = talloc_zero_array(current_op.mem_ctx, uint8_t, parm[0].writex.in.count);
2077
2078         GEN_COPY_PARM;
2079         GEN_SET_FNUM_SMB(writex.in.file.fnum);
2080         GEN_CALL_SMB(smb_raw_write(tree, &parm[i]));
2081
2082         CHECK_EQUAL(writex.out.nwritten);
2083         CHECK_EQUAL(writex.out.remaining);
2084
2085         return true;
2086 }
2087
2088 /*
2089   generate lockingx operations
2090 */
2091 static bool handler_smb_lockingx(int instance)
2092 {
2093         union smb_lock parm[NSERVERS];
2094         NTSTATUS status[NSERVERS];
2095         int n, nlocks;
2096
2097         parm[0].lockx.level = RAW_LOCK_LOCKX;
2098         parm[0].lockx.in.file.fnum = gen_fnum(instance);
2099         parm[0].lockx.in.mode = gen_lock_mode();
2100         parm[0].lockx.in.timeout = gen_timeout();
2101         do {
2102                 /* make sure we don't accidentally generate an oplock
2103                    break ack - otherwise the server can just block forever */
2104                 parm[0].lockx.in.ulock_cnt = gen_lock_count();
2105                 parm[0].lockx.in.lock_cnt = gen_lock_count();
2106                 nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt;
2107         } while (nlocks == 0);
2108
2109         if (nlocks > 0) {
2110                 parm[0].lockx.in.locks = talloc_array(current_op.mem_ctx,
2111                                                         struct smb_lock_entry,
2112                                                         nlocks);
2113                 for (n=0;n<nlocks;n++) {
2114                         parm[0].lockx.in.locks[n].pid = gen_pid();
2115                         parm[0].lockx.in.locks[n].offset = gen_offset();
2116                         parm[0].lockx.in.locks[n].count = gen_io_count();
2117                 }
2118         }
2119
2120         GEN_COPY_PARM;
2121         GEN_SET_FNUM_SMB(lockx.in.file.fnum);
2122         GEN_CALL_SMB(smb_raw_lock(tree, &parm[i]));
2123
2124         return true;
2125 }
2126
2127 #if 0
2128 /*
2129   generate a fileinfo query structure
2130 */
2131 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
2132 {
2133         int i;
2134         #undef LVL
2135         #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2136         struct {
2137                 enum smb_setfileinfo_level level;
2138                 const char *name;
2139         }  levels[] = {
2140 #if 0
2141                 /* disabled until win2003 can handle them ... */
2142                 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), 
2143                 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), 
2144 #endif
2145                 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
2146                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
2147                 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
2148                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
2149                 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
2150         };
2151         do {
2152                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2153         } while (ignore_pattern(levels[i].name));
2154
2155         info->generic.level = levels[i].level;
2156
2157         switch (info->generic.level) {
2158         case RAW_SFILEINFO_SETATTR:
2159                 info->setattr.in.attrib = gen_attrib();
2160                 info->setattr.in.write_time = gen_timet();
2161                 break;
2162         case RAW_SFILEINFO_SETATTRE:
2163                 info->setattre.in.create_time = gen_timet();
2164                 info->setattre.in.access_time = gen_timet();
2165                 info->setattre.in.write_time = gen_timet();
2166                 break;
2167         case RAW_SFILEINFO_STANDARD:
2168                 info->standard.in.create_time = gen_timet();
2169                 info->standard.in.access_time = gen_timet();
2170                 info->standard.in.write_time = gen_timet();
2171                 break;
2172         case RAW_SFILEINFO_EA_SET: {
2173                 static struct ea_struct ea;
2174                 info->ea_set.in.num_eas = 1;
2175                 info->ea_set.in.eas = &ea;
2176                 info->ea_set.in.eas[0] = gen_ea_struct();
2177         }
2178                 break;
2179         case RAW_SFILEINFO_BASIC_INFO:
2180         case RAW_SFILEINFO_BASIC_INFORMATION:
2181                 info->basic_info.in.create_time = gen_nttime();
2182                 info->basic_info.in.access_time = gen_nttime();
2183                 info->basic_info.in.write_time = gen_nttime();
2184                 info->basic_info.in.change_time = gen_nttime();
2185                 info->basic_info.in.attrib = gen_attrib();
2186                 break;
2187         case RAW_SFILEINFO_DISPOSITION_INFO:
2188         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
2189                 info->disposition_info.in.delete_on_close = gen_bool();
2190                 break;
2191         case RAW_SFILEINFO_ALLOCATION_INFO:
2192         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
2193                 info->allocation_info.in.alloc_size = gen_alloc_size();
2194                 break;
2195         case RAW_SFILEINFO_END_OF_FILE_INFO:
2196         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
2197                 info->end_of_file_info.in.size = gen_offset();
2198                 break;
2199         case RAW_SFILEINFO_RENAME_INFORMATION:
2200         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
2201                 info->rename_information.in.overwrite = gen_bool();
2202                 info->rename_information.in.root_fid = gen_root_fid(instance);
2203                 info->rename_information.in.new_name = gen_fname_open(instance);
2204                 break;
2205         case RAW_SFILEINFO_POSITION_INFORMATION:
2206                 info->position_information.in.position = gen_offset();
2207                 break;
2208         case RAW_SFILEINFO_MODE_INFORMATION:
2209                 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
2210                 break;
2211         case RAW_SFILEINFO_FULL_EA_INFORMATION:
2212                 info->full_ea_information.in.eas = gen_ea_list();
2213                 break;
2214         case RAW_SFILEINFO_GENERIC:
2215         case RAW_SFILEINFO_SEC_DESC:
2216         case RAW_SFILEINFO_UNIX_BASIC:
2217         case RAW_SFILEINFO_UNIX_LINK:
2218         case RAW_SFILEINFO_UNIX_HLINK:
2219         case RAW_SFILEINFO_1023:
2220         case RAW_SFILEINFO_1025:
2221         case RAW_SFILEINFO_1029:
2222         case RAW_SFILEINFO_1032:
2223         case RAW_SFILEINFO_1039:
2224         case RAW_SFILEINFO_1040:
2225         case RAW_SFILEINFO_UNIX_INFO2:
2226                 /* Untested */
2227                 break;
2228         }
2229 }
2230 #endif
2231
2232 /*
2233   generate a fileinfo query structure
2234 */
2235 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
2236 {
2237         int i;
2238         #undef LVL
2239         #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2240         struct levels {
2241                 enum smb_setfileinfo_level level;
2242                 const char *name;
2243         };
2244         struct levels smb_levels[] = {
2245                 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), 
2246                 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), 
2247                 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
2248                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
2249                 LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION),
2250                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
2251                 LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION), 
2252                 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2253                 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2254         };
2255         struct levels smb2_levels[] = {
2256                 LVL(BASIC_INFORMATION),
2257                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
2258                 LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION),
2259                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
2260                 LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION), 
2261                 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2262                 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2263         };
2264         struct levels *levels = options.smb2?smb2_levels:smb_levels;
2265         uint32_t num_levels = options.smb2?ARRAY_SIZE(smb2_levels):ARRAY_SIZE(smb_levels);
2266
2267         do {
2268                 i = gen_int_range(0, num_levels-1);
2269         } while (ignore_pattern(levels[i].name));
2270
2271         ZERO_STRUCTP(info);
2272         info->generic.level = levels[i].level;
2273
2274         switch (info->generic.level) {
2275         case RAW_SFILEINFO_SETATTR:
2276                 info->setattr.in.attrib = gen_attrib();
2277                 info->setattr.in.write_time = gen_timet();
2278                 break;
2279         case RAW_SFILEINFO_SETATTRE:
2280                 info->setattre.in.create_time = gen_timet();
2281                 info->setattre.in.access_time = gen_timet();
2282                 info->setattre.in.write_time = gen_timet();
2283                 break;
2284         case RAW_SFILEINFO_STANDARD:
2285                 info->standard.in.create_time = gen_timet();
2286                 info->standard.in.access_time = gen_timet();
2287                 info->standard.in.write_time = gen_timet();
2288                 break;
2289         case RAW_SFILEINFO_EA_SET: {
2290                 static struct ea_struct ea;
2291                 info->ea_set.in.num_eas = 1;
2292                 info->ea_set.in.eas = &ea;
2293                 info->ea_set.in.eas[0] = gen_ea_struct();
2294                 break;
2295         }
2296         case RAW_SFILEINFO_BASIC_INFO:
2297         case RAW_SFILEINFO_BASIC_INFORMATION:
2298                 info->basic_info.in.create_time = gen_nttime();
2299                 info->basic_info.in.access_time = gen_nttime();
2300                 info->basic_info.in.write_time = gen_nttime();
2301                 info->basic_info.in.change_time = gen_nttime();
2302                 info->basic_info.in.attrib = gen_attrib();
2303                 break;
2304         case RAW_SFILEINFO_DISPOSITION_INFO:
2305         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
2306                 info->disposition_info.in.delete_on_close = gen_bool();
2307                 break;
2308         case RAW_SFILEINFO_ALLOCATION_INFO:
2309         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
2310                 info->allocation_info.in.alloc_size = gen_alloc_size();
2311                 break;
2312         case RAW_SFILEINFO_END_OF_FILE_INFO:
2313         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
2314                 info->end_of_file_info.in.size = gen_offset();
2315                 break;
2316         case RAW_SFILEINFO_RENAME_INFORMATION:
2317         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
2318                 info->rename_information.in.overwrite = gen_bool();
2319                 info->rename_information.in.root_fid = gen_root_fid(instance);
2320                 info->rename_information.in.new_name = gen_fname_open(instance);
2321                 break;
2322         case RAW_SFILEINFO_POSITION_INFORMATION:
2323                 info->position_information.in.position = gen_offset();
2324                 break;
2325         case RAW_SFILEINFO_MODE_INFORMATION:
2326                 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
2327                 break;
2328         case RAW_SFILEINFO_FULL_EA_INFORMATION:
2329                 info->full_ea_information.in.eas = gen_ea_list();
2330                 break;
2331
2332         case RAW_SFILEINFO_GENERIC:
2333         case RAW_SFILEINFO_SEC_DESC:
2334         case RAW_SFILEINFO_1025:
2335         case RAW_SFILEINFO_1029:
2336         case RAW_SFILEINFO_1032:
2337         case RAW_SFILEINFO_UNIX_BASIC:
2338         case RAW_SFILEINFO_UNIX_INFO2:
2339         case RAW_SFILEINFO_UNIX_LINK:
2340         case RAW_SFILEINFO_UNIX_HLINK:
2341         case RAW_SFILEINFO_LINK_INFORMATION:
2342         case RAW_SFILEINFO_PIPE_INFORMATION:
2343         case RAW_SFILEINFO_VALID_DATA_INFORMATION:
2344         case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
2345         case RAW_SFILEINFO_1027:
2346         case RAW_SFILEINFO_1030:
2347         case RAW_SFILEINFO_1031:
2348         case RAW_SFILEINFO_1036:
2349         case RAW_SFILEINFO_1041:
2350         case RAW_SFILEINFO_1042:
2351         case RAW_SFILEINFO_1043:
2352         case RAW_SFILEINFO_1044:
2353                 /* Untested */
2354                 break;
2355         }
2356 }
2357
2358
2359
2360 /*
2361   generate a fileinfo query structure
2362 */
2363 static void gen_fileinfo_smb(int instance, union smb_fileinfo *info)
2364 {
2365         int i;
2366         #undef LVL
2367         #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2368         struct {
2369                 enum smb_fileinfo_level level;
2370                 const char *name;
2371         }  levels[] = {
2372                 LVL(GETATTR), LVL(GETATTRE), LVL(STANDARD),
2373                 LVL(EA_SIZE), LVL(ALL_EAS), LVL(IS_NAME_VALID),
2374                 LVL(BASIC_INFO), LVL(STANDARD_INFO), LVL(EA_INFO),
2375                 LVL(NAME_INFO), LVL(ALL_INFO), LVL(ALT_NAME_INFO),
2376                 LVL(STREAM_INFO), LVL(COMPRESSION_INFO), LVL(BASIC_INFORMATION),
2377                 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
2378                 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
2379                 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(ALL_INFORMATION),
2380                 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
2381                 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION)
2382         };
2383         do {
2384                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2385         } while (ignore_pattern(levels[i].name));
2386
2387         info->generic.level = levels[i].level;
2388 }
2389
2390 /*
2391   generate qpathinfo operations
2392 */
2393 static bool handler_smb_qpathinfo(int instance)
2394 {
2395         union smb_fileinfo parm[NSERVERS];
2396         NTSTATUS status[NSERVERS];
2397
2398         parm[0].generic.in.file.path = gen_fname_open(instance);
2399
2400         gen_fileinfo_smb(instance, &parm[0]);
2401
2402         GEN_COPY_PARM;
2403         GEN_CALL_SMB(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i]));
2404
2405         return cmp_fileinfo(instance, parm, status);
2406 }
2407
2408 /*
2409   generate qfileinfo operations
2410 */
2411 static bool handler_smb_qfileinfo(int instance)
2412 {
2413         union smb_fileinfo parm[NSERVERS];
2414         NTSTATUS status[NSERVERS];
2415
2416         parm[0].generic.in.file.fnum = gen_fnum(instance);
2417
2418         gen_fileinfo_smb(instance, &parm[0]);
2419
2420         GEN_COPY_PARM;
2421         GEN_SET_FNUM_SMB(generic.in.file.fnum);
2422         GEN_CALL_SMB(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i]));
2423
2424         return cmp_fileinfo(instance, parm, status);
2425 }
2426
2427
2428 /*
2429   generate setpathinfo operations
2430 */
2431 static bool handler_smb_spathinfo(int instance)
2432 {
2433         union smb_setfileinfo parm[NSERVERS];
2434         NTSTATUS status[NSERVERS];
2435
2436         gen_setfileinfo(instance, &parm[0]);
2437         parm[0].generic.in.file.path = gen_fname_open(instance);
2438
2439         GEN_COPY_PARM;
2440
2441         /* a special case for the fid in a RENAME */
2442         if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION &&
2443             parm[0].rename_information.in.root_fid != 0) {
2444                 GEN_SET_FNUM_SMB(rename_information.in.root_fid);
2445         }
2446
2447         GEN_CALL_SMB(smb_raw_setpathinfo(tree, &parm[i]));
2448
2449         return true;
2450 }
2451
2452
2453 /*
2454   generate setfileinfo operations
2455 */
2456 static bool handler_smb_sfileinfo(int instance)
2457 {
2458         union smb_setfileinfo parm[NSERVERS];
2459         NTSTATUS status[NSERVERS];
2460
2461         parm[0].generic.in.file.fnum = gen_fnum(instance);
2462
2463         gen_setfileinfo(instance, &parm[0]);
2464
2465         GEN_COPY_PARM;
2466         GEN_SET_FNUM_SMB(generic.in.file.fnum);
2467         GEN_CALL_SMB(smb_raw_setfileinfo(tree, &parm[i]));
2468
2469         return true;
2470 }
2471
2472
2473 /*
2474   this is called when a change notify reply comes in
2475 */
2476 static void async_notify_smb(struct smbcli_request *req)
2477 {
2478         union smb_notify notify;
2479         NTSTATUS status;
2480         int i, j;
2481         uint16_t tid = 0;
2482         struct smbcli_transport *transport = req->transport;
2483
2484         if (req->tree) {
2485                 tid = req->tree->tid;
2486         }
2487
2488         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
2489         status = smb_raw_changenotify_recv(req, current_op.mem_ctx, &notify);
2490         if (NT_STATUS_IS_OK(status) && notify.nttrans.out.num_changes > 0) {
2491                 printf("notify tid=%d num_changes=%d action=%d name=%s\n", 
2492                        tid, 
2493                        notify.nttrans.out.num_changes,
2494                        notify.nttrans.out.changes[0].action,
2495                        notify.nttrans.out.changes[0].name.s);
2496         }
2497
2498         for (i=0;i<NSERVERS;i++) {
2499                 for (j=0;j<NINSTANCES;j++) {
2500                         if (transport == servers[i].smb_tree[j]->session->transport &&
2501                             tid == servers[i].smb_tree[j]->tid) {
2502                                 notifies[i][j].notify_count++;
2503                                 notifies[i][j].status = status;
2504                                 notifies[i][j].notify = notify;
2505                         }
2506                 }
2507         }
2508 }
2509
2510 /*
2511   generate change notify operations
2512 */
2513 static bool handler_smb_notify(int instance)
2514 {
2515         union smb_notify parm[NSERVERS];
2516         int n;
2517
2518         ZERO_STRUCT(parm[0]);
2519         parm[0].nttrans.level                   = RAW_NOTIFY_NTTRANS;
2520         parm[0].nttrans.in.buffer_size          = gen_io_count();
2521         parm[0].nttrans.in.completion_filter    = gen_bits_mask(0xFF);
2522         parm[0].nttrans.in.file.fnum            = gen_fnum(instance);
2523         parm[0].nttrans.in.recursive            = gen_bool();
2524
2525         GEN_COPY_PARM;
2526         GEN_SET_FNUM_SMB(nttrans.in.file.fnum);
2527
2528         for (n=0;n<NSERVERS;n++) {
2529                 struct smbcli_request *req;
2530                 req = smb_raw_changenotify_send(servers[n].smb_tree[instance], &parm[n]);
2531                 req->async.fn = async_notify_smb;
2532         }
2533
2534         return true;
2535 }
2536
2537
2538 /*
2539   generate ntcreatex operations
2540 */
2541 static bool handler_smb2_create(int instance)
2542 {
2543         struct smb2_create parm[NSERVERS];
2544         NTSTATUS status[NSERVERS];
2545
2546         ZERO_STRUCT(parm[0]);
2547         parm[0].in.security_flags             = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF);
2548         parm[0].in.oplock_level               = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF);
2549         parm[0].in.impersonation_level        = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF);
2550         parm[0].in.create_flags               = gen_reserved64();
2551         parm[0].in.reserved                   = gen_reserved64();
2552         parm[0].in.desired_access             = gen_access_mask();
2553         parm[0].in.file_attributes            = gen_attrib();
2554         parm[0].in.share_access               = gen_bits_mask2(0x7, 0xFFFFFFFF);
2555         parm[0].in.create_disposition         = gen_open_disp();
2556         parm[0].in.create_options             = gen_create_options();
2557         parm[0].in.fname                      = gen_fname_open(instance);
2558         parm[0].in.eas                        = gen_ea_list();
2559         parm[0].in.alloc_size                 = gen_alloc_size();
2560         parm[0].in.durable_open               = gen_bool();
2561         parm[0].in.query_maximal_access       = gen_bool();
2562         parm[0].in.timewarp                   = gen_timewarp();
2563         parm[0].in.query_on_disk_id           = gen_bool();
2564         parm[0].in.sec_desc                   = gen_sec_desc();
2565
2566         if (!options.use_oplocks) {
2567                 /* mask out oplocks */
2568                 parm[0].in.oplock_level = 0;
2569         }
2570
2571         if (options.valid) {
2572                 parm[0].in.security_flags   &= 3;
2573                 parm[0].in.oplock_level     &= 9;
2574                 parm[0].in.impersonation_level &= 3;
2575         }
2576
2577         GEN_COPY_PARM;
2578         GEN_CALL_SMB2(smb2_create(tree, current_op.mem_ctx, &parm[i]));
2579
2580         CHECK_EQUAL(out.oplock_level);
2581         CHECK_EQUAL(out.reserved);
2582         CHECK_EQUAL(out.create_action);
2583         CHECK_NTTIMES_EQUAL(out.create_time);
2584         CHECK_NTTIMES_EQUAL(out.access_time);
2585         CHECK_NTTIMES_EQUAL(out.write_time);
2586         CHECK_NTTIMES_EQUAL(out.change_time);
2587         CHECK_EQUAL(out.alloc_size);
2588         CHECK_EQUAL(out.size);
2589         CHECK_ATTRIB(out.file_attr);
2590         CHECK_EQUAL(out.reserved2);
2591         CHECK_EQUAL(out.maximal_access);
2592
2593         /* ntcreatex creates a new file handle */
2594         ADD_HANDLE_SMB2(parm[0].in.fname, out.file.handle);
2595
2596         return true;
2597 }
2598
2599 /*
2600   generate close operations
2601 */
2602 static bool handler_smb2_close(int instance)
2603 {
2604         struct smb2_close parm[NSERVERS];
2605         NTSTATUS status[NSERVERS];
2606
2607         ZERO_STRUCT(parm[0]);
2608         parm[0].in.file.handle.data[0] = gen_fnum_close(instance);
2609         parm[0].in.flags               = gen_bits_mask2(0x1, 0xFFFF);
2610
2611         GEN_COPY_PARM;
2612         GEN_SET_FNUM_SMB2(in.file.handle);
2613         GEN_CALL_SMB2(smb2_close(tree, &parm[i]));
2614
2615         CHECK_EQUAL(out.flags);
2616         CHECK_EQUAL(out._pad);
2617         CHECK_NTTIMES_EQUAL(out.create_time);
2618         CHECK_NTTIMES_EQUAL(out.access_time);
2619         CHECK_NTTIMES_EQUAL(out.write_time);
2620         CHECK_NTTIMES_EQUAL(out.change_time);
2621         CHECK_EQUAL(out.alloc_size);
2622         CHECK_EQUAL(out.size);
2623         CHECK_ATTRIB(out.file_attr);
2624
2625         REMOVE_HANDLE_SMB2(in.file.handle);
2626
2627         return true;
2628 }
2629
2630 /*
2631   generate read operations
2632 */
2633 static bool handler_smb2_read(int instance)
2634 {
2635         struct smb2_read parm[NSERVERS];
2636         NTSTATUS status[NSERVERS];
2637
2638         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2639         parm[0].in.reserved    = gen_reserved8();
2640         parm[0].in.length      = gen_io_count();
2641         parm[0].in.offset      = gen_offset();
2642         parm[0].in.min_count   = gen_io_count();
2643         parm[0].in.channel     = gen_bits_mask2(0x0, 0xFFFFFFFF);
2644         parm[0].in.remaining   = gen_bits_mask2(0x0, 0xFFFFFFFF);
2645         parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF);
2646         parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF);
2647
2648         GEN_COPY_PARM;
2649         GEN_SET_FNUM_SMB2(in.file.handle);
2650         GEN_CALL_SMB2(smb2_read(tree, current_op.mem_ctx, &parm[i]));
2651
2652         CHECK_EQUAL(out.remaining);
2653         CHECK_EQUAL(out.reserved);
2654         CHECK_EQUAL(out.data.length);
2655
2656         return true;
2657 }
2658
2659 /*
2660   generate write operations
2661 */
2662 static bool handler_smb2_write(int instance)
2663 {
2664         struct smb2_write parm[NSERVERS];
2665         NTSTATUS status[NSERVERS];
2666
2667         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2668         parm[0].in.offset = gen_offset();
2669         parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF);
2670         parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF);
2671         parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL,
2672                                             gen_io_count());
2673
2674         GEN_COPY_PARM;
2675         GEN_SET_FNUM_SMB2(in.file.handle);
2676         GEN_CALL_SMB2(smb2_write(tree, &parm[i]));
2677
2678         CHECK_EQUAL(out._pad);
2679         CHECK_EQUAL(out.nwritten);
2680         CHECK_EQUAL(out.unknown1);
2681
2682         return true;
2683 }
2684
2685 /*
2686   generate lockingx operations
2687 */
2688 static bool handler_smb2_lock(int instance)
2689 {
2690         struct smb2_lock parm[NSERVERS];
2691         NTSTATUS status[NSERVERS];
2692         int n;
2693
2694         parm[0].level = RAW_LOCK_LOCKX;
2695         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2696         parm[0].in.lock_count = gen_lock_count();
2697         parm[0].in.lock_sequence = gen_reserved32();
2698         
2699         parm[0].in.locks = talloc_array(current_op.mem_ctx,
2700                                         struct smb2_lock_element,
2701                                         parm[0].in.lock_count);
2702         for (n=0;n<parm[0].in.lock_count;n++) {
2703                 parm[0].in.locks[n].offset = gen_offset();
2704                 parm[0].in.locks[n].length = gen_io_count();
2705                 /* don't yet cope with async replies */
2706                 parm[0].in.locks[n].flags  = gen_lock_flags_smb2() | 
2707                         SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
2708                 parm[0].in.locks[n].reserved = gen_bits_mask2(0x0, 0xFFFFFFFF);
2709         }
2710
2711         GEN_COPY_PARM;
2712         GEN_SET_FNUM_SMB2(in.file.handle);
2713         GEN_CALL_SMB2(smb2_lock(tree, &parm[i]));
2714
2715         return true;
2716 }
2717
2718 /*
2719   generate flush operations
2720 */
2721 static bool handler_smb2_flush(int instance)
2722 {
2723         struct smb2_flush parm[NSERVERS];
2724         NTSTATUS status[NSERVERS];
2725
2726         ZERO_STRUCT(parm[0]);
2727         parm[0].in.file.handle.data[0] = gen_fnum(instance);
2728         parm[0].in.reserved1  = gen_reserved16();
2729         parm[0].in.reserved2  = gen_reserved32();
2730
2731         GEN_COPY_PARM;
2732         GEN_SET_FNUM_SMB2(in.file.handle);
2733         GEN_CALL_SMB2(smb2_flush(tree, &parm[i]));
2734
2735         CHECK_EQUAL(out.reserved);
2736
2737         return true;
2738 }
2739
2740 /*
2741   generate echo operations
2742 */
2743 static bool handler_smb2_echo(int instance)
2744 {
2745         NTSTATUS status[NSERVERS];
2746
2747         GEN_CALL_SMB2(smb2_keepalive(tree->session->transport));
2748
2749         return true;
2750 }
2751
2752
2753
2754 /*
2755   generate a fileinfo query structure
2756 */
2757 static void gen_fileinfo_smb2(int instance, union smb_fileinfo *info)
2758 {
2759         int i;
2760         #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2761         struct {
2762                 enum smb_fileinfo_level level;
2763                 const char *name;
2764         }  levels[] = {
2765                 LVL(BASIC_INFORMATION),
2766                 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
2767                 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
2768                 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION),
2769                 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
2770                 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION),
2771                 LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC),
2772         };
2773         do {
2774                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
2775         } while (ignore_pattern(levels[i].name));
2776
2777         info->generic.level = levels[i].level;
2778 }
2779
2780 /*
2781   generate qfileinfo operations
2782 */
2783 static bool handler_smb2_qfileinfo(int instance)
2784 {
2785         union smb_fileinfo parm[NSERVERS];
2786         NTSTATUS status[NSERVERS];
2787
2788         parm[0].generic.in.file.handle.data[0] = gen_fnum(instance);
2789
2790         gen_fileinfo_smb2(instance, &parm[0]);
2791
2792         GEN_COPY_PARM;
2793         GEN_SET_FNUM_SMB2(generic.in.file.handle);
2794         GEN_CALL_SMB2(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i]));
2795
2796         return cmp_fileinfo(instance, parm, status);
2797 }
2798
2799
2800 /*
2801   generate setfileinfo operations
2802 */
2803 static bool handler_smb2_sfileinfo(int instance)
2804 {
2805         union smb_setfileinfo parm[NSERVERS];
2806         NTSTATUS status[NSERVERS];
2807
2808         gen_setfileinfo(instance, &parm[0]);
2809         parm[0].generic.in.file.fnum = gen_fnum(instance);
2810
2811         GEN_COPY_PARM;
2812         GEN_SET_FNUM_SMB2(generic.in.file.handle);
2813         GEN_CALL_SMB2(smb2_setinfo_file(tree, &parm[i]));
2814
2815         return true;
2816 }
2817
2818 /*
2819   wipe any relevant files
2820 */
2821 static void wipe_files(void)
2822 {
2823         int i;
2824         NTSTATUS status;
2825
2826         if (options.skip_cleanup) {
2827                 return;
2828         }
2829
2830         for (i=0;i<NSERVERS;i++) {
2831                 int n;
2832                 if (options.smb2) {
2833                         n = smb2_deltree(servers[i].smb2_tree[0], "gentest");
2834                 } else {
2835                         n = smbcli_deltree(servers[i].smb_tree[0], "gentest");
2836                 }
2837                 if (n == -1) {
2838                         printf("Failed to wipe tree on server %d\n", i);
2839                         exit(1);
2840                 }
2841                 if (options.smb2) {
2842                         status = smb2_util_mkdir(servers[i].smb2_tree[0], "gentest");
2843                 } else {
2844                         status = smbcli_mkdir(servers[i].smb_tree[0], "gentest");
2845                 }
2846                 if (NT_STATUS_IS_ERR(status)) {
2847                         printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status));
2848                         exit(1);
2849                 }
2850                 if (n > 0) {
2851                         printf("Deleted %d files on server %d\n", n, i);
2852                 }
2853         }
2854 }
2855
2856 /*
2857   dump the current seeds - useful for continuing a backtrack
2858 */
2859 static void dump_seeds(void)
2860 {
2861         int i;
2862         FILE *f;
2863
2864         if (!options.seeds_file) {
2865                 return;
2866         }
2867         f = fopen("seeds.tmp", "w");
2868         if (!f) return;
2869
2870         for (i=0;i<options.numops;i++) {
2871                 fprintf(f, "%u\n", op_parms[i].seed);
2872         }
2873         fclose(f);
2874         rename("seeds.tmp", options.seeds_file);
2875 }
2876
2877
2878
2879 /*
2880   the list of top-level operations that we will generate
2881 */
2882 static struct {
2883         const char *name;
2884         bool (*handler)(int instance);
2885         bool smb2;
2886         int count, success_count;
2887 } gen_ops[] = {
2888         {
2889                 .name    = "CREATE",
2890                 .handler = handler_smb2_create,
2891                 .smb2    = true,
2892         },
2893         {
2894                 .name    = "CLOSE",
2895                 .handler = handler_smb2_close,
2896                 .smb2    = true,
2897         },
2898         {
2899                 .name    = "READ",
2900                 .handler = handler_smb2_read,
2901                 .smb2    = true,
2902         },
2903         {
2904                 .name    = "WRITE",
2905                 .handler = handler_smb2_write,
2906                 .smb2    = true,
2907         },
2908         {
2909                 .name    = "LOCK",
2910                 .handler = handler_smb2_lock,
2911                 .smb2    = true,
2912         },
2913         {
2914                 .name    = "FLUSH",
2915                 .handler = handler_smb2_flush,
2916                 .smb2    = true,
2917         },
2918         {
2919                 .name    = "ECHO",
2920                 .handler = handler_smb2_echo,
2921                 .smb2    = true,
2922         },
2923         {
2924                 .name    = "QFILEINFO",
2925                 .handler = handler_smb2_qfileinfo,
2926                 .smb2    = true,
2927         },
2928         {
2929                 .name    = "SFILEINFO",
2930                 .handler = handler_smb2_sfileinfo,
2931                 .smb2    = true,
2932         },
2933
2934         {
2935                 .name    = "OPEN",
2936                 .handler = handler_smb_open,
2937                 .smb2    = false,
2938         },
2939         {
2940                 .name    = "OPENX",
2941                 .handler = handler_smb_openx,
2942                 .smb2    = false,
2943         },
2944         {
2945                 .name    = "NTCREATEX",
2946                 .handler = handler_smb_ntcreatex,
2947                 .smb2    = false,
2948         },
2949         {
2950                 .name    = "CLOSE",
2951                 .handler = handler_smb_close,
2952                 .smb2    = false,
2953         },
2954         {
2955                 .name    = "UNLINK",
2956                 .handler = handler_smb_unlink,
2957                 .smb2    = false,
2958         },
2959         {
2960                 .name    = "MKDIR",
2961                 .handler = handler_smb_mkdir,
2962                 .smb2    = false,
2963         },
2964         {
2965                 .name    = "RMDIR",
2966                 .handler = handler_smb_rmdir,
2967                 .smb2    = false,
2968         },
2969         {
2970                 .name    = "RENAME",
2971                 .handler = handler_smb_rename,
2972                 .smb2    = false,
2973         },
2974         {
2975                 .name    = "NTRENAME",
2976                 .handler = handler_smb_ntrename,
2977                 .smb2    = false,
2978         },
2979         {
2980                 .name    = "READX",
2981                 .handler = handler_smb_readx,
2982                 .smb2    = false,
2983         },
2984         {
2985                 .name    = "WRITEX",
2986                 .handler = handler_smb_writex,
2987                 .smb2    = false,
2988         },
2989         {
2990                 .name    = "CHKPATH",
2991                 .handler = handler_smb_chkpath,
2992                 .smb2    = false,
2993         },
2994         {
2995                 .name    = "SEEK",
2996                 .handler = handler_smb_seek,
2997                 .smb2    = false,
2998         },
2999         {
3000                 .name    = "LOCKINGX",
3001                 .handler = handler_smb_lockingx,
3002                 .smb2    = false,
3003         },
3004         {
3005                 .name    = "QPATHINFO",
3006                 .handler = handler_smb_qpathinfo,
3007                 .smb2    = false,
3008         },
3009         {
3010                 .name    = "QFILEINFO",
3011                 .handler = handler_smb_qfileinfo,
3012                 .smb2    = false,
3013         },
3014         {
3015                 .name    = "SPATHINFO",
3016                 .handler = handler_smb_spathinfo,
3017                 .smb2    = false,
3018         },
3019         {
3020                 .name    = "SFILEINFO",
3021                 .handler = handler_smb_sfileinfo,
3022                 .smb2    = false,
3023         },
3024         {
3025                 .name    = "NOTIFY",
3026                 .handler = handler_smb_notify,
3027                 .smb2    = false,
3028         },
3029 };
3030
3031
3032 /*
3033   run the test with the current set of op_parms parameters
3034   return the number of operations that completed successfully
3035 */
3036 static int run_test(struct tevent_context *ev, struct loadparm_context *lp_ctx)
3037 {
3038         int op, i;
3039
3040         if (!connect_servers(ev, lp_ctx)) {
3041                 printf("Failed to connect to servers\n");
3042                 exit(1);
3043         }
3044
3045         dump_seeds();
3046
3047         /* wipe any leftover files from old runs */
3048         wipe_files();
3049
3050         /* reset the open handles array */
3051         memset(open_handles, 0, options.max_open_handles * sizeof(open_handles[0]));
3052         num_open_handles = 0;
3053
3054         /* reset the counts from previous runs */
3055         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
3056                 gen_ops[i].count = 0;
3057                 gen_ops[i].success_count = 0;
3058         }
3059
3060         for (op=0; op<options.numops; op++) {
3061                 int instance, which_op;
3062                 bool ret;
3063
3064                 if (op_parms[op].disabled) continue;
3065
3066                 srandom(op_parms[op].seed);
3067
3068                 instance = gen_int_range(0, NINSTANCES-1);
3069
3070                 /* generate a non-ignored operation */
3071                 do {
3072                         which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1);
3073                 } while (ignore_pattern(gen_ops[which_op].name) ||
3074                          gen_ops[which_op].smb2 != options.smb2);
3075
3076                 DEBUG(3,("Generating op %s on instance %d\n",
3077                          gen_ops[which_op].name, instance));
3078
3079                 current_op.seed = op_parms[op].seed;
3080                 current_op.opnum = op;
3081                 current_op.name = gen_ops[which_op].name;
3082                 current_op.status = NT_STATUS_OK;
3083                 talloc_free(current_op.mem_ctx);
3084                 current_op.mem_ctx = talloc_named(NULL, 0, "%s", current_op.name);
3085
3086                 ret = gen_ops[which_op].handler(instance);
3087
3088                 gen_ops[which_op].count++;
3089                 if (NT_STATUS_IS_OK(current_op.status)) {
3090                         gen_ops[which_op].success_count++;                      
3091                 }
3092
3093                 if (!ret) {
3094                         printf("Failed at operation %d - %s\n",
3095                                op, gen_ops[which_op].name);
3096                         return op;
3097                 }
3098
3099                 if (op % 100 == 0) {
3100                         printf("%d\n", op);
3101                 }
3102         }
3103
3104         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
3105                 printf("Op %-10s got %d/%d success\n", 
3106                        gen_ops[i].name,
3107                        gen_ops[i].success_count,
3108                        gen_ops[i].count);
3109         }
3110
3111         return op;
3112 }
3113
3114 /* 
3115    perform a backtracking analysis of the minimal set of operations
3116    to generate an error
3117 */
3118 static void backtrack_analyze(struct tevent_context *ev,
3119                               struct loadparm_context *lp_ctx)
3120 {
3121         int chunk, ret;
3122         const char *mismatch = current_op.mismatch;
3123
3124         chunk = options.numops / 2;
3125
3126         do {
3127                 int base;
3128                 for (base=0; 
3129                      chunk > 0 && base+chunk < options.numops && options.numops > 1; ) {
3130                         int i, max;
3131
3132                         chunk = MIN(chunk, options.numops / 2);
3133
3134                         /* mark this range as disabled */
3135                         max = MIN(options.numops, base+chunk);
3136                         for (i=base;i<max; i++) {
3137                                 op_parms[i].disabled = true;
3138                         }
3139                         printf("Testing %d ops with %d-%d disabled\n", 
3140                                options.numops, base, max-1);
3141                         ret = run_test(ev, lp_ctx);
3142                         printf("Completed %d of %d ops\n", ret, options.numops);
3143                         for (i=base;i<max; i++) {
3144                                 op_parms[i].disabled = false;
3145                         }
3146                         if (ret == options.numops) {
3147                                 /* this chunk is needed */
3148                                 base += chunk;
3149                         } else if (mismatch != current_op.mismatch &&
3150                                    strcmp(mismatch, current_op.mismatch)) {
3151                                 base += chunk;
3152                                 printf("Different error in backtracking\n");
3153                         } else if (ret < base) {
3154                                 printf("damn - inconsistent errors! found early error\n");
3155                                 options.numops = ret+1;
3156                                 base = 0;
3157                         } else {
3158                                 /* it failed - this chunk isn't needed for a failure */
3159                                 memmove(&op_parms[base], &op_parms[max], 
3160                                         sizeof(op_parms[0]) * (options.numops - max));
3161                                 options.numops = (ret+1) - (max - base);
3162                         }
3163                 }
3164
3165                 if (chunk == 2) {
3166                         chunk = 1;
3167                 } else {
3168                         chunk *= 0.4;
3169                 }
3170
3171                 if (options.analyze_continuous && chunk == 0 && options.numops != 1) {
3172                         chunk = 1;
3173                 }
3174         } while (chunk > 0);
3175
3176         printf("Reduced to %d ops\n", options.numops);
3177         ret = run_test(ev, lp_ctx);
3178         if (ret != options.numops - 1) {
3179                 printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops);
3180         }
3181 }
3182
3183 /* 
3184    start the main gentest process
3185 */
3186 static bool start_gentest(struct tevent_context *ev,
3187                           struct loadparm_context *lp_ctx)
3188 {
3189         int op;
3190         int ret;
3191
3192         /* allocate the open_handles array */
3193         open_handles = calloc(options.max_open_handles, sizeof(open_handles[0]));
3194         if (open_handles == NULL) {
3195                 printf("Unable to allocate memory for open_handles array.\n");
3196                 exit(1);
3197         }
3198
3199         srandom(options.seed);
3200         op_parms = calloc(options.numops, sizeof(op_parms[0]));
3201         if (op_parms == NULL) {
3202                 printf("Unable to allocate memory for op_parms.\n");
3203                 exit(1);
3204         }
3205
3206         /* generate the seeds - after this everything is deterministic */
3207         if (options.use_preset_seeds) {
3208                 int numops;
3209                 char **preset = file_lines_load(options.seeds_file, &numops, 0, NULL);
3210                 if (!preset) {
3211                         printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno));
3212                         exit(1);
3213                 }
3214                 if (numops < options.numops) {
3215                         options.numops = numops;
3216                 }
3217                 for (op=0;op<options.numops;op++) {
3218                         if (!preset[op]) {
3219                                 printf("Not enough seeds in %s\n", options.seeds_file);
3220                                 exit(1);
3221                         }
3222                         op_parms[op].seed = atoi(preset[op]);
3223                 }
3224                 printf("Loaded %d seeds from %s\n", options.numops, options.seeds_file);
3225         } else {
3226                 for (op=0; op<options.numops; op++) {
3227                         op_parms[op].seed = random();
3228                 }
3229         }
3230
3231         ret = run_test(ev, lp_ctx);
3232
3233         if (ret != options.numops && options.analyze) {
3234                 options.numops = ret+1;
3235                 backtrack_analyze(ev, lp_ctx);
3236         } else if (options.analyze_always) {
3237                 backtrack_analyze(ev, lp_ctx);
3238         } else if (options.analyze_continuous) {
3239                 while (run_test(ev, lp_ctx) == options.numops) ;
3240         }
3241
3242         return ret == options.numops;
3243 }
3244
3245
3246 static void usage(poptContext pc)
3247 {
3248         printf(
3249 "Usage:\n\
3250   gentest //server1/share1 //server2/share2 [options..]\n\
3251 ");
3252         poptPrintUsage(pc, stdout, 0);
3253 }
3254
3255 /**
3256   split a UNC name into server and share names
3257 */
3258 static bool split_unc_name(const char *unc, char **server, char **share)
3259 {
3260         char *p = strdup(unc);
3261         if (!p) return false;
3262         all_string_sub(p, "\\", "/", 0);
3263         if (strncmp(p, "//", 2) != 0) return false;
3264
3265         (*server) = p+2;
3266         p = strchr(*server, '/');
3267         if (!p) return false;
3268
3269         *p = 0;
3270         (*share) = p+1;
3271         
3272         return true;
3273 }
3274
3275
3276
3277 /****************************************************************************
3278   main program
3279 ****************************************************************************/
3280 int main(int argc, const char *argv[])
3281 {
3282         int opt;
3283         int i, username_count=0;
3284         bool ret;
3285         char *ignore_file=NULL;
3286         struct tevent_context *ev;
3287         struct loadparm_context *lp_ctx;
3288         poptContext pc;
3289         int argc_new;
3290         char **argv_new;
3291         enum {
3292                 OPT_UNCLIST=1000,
3293                 OPT_USER1,
3294                 OPT_USER2,
3295         };
3296         struct poptOption long_options[] = {
3297                 POPT_AUTOHELP
3298                 {"smb2",          0, POPT_ARG_NONE, &options.smb2, 0,   "use SMB2 protocol",    NULL},
3299                 {"seed",          0, POPT_ARG_INT,  &options.seed,      0,      "Seed to use for randomizer",   NULL},
3300                 {"num-ops",       0, POPT_ARG_INT,  &options.numops,    0,      "num ops",      NULL},
3301                 {"oplocks",       0, POPT_ARG_NONE, &options.use_oplocks,0,      "use oplocks", NULL},
3302                 {"showall",       0, POPT_ARG_NONE, &options.showall,    0,      "display all operations", NULL},
3303                 {"analyse",       0, POPT_ARG_NONE, &options.analyze,    0,      "do backtrack analysis", NULL},
3304                 {"analysealways", 0, POPT_ARG_NONE, &options.analyze_always,    0,      "analysis always", NULL},
3305                 {"analysecontinuous", 0, POPT_ARG_NONE, &options.analyze_continuous,    0,      "analysis continuous", NULL},
3306                 {"ignore",        0, POPT_ARG_STRING, &ignore_file,    0,      "ignore from file", NULL},
3307                 {"preset",        0, POPT_ARG_NONE, &options.use_preset_seeds,    0,      "use preset seeds", NULL},
3308                 {"fast",          0, POPT_ARG_NONE, &options.fast_reconnect,    0,      "use fast reconnect", NULL},
3309                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
3310                 {"seedsfile",     0, POPT_ARG_STRING,  &options.seeds_file, 0,  "seed file",    NULL},
3311                 {"user1",         0, POPT_ARG_STRING, NULL, OPT_USER1, "Set first network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
3312                 {"user2",         0, POPT_ARG_STRING, NULL, OPT_USER2, "Set second network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
3313                 {"maskindexing",  0, POPT_ARG_NONE,  &options.mask_indexing, 0, "mask out the indexed file attrib",     NULL},
3314                 {"noeas",  0, POPT_ARG_NONE,  &options.no_eas, 0,       "don't use extended attributes",        NULL},
3315                 {"noacls",  0, POPT_ARG_NONE,  &options.no_acls, 0,     "don't use ACLs",       NULL},
3316                 {"skip-cleanup",  0, POPT_ARG_NONE,  &options.skip_cleanup, 0,  "don't delete files at start",  NULL},
3317                 {"valid",  0, POPT_ARG_NONE,  &options.valid, 0,        "generate only valid fields",   NULL},
3318                 POPT_COMMON_SAMBA
3319                 POPT_COMMON_CONNECTION
3320                 POPT_COMMON_CREDENTIALS
3321                 POPT_COMMON_VERSION
3322                 POPT_LEGACY_S4
3323                 POPT_TABLEEND
3324         };
3325         TALLOC_CTX *mem_ctx = NULL;
3326         bool ok;
3327
3328         memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle));
3329
3330         setlinebuf(stdout);
3331         options.seed = time(NULL);
3332         options.numops = 1000;
3333         options.max_open_handles = 20;
3334         options.seeds_file = "gentest_seeds.dat";
3335
3336         mem_ctx = talloc_named_const(NULL, 0, "gentest_ctx");
3337         if (mem_ctx == NULL) {
3338                 printf("Unable to allocate gentest_ctx\n");
3339                 exit(1);
3340         }
3341
3342         ok = samba_cmdline_init(mem_ctx,
3343                                 SAMBA_CMDLINE_CONFIG_CLIENT,
3344                                 false /* require_smbconf */);
3345         if (!ok) {
3346                 DBG_ERR("Failed to init cmdline parser!\n");
3347                 TALLOC_FREE(mem_ctx);
3348                 exit(1);
3349         }
3350
3351         pc = samba_popt_get_context(getprogname(),
3352                                     argc,
3353                                     argv,
3354                                     long_options,
3355                                     POPT_CONTEXT_KEEP_FIRST);
3356         if (pc == NULL) {
3357                 DBG_ERR("Failed to setup popt context!\n");
3358                 TALLOC_FREE(mem_ctx);
3359                 exit(1);
3360         }
3361
3362         poptSetOtherOptionHelp(pc, "<unc1> <unc2>");
3363
3364         lp_ctx = samba_cmdline_get_lp_ctx();
3365         servers[0].credentials = cli_credentials_init(mem_ctx);
3366         servers[1].credentials = cli_credentials_init(mem_ctx);
3367         cli_credentials_guess(servers[0].credentials, lp_ctx);
3368         cli_credentials_guess(servers[1].credentials, lp_ctx);
3369
3370         while((opt = poptGetNextOpt(pc)) != -1) {
3371                 switch (opt) {
3372                 case OPT_UNCLIST:
3373                         lpcfg_set_cmdline(lp_ctx, "torture:unclist", poptGetOptArg(pc));
3374                         break;
3375                 case OPT_USER1:
3376                         cli_credentials_parse_string(servers[0].credentials,
3377                                                      poptGetOptArg(pc),
3378                                                      CRED_SPECIFIED);
3379                         username_count++;
3380                         break;
3381                 case OPT_USER2:
3382                         cli_credentials_parse_string(servers[1].credentials,
3383                                                      poptGetOptArg(pc),
3384                                                      CRED_SPECIFIED);
3385                         username_count++;
3386                         break;
3387                 case POPT_ERROR_BADOPT:
3388                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
3389                                 poptBadOption(pc, 0), poptStrerror(opt));
3390                         poptPrintUsage(pc, stderr, 0);
3391                         exit(1);
3392                 }
3393         }
3394
3395         if (ignore_file) {
3396                 options.ignore_patterns = file_lines_load(ignore_file, NULL, 0, NULL);
3397         }
3398
3399         argv_new = discard_const_p(char *, poptGetArgs(pc));
3400         argc_new = argc;
3401         for (i=0; i<argc; i++) {
3402                 if (argv_new[i] == NULL) {
3403                         argc_new = i;
3404                         break;
3405                 }
3406         }
3407
3408         if (!(argc_new >= 3)) {
3409                 usage(pc);
3410                 talloc_free(mem_ctx);
3411                 exit(1);
3412         }
3413
3414         setlinebuf(stdout);
3415
3416         setup_logging("gentest", DEBUG_STDOUT);
3417
3418         if (argc < 3 || argv[1][0] == '-') {
3419                 usage(pc);
3420                 talloc_free(mem_ctx);
3421                 exit(1);
3422         }
3423
3424         setup_logging(argv[0], DEBUG_STDOUT);
3425
3426         for (i=0;i<NSERVERS;i++) {
3427                 const char *share = argv[1+i];
3428                 if (!split_unc_name(share, &servers[i].server_name, &servers[i].share_name)) {
3429                         printf("Invalid share name '%s'\n", share);
3430                         poptFreeContext(pc);
3431                         talloc_free(mem_ctx);
3432                         return -1;
3433                 }
3434         }
3435
3436         if (username_count == 0) {
3437                 usage(pc);
3438                 poptFreeContext(pc);
3439                 talloc_free(mem_ctx);
3440                 return -1;
3441         }
3442         if (username_count == 1) {
3443                 servers[1].credentials = servers[0].credentials;
3444         }
3445
3446         printf("seed=%u\n", options.seed);
3447
3448         ev = s4_event_context_init(mem_ctx);
3449
3450         gensec_init();
3451
3452         ret = start_gentest(ev, lp_ctx);
3453
3454         if (ret) {
3455                 printf("gentest completed - no errors\n");
3456         } else {
3457                 printf("gentest failed\n");
3458         }
3459
3460         poptFreeContext(pc);
3461         talloc_free(mem_ctx);
3462         return ret?0:-1;
3463 }