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