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