2 Unix SMB/CIFS implementation.
4 generic testing tool - version with both SMB and SMB2 support
6 Copyright (C) Andrew Tridgell 2003-2008
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.
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.
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/>.
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"
46 static struct gentest_options
{
50 int analyze_continuous
;
51 unsigned int max_open_handles
;
55 char **ignore_patterns
;
56 const char *seeds_file
;
67 /* mapping between open handles on the server and local handles */
70 unsigned int instance
;
71 struct smb2_handle smb2_handle
[NSERVERS
]; /* SMB2 */
72 uint16_t smb_handle
[NSERVERS
]; /* SMB */
75 static unsigned int num_open_handles
;
77 /* state information for the servers. We open NINSTANCES connections to
80 struct smb2_tree
*smb2_tree
[NINSTANCES
];
81 struct smbcli_tree
*smb_tree
[NINSTANCES
];
84 struct cli_credentials
*credentials
;
87 /* the seeds and flags for each operation */
94 /* oplock break info */
97 struct smb2_handle smb2_handle
;
102 } oplocks
[NSERVERS
][NINSTANCES
];
104 /* change notify reply info */
108 union smb_notify notify
;
109 } notifies
[NSERVERS
][NINSTANCES
];
111 /* info relevant to the current operation */
118 const char *mismatch
;
121 static struct smb2_handle bad_smb2_handle
;
124 #define BAD_HANDLE 0xFFFE
126 static bool oplock_handler_smb2(struct smb2_transport
*transport
, const struct smb2_handle
*handle
,
127 uint8_t level
, void *private_data
);
128 static void idle_func_smb2(struct smb2_transport
*transport
, void *private_data
);
129 static bool oplock_handler_smb(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private_data
);
130 static void idle_func_smb(struct smbcli_transport
*transport
, void *private_data
);
133 check if a string should be ignored. This is used as the basis
134 for all error ignore settings
136 static bool ignore_pattern(const char *str
)
139 if (!options
.ignore_patterns
) return false;
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
));
151 /*****************************************************
152 connect to the servers
153 *******************************************************/
154 static bool connect_servers_fast(void)
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
++) {
164 status
= smb2_util_close(servers
[i
].smb2_tree
[open_handles
[h
].instance
],
165 open_handles
[h
].smb2_handle
[i
]);
167 status
= smbcli_close(servers
[i
].smb_tree
[open_handles
[h
].instance
],
168 open_handles
[h
].smb_handle
[i
]);
170 if (NT_STATUS_IS_ERR(status
)) {
173 open_handles
[h
].active
= false;
183 /*****************************************************
184 connect to the servers
185 *******************************************************/
186 static bool connect_servers(struct tevent_context
*ev
,
187 struct loadparm_context
*lp_ctx
)
191 if (options
.fast_reconnect
&& servers
[0].smb2_tree
[0]) {
192 if (connect_servers_fast()) {
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
;
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
;
213 for (i
=0;i
<NSERVERS
;i
++) {
214 for (j
=0;j
<NINSTANCES
;j
++) {
216 struct smbcli_options smb_options
;
217 struct smbcli_session_options smb_session_options
;
218 lpcfg_smbcli_options(lp_ctx
, &smb_options
);
219 lpcfg_smbcli_session_options(lp_ctx
, &smb_session_options
);
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
);
225 cli_credentials_set_workstation(servers
[i
].credentials
,
226 "gentest", CRED_SPECIFIED
);
229 status
= smb2_connect(NULL
, servers
[i
].server_name
,
230 lpcfg_smb_ports(lp_ctx
),
231 servers
[i
].share_name
,
232 lpcfg_resolve_context(lp_ctx
),
233 servers
[i
].credentials
,
234 &servers
[i
].smb2_tree
[j
],
236 lpcfg_socket_options(lp_ctx
),
237 lpcfg_gensec_settings(lp_ctx
, lp_ctx
)
240 status
= smbcli_tree_full_connection(NULL
,
241 &servers
[i
].smb_tree
[j
],
242 servers
[i
].server_name
,
243 lpcfg_smb_ports(lp_ctx
),
244 servers
[i
].share_name
, "A:",
245 lpcfg_socket_options(lp_ctx
),
246 servers
[i
].credentials
,
247 lpcfg_resolve_context(lp_ctx
), ev
,
249 &smb_session_options
,
250 lpcfg_gensec_settings(lp_ctx
, lp_ctx
));
252 if (!NT_STATUS_IS_OK(status
)) {
253 printf("Failed to connect to \\\\%s\\%s - %s\n",
254 servers
[i
].server_name
, servers
[i
].share_name
,
260 servers
[i
].smb2_tree
[j
]->session
->transport
->oplock
.handler
= oplock_handler_smb2
;
261 servers
[i
].smb2_tree
[j
]->session
->transport
->oplock
.private_data
= (void *)(uintptr_t)((i
<<8)|j
);
262 smb2_transport_idle_handler(servers
[i
].smb2_tree
[j
]->session
->transport
,
263 idle_func_smb2
, 50000, NULL
);
265 smbcli_oplock_handler(servers
[i
].smb_tree
[j
]->session
->transport
, oplock_handler_smb
,
266 (void *)(uintptr_t)((i
<<8)|j
));
267 smbcli_transport_idle_handler(servers
[i
].smb_tree
[j
]->session
->transport
, idle_func_smb
,
268 50000, (void *)(uintptr_t)((i
<<8)|j
));
277 work out the time skew between the servers - be conservative
279 static unsigned int time_skew(void)
283 ret
= labs(servers
[0].smb2_tree
[0]->session
->transport
->negotiate
.system_time
-
284 servers
[1].smb2_tree
[0]->session
->transport
->negotiate
.system_time
);
286 ret
= labs(servers
[0].smb_tree
[0]->session
->transport
->negotiate
.server_time
-
287 servers
[1].smb_tree
[0]->session
->transport
->negotiate
.server_time
);
293 static bool smb2_handle_equal(const struct smb2_handle
*h1
, const struct smb2_handle
*h2
)
295 return memcmp(h1
, h2
, sizeof(struct smb2_handle
)) == 0;
299 turn a server handle into a local handle
301 static unsigned int fnum_to_handle_smb2(int server
, int instance
, struct smb2_handle server_handle
)
304 for (i
=0;i
<options
.max_open_handles
;i
++) {
305 if (!open_handles
[i
].active
||
306 instance
!= open_handles
[i
].instance
) continue;
307 if (smb2_handle_equal(&open_handles
[i
].smb2_handle
[server
], &server_handle
)) {
311 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
317 turn a server handle into a local handle
319 static unsigned int fnum_to_handle_smb(int server
, int instance
, uint16_t server_handle
)
322 for (i
=0;i
<options
.max_open_handles
;i
++) {
323 if (!open_handles
[i
].active
||
324 instance
!= open_handles
[i
].instance
) continue;
325 if (open_handles
[i
].smb_handle
[server
] == server_handle
) {
329 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
335 add some newly opened handles
337 static void gen_add_handle_smb2(int instance
, const char *name
, struct smb2_handle handles
[NSERVERS
])
340 for (h
=0;h
<options
.max_open_handles
;h
++) {
341 if (!open_handles
[h
].active
) break;
343 if (h
== options
.max_open_handles
) {
344 /* we have to force close a random handle */
345 h
= random() % options
.max_open_handles
;
346 for (i
=0;i
<NSERVERS
;i
++) {
348 status
= smb2_util_close(servers
[i
].smb2_tree
[open_handles
[h
].instance
],
349 open_handles
[h
].smb2_handle
[i
]);
350 if (NT_STATUS_IS_ERR(status
)) {
351 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
355 printf("Recovered handle %d\n", h
);
358 for (i
=0;i
<NSERVERS
;i
++) {
359 open_handles
[h
].smb2_handle
[i
] = handles
[i
];
360 open_handles
[h
].instance
= instance
;
361 open_handles
[h
].active
= true;
362 open_handles
[h
].name
= name
;
366 printf("OPEN num_open_handles=%d h=%d (%s)\n",
367 num_open_handles
, h
, name
);
371 add some newly opened handles
373 static void gen_add_handle_smb(int instance
, const char *name
, uint16_t handles
[NSERVERS
])
376 for (h
=0;h
<options
.max_open_handles
;h
++) {
377 if (!open_handles
[h
].active
) break;
379 if (h
== options
.max_open_handles
) {
380 /* we have to force close a random handle */
381 h
= random() % options
.max_open_handles
;
382 for (i
=0;i
<NSERVERS
;i
++) {
384 status
= smbcli_close(servers
[i
].smb_tree
[open_handles
[h
].instance
],
385 open_handles
[h
].smb_handle
[i
]);
386 if (NT_STATUS_IS_ERR(status
)) {
387 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
391 printf("Recovered handle %d\n", h
);
394 for (i
=0;i
<NSERVERS
;i
++) {
395 open_handles
[h
].smb_handle
[i
] = handles
[i
];
396 open_handles
[h
].instance
= instance
;
397 open_handles
[h
].active
= true;
398 open_handles
[h
].name
= name
;
402 printf("OPEN num_open_handles=%d h=%d (%s)\n",
403 num_open_handles
, h
, name
);
408 remove a closed handle
410 static void gen_remove_handle_smb2(int instance
, struct smb2_handle handles
[NSERVERS
])
413 for (h
=0;h
<options
.max_open_handles
;h
++) {
414 if (instance
== open_handles
[h
].instance
&&
415 smb2_handle_equal(&open_handles
[h
].smb2_handle
[0], &handles
[0])) {
416 open_handles
[h
].active
= false;
418 printf("CLOSE num_open_handles=%d h=%d (%s)\n",
420 open_handles
[h
].name
);
424 printf("Removing invalid handle!?\n");
429 remove a closed handle
431 static void gen_remove_handle_smb(int instance
, uint16_t handles
[NSERVERS
])
434 for (h
=0;h
<options
.max_open_handles
;h
++) {
435 if (instance
== open_handles
[h
].instance
&&
436 open_handles
[h
].smb_handle
[0] == handles
[0]) {
437 open_handles
[h
].active
= false;
439 printf("CLOSE num_open_handles=%d h=%d (%s)\n",
441 open_handles
[h
].name
);
445 printf("Removing invalid handle!?\n");
450 return true with 'chance' probability as a percentage
452 static bool gen_chance(unsigned int chance
)
454 return ((random() % 100) <= chance
);
458 map an internal handle number to a server handle
460 static struct smb2_handle
gen_lookup_handle_smb2(int server
, uint16_t handle
)
462 if (handle
== BAD_HANDLE
) return bad_smb2_handle
;
463 return open_handles
[handle
].smb2_handle
[server
];
467 map an internal handle number to a server handle
469 static uint16_t gen_lookup_handle_smb(int server
, uint16_t handle
)
471 if (handle
== BAD_HANDLE
) return BAD_HANDLE
;
472 return open_handles
[handle
].smb_handle
[server
];
478 static uint16_t gen_fnum(int instance
)
483 if (gen_chance(20)) return BAD_HANDLE
;
485 while (num_open_handles
> 0 && count
++ < 10*options
.max_open_handles
) {
486 h
= random() % options
.max_open_handles
;
487 if (open_handles
[h
].active
&&
488 open_handles
[h
].instance
== instance
) {
496 return a file handle, but skewed so we don't close the last
497 couple of handles too readily
499 static uint16_t gen_fnum_close(int instance
)
501 if (num_open_handles
< 5) {
502 if (gen_chance(90)) return BAD_HANDLE
;
505 return gen_fnum(instance
);
509 generate an integer in a specified range
511 static int gen_int_range(uint64_t min
, uint64_t max
)
513 unsigned int r
= random();
514 return min
+ (r
% (1+max
-min
));
518 return a fnum for use as a root fid
519 be careful to call GEN_SET_FNUM() when you use this!
521 static uint16_t gen_root_fid(int instance
)
523 if (gen_chance(5)) return gen_fnum(instance
);
528 generate a file offset
530 static int gen_offset(void)
532 if (gen_chance(20)) return 0;
533 // if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
534 return gen_int_range(0, 1024*1024);
540 static int gen_io_count(void)
542 if (gen_chance(20)) return 0;
543 // if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
544 return gen_int_range(0, 4096);
550 static const char *gen_fname(void)
552 const char *names
[] = {"gentest\\gentest.dat",
557 "gentest\\foo4:teststream1",
558 "gentest\\foo4:teststream2",
560 "gentest\\foo5.exe:teststream3",
561 "gentest\\foo5.exe:teststream4",
564 "gentest\\blah\\blergh.txt",
565 "gentest\\blah\\blergh2",
566 "gentest\\blah\\blergh3.txt",
567 "gentest\\blah\\blergh4",
568 "gentest\\blah\\blergh5.txt",
569 "gentest\\blah\\blergh5",
572 "gentest\\a_very_long_name.bin",
578 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
579 } while (ignore_pattern(names
[i
]));
585 generate a filename with a higher chance of choosing an already
588 static const char *gen_fname_open(int instance
)
591 h
= gen_fnum(instance
);
592 if (h
== BAD_HANDLE
) {
595 return open_handles
[h
].name
;
599 generate a wildcard pattern
601 static const char *gen_pattern(void)
604 const char *names
[] = {"gentest\\*.dat",
607 "gentest\\blah\\*.*",
611 if (gen_chance(50)) return gen_fname();
614 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
615 } while (ignore_pattern(names
[i
]));
620 static uint32_t gen_bits_levels(int nlevels
, ...)
626 va_start(ap
, nlevels
);
627 for (i
=0;i
<nlevels
;i
++) {
628 pct
= va_arg(ap
, uint32_t);
629 mask
= va_arg(ap
, uint32_t);
630 if (pct
== 100 || gen_chance(pct
)) {
632 return mask
& random();
642 static uint32_t gen_bits_mask(unsigned int mask
)
644 unsigned int ret
= random();
649 generate a bitmask with high probability of the first mask
650 and low of the second
652 static uint32_t gen_bits_mask2(uint32_t mask1
, uint32_t mask2
)
654 if (!options
.valid
&& gen_chance(10)) return gen_bits_mask(mask2
);
655 return gen_bits_mask(mask1
);
659 generate reserved values
661 static uint64_t gen_reserved8(void)
663 if (options
.valid
) return 0;
664 return gen_bits_mask(0xFF);
667 static uint64_t gen_reserved16(void)
669 if (options
.valid
) return 0;
670 return gen_bits_mask(0xFFFF);
673 static uint64_t gen_reserved32(void)
675 if (options
.valid
) return 0;
676 return gen_bits_mask(0xFFFFFFFF);
679 static uint64_t gen_reserved64(void)
681 if (options
.valid
) return 0;
682 return gen_bits_mask(0xFFFFFFFF) | (((uint64_t)gen_bits_mask(0xFFFFFFFF))<<32);
690 static bool gen_bool(void)
692 return gen_bits_mask2(0x1, 0xFF);
696 generate ntrename flags
698 static uint16_t gen_rename_flags(void)
700 if (gen_chance(30)) return RENAME_FLAG_RENAME
;
701 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK
;
702 if (gen_chance(30)) return RENAME_FLAG_COPY
;
703 return gen_bits_mask(0xFFFF);
709 static uint16_t gen_pid(void)
711 if (gen_chance(10)) return gen_bits_mask(0xFFFF);
716 return a set of lock flags
718 static uint16_t gen_lock_flags_smb2(void)
720 if (!options
.valid
&& gen_chance(5)) return gen_bits_mask(0xFFFF);
721 if (gen_chance(20)) return gen_bits_mask(0x1F);
722 if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK
;
723 return gen_bits_mask(SMB2_LOCK_FLAG_SHARED
|
724 SMB2_LOCK_FLAG_EXCLUSIVE
|
725 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
);
729 generate a lock count
731 static off_t
gen_lock_count(void)
733 return gen_int_range(0, 3);
737 generate a NT access mask
739 static uint32_t gen_access_mask(void)
742 if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED
;
743 if (gen_chance(70)) return SEC_FILE_ALL
;
744 ret
= gen_bits_mask(0xFFFFFFFF);
745 if (options
.valid
) ret
&= ~SEC_MASK_INVALID
;
750 return a lockingx lock mode
752 static uint16_t gen_lock_mode(void)
754 if (!options
.valid
&& gen_chance(5)) return gen_bits_mask(0xFFFF);
755 if (gen_chance(20)) return gen_bits_mask(0x1F);
756 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK
| LOCKING_ANDX_LARGE_FILES
);
760 generate a ntcreatex flags field
762 static uint32_t gen_ntcreatex_flags(void)
764 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED
;
765 return gen_bits_mask2(0x1F, 0xFFFFFFFF);
769 generate a ntcreatex create options bitfield
771 static uint32_t gen_create_options(void)
773 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
774 if (gen_chance(50)) return 0;
775 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE
| NTCREATEX_OPTIONS_DIRECTORY
);
779 generate a ntcreatex open disposition
781 static uint32_t gen_open_disp(void)
783 if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF
;
784 if (!options
.valid
&& gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
785 return gen_int_range(0, 5);
789 generate an openx open mode
791 static uint16_t gen_openx_mode(void)
793 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFF);
794 if (gen_chance(20)) return gen_bits_mask(0xFF);
795 return OPENX_MODE_DENY_NONE
| gen_bits_mask(0x3);
799 generate an openx flags field
801 static uint16_t gen_openx_flags(void)
803 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFF);
804 return gen_bits_mask(0x7);
808 generate an openx open function
810 static uint16_t gen_openx_func(void)
812 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFF);
813 return gen_bits_mask(0x13);
817 generate a file attrib combination
819 static uint32_t gen_attrib(void)
822 if (gen_chance(20)) {
823 ret
= gen_bits_mask(0xFFFFFFFF);
824 if (options
.valid
) ret
&= FILE_ATTRIBUTE_ALL_MASK
;
827 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_DIRECTORY
);
831 generate a unix timestamp
833 static time_t gen_timet(void)
835 if (gen_chance(30)) return 0;
836 return (time_t)random();
840 generate a milliseconds protocol timeout
842 static uint32_t gen_timeout(void)
844 if (gen_chance(98)) return 0;
845 return random() % 50;
851 static NTTIME
gen_nttime(void)
854 unix_to_nt_time(&ret
, gen_timet());
859 generate a timewarp value
861 static NTTIME
gen_timewarp(void)
863 NTTIME ret
= gen_nttime();
864 if (gen_chance(98)) ret
= 0;
869 generate a file allocation size
871 static unsigned int gen_alloc_size(void)
875 if (gen_chance(30)) return 0;
877 ret
= random() % 4*1024*1024;
878 /* give a high chance of a round number */
879 if (gen_chance(60)) {
880 ret
&= ~(1024*1024 - 1);
886 generate an ea_struct
888 static struct ea_struct
gen_ea_struct(void)
891 const char *names
[] = {"EAONE",
896 "AVERYLONGATTRIBUTENAME"};
897 const char *values
[] = {"VALUE1",
902 "ASOMEWHATLONGERATTRIBUTEVALUE"};
908 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
909 } while (ignore_pattern(names
[i
]));
911 ea
.name
.s
= names
[i
];
914 i
= gen_int_range(0, ARRAY_SIZE(values
)-1);
915 } while (ignore_pattern(values
[i
]));
917 ea
.value
= data_blob(values
[i
], strlen(values
[i
]));
919 if (gen_chance(10)) ea
.flags
= gen_bits_mask(0xFF);
926 generate an ea_struct
928 static struct smb_ea_list
gen_ea_list(void)
930 struct smb_ea_list eas
;
932 if (options
.no_eas
) {
936 eas
.num_eas
= gen_int_range(0, 3);
937 eas
.eas
= talloc_array(current_op
.mem_ctx
, struct ea_struct
, eas
.num_eas
);
938 for (i
=0;i
<eas
.num_eas
;i
++) {
939 eas
.eas
[i
] = gen_ea_struct();
944 /* generate a security descriptor */
945 static struct security_descriptor
*gen_sec_desc(void)
947 struct security_descriptor
*sd
;
948 if (options
.no_acls
|| gen_chance(90)) return NULL
;
950 sd
= security_descriptor_dacl_create(current_op
.mem_ctx
,
953 SEC_ACE_TYPE_ACCESS_ALLOWED
,
954 SEC_FILE_WRITE_DATA
| SEC_STD_WRITE_DAC
,
955 SEC_ACE_FLAG_OBJECT_INHERIT
,
957 SEC_ACE_TYPE_ACCESS_ALLOWED
,
958 SEC_FILE_ALL
| SEC_STD_ALL
,
965 static void oplock_handler_close_recv_smb(struct smbcli_request
*req
)
968 status
= smbcli_request_simple_recv(req
);
969 if (!NT_STATUS_IS_OK(status
)) {
970 printf("close failed in oplock_handler\n");
971 smb_panic("close failed in oplock_handler");
976 the oplock handler will either ack the break or close the file
978 static bool oplock_handler_smb(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private_data
)
983 struct smbcli_tree
*tree
= NULL
;
984 struct smbcli_request
*req
;
986 srandom(current_op
.seed
);
987 do_close
= gen_chance(50);
989 for (i
=0;i
<NSERVERS
;i
++) {
990 for (j
=0;j
<NINSTANCES
;j
++) {
991 if (transport
== servers
[i
].smb_tree
[j
]->session
->transport
&&
992 tid
== servers
[i
].smb_tree
[j
]->tid
) {
993 oplocks
[i
][j
].got_break
= true;
994 oplocks
[i
][j
].smb_handle
= fnum
;
995 oplocks
[i
][j
].handle
= fnum_to_handle_smb(i
, j
, fnum
);
996 oplocks
[i
][j
].level
= level
;
997 oplocks
[i
][j
].do_close
= do_close
;
998 tree
= servers
[i
].smb_tree
[j
];
1004 printf("Oplock break not for one of our trees!?\n");
1009 printf("oplock ack fnum=%d\n", fnum
);
1010 return smbcli_oplock_ack(tree
, fnum
, level
);
1013 printf("oplock close fnum=%d\n", fnum
);
1015 io
.close
.level
= RAW_CLOSE_CLOSE
;
1016 io
.close
.in
.file
.fnum
= fnum
;
1017 io
.close
.in
.write_time
= 0;
1018 req
= smb_raw_close_send(tree
, &io
);
1021 printf("WARNING: close failed in oplock_handler_close\n");
1025 req
->async
.fn
= oplock_handler_close_recv_smb
;
1026 req
->async
.private_data
= NULL
;
1033 the idle function tries to cope with getting an oplock break on a connection, and
1034 an operation on another connection blocking until that break is acked
1035 we check for operations on all transports in the idle function
1037 static void idle_func_smb(struct smbcli_transport
*transport
, void *private_data
)
1040 for (i
=0;i
<NSERVERS
;i
++) {
1041 for (j
=0;j
<NINSTANCES
;j
++) {
1042 if (servers
[i
].smb_tree
[j
] &&
1043 transport
!= servers
[i
].smb_tree
[j
]->session
->transport
) {
1044 smbcli_transport_process(servers
[i
].smb_tree
[j
]->session
->transport
);
1051 static void oplock_handler_close_recv_smb2(struct smb2_request
*req
)
1054 struct smb2_close io
;
1055 status
= smb2_close_recv(req
, &io
);
1056 if (!NT_STATUS_IS_OK(status
)) {
1057 printf("close failed in oplock_handler\n");
1058 smb_panic("close failed in oplock_handler");
1062 static void oplock_handler_ack_callback_smb2(struct smb2_request
*req
)
1065 struct smb2_break br
;
1067 status
= smb2_break_recv(req
, &br
);
1068 if (!NT_STATUS_IS_OK(status
)) {
1069 printf("oplock break ack failed in oplock_handler\n");
1070 smb_panic("oplock break ack failed in oplock_handler");
1074 static bool send_oplock_ack_smb2(struct smb2_tree
*tree
, struct smb2_handle handle
,
1077 struct smb2_break br
;
1078 struct smb2_request
*req
;
1081 br
.in
.file
.handle
= handle
;
1082 br
.in
.oplock_level
= level
;
1083 br
.in
.reserved
= gen_reserved8();
1084 br
.in
.reserved2
= gen_reserved32();
1086 req
= smb2_break_send(tree
, &br
);
1087 if (req
== NULL
) return false;
1088 req
->async
.fn
= oplock_handler_ack_callback_smb2
;
1089 req
->async
.private_data
= NULL
;
1094 the oplock handler will either ack the break or close the file
1096 static bool oplock_handler_smb2(struct smb2_transport
*transport
, const struct smb2_handle
*handle
,
1097 uint8_t level
, void *private_data
)
1099 struct smb2_close io
;
1102 struct smb2_tree
*tree
= NULL
;
1103 struct smb2_request
*req
;
1105 srandom(current_op
.seed
);
1106 do_close
= gen_chance(50);
1108 i
= ((uintptr_t)private_data
) >> 8;
1109 j
= ((uintptr_t)private_data
) & 0xFF;
1111 if (i
>= NSERVERS
|| j
>= NINSTANCES
) {
1112 printf("Bad private_data in oplock_handler\n");
1116 oplocks
[i
][j
].got_break
= true;
1117 oplocks
[i
][j
].smb2_handle
= *handle
;
1118 oplocks
[i
][j
].handle
= fnum_to_handle_smb2(i
, j
, *handle
);
1119 oplocks
[i
][j
].level
= level
;
1120 oplocks
[i
][j
].do_close
= do_close
;
1121 tree
= talloc_get_type(servers
[i
].smb2_tree
[j
], struct smb2_tree
);
1124 printf("Oplock break not for one of our trees!?\n");
1129 printf("oplock ack handle=%d\n", oplocks
[i
][j
].handle
);
1130 return send_oplock_ack_smb2(tree
, *handle
, level
);
1133 printf("oplock close fnum=%d\n", oplocks
[i
][j
].handle
);
1136 io
.in
.file
.handle
= *handle
;
1138 req
= smb2_close_send(tree
, &io
);
1141 printf("WARNING: close failed in oplock_handler_close\n");
1145 req
->async
.fn
= oplock_handler_close_recv_smb2
;
1146 req
->async
.private_data
= NULL
;
1153 the idle function tries to cope with getting an oplock break on a connection, and
1154 an operation on another connection blocking until that break is acked
1155 we check for operations on all transports in the idle function
1157 static void idle_func_smb2(struct smb2_transport
*transport
, void *private_data
)
1160 for (i
=0;i
<NSERVERS
;i
++) {
1161 for (j
=0;j
<NINSTANCES
;j
++) {
1162 if (servers
[i
].smb2_tree
[j
] &&
1163 transport
!= servers
[i
].smb2_tree
[j
]->session
->transport
) {
1164 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1173 compare NTSTATUS, using checking ignored patterns
1175 static bool compare_status(NTSTATUS status1
, NTSTATUS status2
)
1179 if (NT_STATUS_EQUAL(status1
, status2
)) return true;
1181 /* one code being an error and the other OK is always an error */
1182 if (NT_STATUS_IS_OK(status1
) || NT_STATUS_IS_OK(status2
)) {
1183 current_op
.mismatch
= nt_errstr(status1
);
1187 /* if we are ignoring one of the status codes then consider this a match */
1188 if (ignore_pattern(nt_errstr(status1
)) ||
1189 ignore_pattern(nt_errstr(status2
))) {
1193 /* also support ignore patterns of the form NT_STATUS_XX:NT_STATUS_YY
1194 meaning that the first server returns NT_STATUS_XX and the 2nd
1195 returns NT_STATUS_YY */
1196 s
= talloc_asprintf(current_op
.mem_ctx
, "%s:%s",
1198 nt_errstr(status2
));
1199 if (ignore_pattern(s
)) {
1203 current_op
.mismatch
= nt_errstr(status1
);
1208 check for pending packets on all connections
1210 static void check_pending(void)
1216 for (j
=0;j
<NINSTANCES
;j
++) {
1217 for (i
=0;i
<NSERVERS
;i
++) {
1218 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1224 check that the same oplock breaks have been received by all instances
1226 static bool check_oplocks(const char *call
)
1231 if (!options
.use_oplocks
|| options
.smb2
) {
1232 /* no smb2 oplocks in gentest yet */
1239 for (j
=0;j
<NINSTANCES
;j
++) {
1240 for (i
=1;i
<NSERVERS
;i
++) {
1241 if (oplocks
[0][j
].got_break
!= oplocks
[i
][j
].got_break
||
1242 oplocks
[0][j
].handle
!= oplocks
[i
][j
].handle
||
1243 oplocks
[0][j
].level
!= oplocks
[i
][j
].level
) {
1244 if (tries
++ < 10) goto again
;
1245 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
1246 oplocks
[0][j
].got_break
,
1247 oplocks
[0][j
].handle
,
1248 oplocks
[0][j
].level
,
1249 oplocks
[i
][j
].got_break
,
1250 oplocks
[i
][j
].handle
,
1251 oplocks
[i
][j
].level
);
1252 current_op
.mismatch
= "oplock break";
1258 /* if we got a break and closed then remove the handle */
1259 for (j
=0;j
<NINSTANCES
;j
++) {
1260 if (oplocks
[0][j
].got_break
&&
1261 oplocks
[0][j
].do_close
) {
1262 uint16_t fnums
[NSERVERS
];
1263 for (i
=0;i
<NSERVERS
;i
++) {
1264 fnums
[i
] = oplocks
[i
][j
].smb_handle
;
1266 gen_remove_handle_smb(j
, fnums
);
1275 check that the same change notify info has been received by all instances
1277 static bool check_notifies(const char *call
)
1283 /* no smb2 notifies in gentest yet */
1290 for (j
=0;j
<NINSTANCES
;j
++) {
1291 for (i
=1;i
<NSERVERS
;i
++) {
1293 union smb_notify not1
, not2
;
1295 if (notifies
[0][j
].notify_count
!= notifies
[i
][j
].notify_count
) {
1296 if (tries
++ < 10) goto again
;
1297 printf("Notify count inconsistent %d %d\n",
1298 notifies
[0][j
].notify_count
,
1299 notifies
[i
][j
].notify_count
);
1300 current_op
.mismatch
= "notify count";
1304 if (notifies
[0][j
].notify_count
== 0) continue;
1306 if (!NT_STATUS_EQUAL(notifies
[0][j
].status
,
1307 notifies
[i
][j
].status
)) {
1308 printf("Notify status mismatch - %s - %s\n",
1309 nt_errstr(notifies
[0][j
].status
),
1310 nt_errstr(notifies
[i
][j
].status
));
1311 current_op
.mismatch
= "Notify status";
1315 if (!NT_STATUS_IS_OK(notifies
[0][j
].status
)) {
1319 not1
= notifies
[0][j
].notify
;
1320 not2
= notifies
[i
][j
].notify
;
1322 for (n
=0;n
<not1
.nttrans
.out
.num_changes
;n
++) {
1323 if (not1
.nttrans
.out
.changes
[n
].action
!=
1324 not2
.nttrans
.out
.changes
[n
].action
) {
1325 printf("Notify action %d inconsistent %d %d\n", n
,
1326 not1
.nttrans
.out
.changes
[n
].action
,
1327 not2
.nttrans
.out
.changes
[n
].action
);
1328 current_op
.mismatch
= "notify action";
1331 if (strcmp(not1
.nttrans
.out
.changes
[n
].name
.s
,
1332 not2
.nttrans
.out
.changes
[n
].name
.s
)) {
1333 printf("Notify name %d inconsistent %s %s\n", n
,
1334 not1
.nttrans
.out
.changes
[n
].name
.s
,
1335 not2
.nttrans
.out
.changes
[n
].name
.s
);
1336 current_op
.mismatch
= "notify name";
1339 if (not1
.nttrans
.out
.changes
[n
].name
.private_length
!=
1340 not2
.nttrans
.out
.changes
[n
].name
.private_length
) {
1341 printf("Notify name length %d inconsistent %d %d\n", n
,
1342 not1
.nttrans
.out
.changes
[n
].name
.private_length
,
1343 not2
.nttrans
.out
.changes
[n
].name
.private_length
);
1344 current_op
.mismatch
= "notify name length";
1351 ZERO_STRUCT(notifies
);
1356 #define GEN_COPY_PARM do { \
1358 for (i=1;i<NSERVERS;i++) { \
1359 parm[i] = parm[0]; \
1363 #define GEN_CALL(call, treetype, treefield) do { \
1365 ZERO_STRUCT(oplocks); \
1366 ZERO_STRUCT(notifies); \
1367 for (i=0;i<NSERVERS;i++) { \
1368 struct treetype *tree = servers[i].treefield[instance]; \
1371 current_op.status = status[0]; \
1372 for (i=1;i<NSERVERS;i++) { \
1373 if (!compare_status(status[0], status[1])) { \
1374 printf("status different in %s - %s %s\n", #call, \
1375 nt_errstr(status[0]), nt_errstr(status[i])); \
1376 current_op.mismatch = nt_errstr(status[0]); \
1380 if (!check_oplocks(#call)) return false; \
1381 if (!check_notifies(#call)) return false; \
1382 if (!NT_STATUS_IS_OK(status[0])) { \
1387 #define GEN_CALL_SMB(call) GEN_CALL(call, smbcli_tree, smb_tree)
1388 #define GEN_CALL_SMB2(call) GEN_CALL(call, smb2_tree, smb2_tree)
1390 #define ADD_HANDLE_SMB2(name, field) do { \
1391 struct smb2_handle handles[NSERVERS]; \
1393 for (i=0;i<NSERVERS;i++) { \
1394 handles[i] = parm[i].field; \
1396 gen_add_handle_smb2(instance, name, handles); \
1399 #define REMOVE_HANDLE_SMB2(field) do { \
1400 struct smb2_handle handles[NSERVERS]; \
1402 for (i=0;i<NSERVERS;i++) { \
1403 handles[i] = parm[i].field; \
1405 gen_remove_handle_smb2(instance, handles); \
1408 #define ADD_HANDLE_SMB(name, field) do { \
1409 uint16_t handles[NSERVERS]; \
1411 for (i=0;i<NSERVERS;i++) { \
1412 handles[i] = parm[i].field; \
1414 gen_add_handle_smb(instance, name, handles); \
1417 #define REMOVE_HANDLE_SMB(field) do { \
1418 uint16_t handles[NSERVERS]; \
1420 for (i=0;i<NSERVERS;i++) { \
1421 handles[i] = parm[i].field; \
1423 gen_remove_handle_smb(instance, handles); \
1426 #define GEN_SET_FNUM_SMB2(field) do { \
1428 for (i=0;i<NSERVERS;i++) { \
1429 parm[i].field = gen_lookup_handle_smb2(i, parm[i].field.data[0]); \
1433 #define GEN_SET_FNUM_SMB(field) do { \
1435 for (i=0;i<NSERVERS;i++) { \
1436 parm[i].field = gen_lookup_handle_smb(i, parm[i].field); \
1440 #define CHECK_EQUAL(field) do { \
1441 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1442 current_op.mismatch = #field; \
1443 printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \
1444 (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \
1449 #define CHECK_SECDESC(field) do { \
1450 if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \
1451 current_op.mismatch = #field; \
1452 printf("Mismatch in %s\n", #field); \
1457 #define CHECK_ATTRIB(field) do { \
1458 if (!options.mask_indexing) { \
1459 CHECK_EQUAL(field); \
1460 } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \
1461 current_op.mismatch = #field; \
1462 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1463 (int)parm[0].field, (int)parm[1].field); \
1468 #define CHECK_WSTR_EQUAL(field) do { \
1469 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1470 current_op.mismatch = #field; \
1471 printf("%s is NULL!\n", #field); \
1474 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1475 current_op.mismatch = #field; \
1476 printf("Mismatch in %s - %s %s\n", #field, \
1477 parm[0].field.s, parm[1].field.s); \
1480 CHECK_EQUAL(field.private_length); \
1483 #define CHECK_BLOB_EQUAL(field) do { \
1484 if (((parm[0].field.data == NULL && parm[1].field.data != NULL) || \
1485 (parm[1].field.data == NULL && parm[0].field.data != NULL) || \
1486 (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0)) && !ignore_pattern(#field)) { \
1487 current_op.mismatch = #field; \
1488 printf("Mismatch in %s\n", #field); \
1491 CHECK_EQUAL(field.length); \
1494 #define CHECK_TIMES_EQUAL(field) do { \
1495 if (labs(parm[0].field - parm[1].field) > time_skew() && \
1496 !ignore_pattern(#field)) { \
1497 current_op.mismatch = #field; \
1498 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1499 (int)parm[0].field, (int)parm[1].field); \
1504 #define CHECK_NTTIMES_EQUAL(field) do { \
1505 if (labs(nt_time_to_unix(parm[0].field) - \
1506 nt_time_to_unix(parm[1].field)) > time_skew() && \
1507 !ignore_pattern(#field)) { \
1508 current_op.mismatch = #field; \
1509 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1510 (int)nt_time_to_unix(parm[0].field), \
1511 (int)nt_time_to_unix(parm[1].field)); \
1518 compare returned fileinfo structures
1520 static bool cmp_fileinfo(int instance
,
1521 union smb_fileinfo parm
[NSERVERS
],
1522 NTSTATUS status
[NSERVERS
])
1525 enum smb_fileinfo_level level
= parm
[0].generic
.level
;
1527 if (level
== RAW_FILEINFO_ALL_INFORMATION
&&
1529 level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
1533 case RAW_FILEINFO_GENERIC
:
1536 case RAW_FILEINFO_GETATTR
:
1537 CHECK_ATTRIB(getattr
.out
.attrib
);
1538 CHECK_EQUAL(getattr
.out
.size
);
1539 CHECK_TIMES_EQUAL(getattr
.out
.write_time
);
1542 case RAW_FILEINFO_GETATTRE
:
1543 CHECK_TIMES_EQUAL(getattre
.out
.create_time
);
1544 CHECK_TIMES_EQUAL(getattre
.out
.access_time
);
1545 CHECK_TIMES_EQUAL(getattre
.out
.write_time
);
1546 CHECK_EQUAL(getattre
.out
.size
);
1547 CHECK_EQUAL(getattre
.out
.alloc_size
);
1548 CHECK_ATTRIB(getattre
.out
.attrib
);
1551 case RAW_FILEINFO_STANDARD
:
1552 CHECK_TIMES_EQUAL(standard
.out
.create_time
);
1553 CHECK_TIMES_EQUAL(standard
.out
.access_time
);
1554 CHECK_TIMES_EQUAL(standard
.out
.write_time
);
1555 CHECK_EQUAL(standard
.out
.size
);
1556 CHECK_EQUAL(standard
.out
.alloc_size
);
1557 CHECK_ATTRIB(standard
.out
.attrib
);
1560 case RAW_FILEINFO_EA_SIZE
:
1561 CHECK_TIMES_EQUAL(ea_size
.out
.create_time
);
1562 CHECK_TIMES_EQUAL(ea_size
.out
.access_time
);
1563 CHECK_TIMES_EQUAL(ea_size
.out
.write_time
);
1564 CHECK_EQUAL(ea_size
.out
.size
);
1565 CHECK_EQUAL(ea_size
.out
.alloc_size
);
1566 CHECK_ATTRIB(ea_size
.out
.attrib
);
1567 CHECK_EQUAL(ea_size
.out
.ea_size
);
1570 case RAW_FILEINFO_ALL_EAS
:
1571 CHECK_EQUAL(all_eas
.out
.num_eas
);
1572 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1573 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1574 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1575 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1579 case RAW_FILEINFO_IS_NAME_VALID
:
1582 case RAW_FILEINFO_BASIC_INFO
:
1583 case RAW_FILEINFO_BASIC_INFORMATION
:
1584 CHECK_NTTIMES_EQUAL(basic_info
.out
.create_time
);
1585 CHECK_NTTIMES_EQUAL(basic_info
.out
.access_time
);
1586 CHECK_NTTIMES_EQUAL(basic_info
.out
.write_time
);
1587 CHECK_NTTIMES_EQUAL(basic_info
.out
.change_time
);
1588 CHECK_ATTRIB(basic_info
.out
.attrib
);
1591 case RAW_FILEINFO_STANDARD_INFO
:
1592 case RAW_FILEINFO_STANDARD_INFORMATION
:
1593 CHECK_EQUAL(standard_info
.out
.alloc_size
);
1594 CHECK_EQUAL(standard_info
.out
.size
);
1595 CHECK_EQUAL(standard_info
.out
.nlink
);
1596 CHECK_EQUAL(standard_info
.out
.delete_pending
);
1597 CHECK_EQUAL(standard_info
.out
.directory
);
1600 case RAW_FILEINFO_EA_INFO
:
1601 case RAW_FILEINFO_EA_INFORMATION
:
1602 CHECK_EQUAL(ea_info
.out
.ea_size
);
1605 case RAW_FILEINFO_NAME_INFO
:
1606 case RAW_FILEINFO_NAME_INFORMATION
:
1607 CHECK_WSTR_EQUAL(name_info
.out
.fname
);
1610 case RAW_FILEINFO_ALL_INFO
:
1611 case RAW_FILEINFO_ALL_INFORMATION
:
1612 CHECK_NTTIMES_EQUAL(all_info
.out
.create_time
);
1613 CHECK_NTTIMES_EQUAL(all_info
.out
.access_time
);
1614 CHECK_NTTIMES_EQUAL(all_info
.out
.write_time
);
1615 CHECK_NTTIMES_EQUAL(all_info
.out
.change_time
);
1616 CHECK_ATTRIB(all_info
.out
.attrib
);
1617 CHECK_EQUAL(all_info
.out
.alloc_size
);
1618 CHECK_EQUAL(all_info
.out
.size
);
1619 CHECK_EQUAL(all_info
.out
.nlink
);
1620 CHECK_EQUAL(all_info
.out
.delete_pending
);
1621 CHECK_EQUAL(all_info
.out
.directory
);
1622 CHECK_EQUAL(all_info
.out
.ea_size
);
1623 CHECK_WSTR_EQUAL(all_info
.out
.fname
);
1626 case RAW_FILEINFO_ALT_NAME_INFO
:
1627 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
1628 CHECK_WSTR_EQUAL(alt_name_info
.out
.fname
);
1631 case RAW_FILEINFO_STREAM_INFO
:
1632 case RAW_FILEINFO_STREAM_INFORMATION
:
1633 CHECK_EQUAL(stream_info
.out
.num_streams
);
1634 for (i
=0;i
<parm
[0].stream_info
.out
.num_streams
;i
++) {
1635 CHECK_EQUAL(stream_info
.out
.streams
[i
].size
);
1636 CHECK_EQUAL(stream_info
.out
.streams
[i
].alloc_size
);
1637 CHECK_WSTR_EQUAL(stream_info
.out
.streams
[i
].stream_name
);
1641 case RAW_FILEINFO_COMPRESSION_INFO
:
1642 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
1643 CHECK_EQUAL(compression_info
.out
.compressed_size
);
1644 CHECK_EQUAL(compression_info
.out
.format
);
1645 CHECK_EQUAL(compression_info
.out
.unit_shift
);
1646 CHECK_EQUAL(compression_info
.out
.chunk_shift
);
1647 CHECK_EQUAL(compression_info
.out
.cluster_shift
);
1650 case RAW_FILEINFO_INTERNAL_INFORMATION
:
1651 CHECK_EQUAL(internal_information
.out
.file_id
);
1654 case RAW_FILEINFO_ACCESS_INFORMATION
:
1655 CHECK_EQUAL(access_information
.out
.access_flags
);
1658 case RAW_FILEINFO_POSITION_INFORMATION
:
1659 CHECK_EQUAL(position_information
.out
.position
);
1662 case RAW_FILEINFO_MODE_INFORMATION
:
1663 CHECK_EQUAL(mode_information
.out
.mode
);
1666 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
1667 CHECK_EQUAL(alignment_information
.out
.alignment_requirement
);
1670 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
1671 CHECK_NTTIMES_EQUAL(network_open_information
.out
.create_time
);
1672 CHECK_NTTIMES_EQUAL(network_open_information
.out
.access_time
);
1673 CHECK_NTTIMES_EQUAL(network_open_information
.out
.write_time
);
1674 CHECK_NTTIMES_EQUAL(network_open_information
.out
.change_time
);
1675 CHECK_EQUAL(network_open_information
.out
.alloc_size
);
1676 CHECK_EQUAL(network_open_information
.out
.size
);
1677 CHECK_ATTRIB(network_open_information
.out
.attrib
);
1680 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
1681 CHECK_ATTRIB(attribute_tag_information
.out
.attrib
);
1682 CHECK_EQUAL(attribute_tag_information
.out
.reparse_tag
);
1685 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
1686 CHECK_NTTIMES_EQUAL(all_info2
.out
.create_time
);
1687 CHECK_NTTIMES_EQUAL(all_info2
.out
.access_time
);
1688 CHECK_NTTIMES_EQUAL(all_info2
.out
.write_time
);
1689 CHECK_NTTIMES_EQUAL(all_info2
.out
.change_time
);
1690 CHECK_ATTRIB(all_info2
.out
.attrib
);
1691 CHECK_EQUAL(all_info2
.out
.unknown1
);
1692 CHECK_EQUAL(all_info2
.out
.alloc_size
);
1693 CHECK_EQUAL(all_info2
.out
.size
);
1694 CHECK_EQUAL(all_info2
.out
.nlink
);
1695 CHECK_EQUAL(all_info2
.out
.delete_pending
);
1696 CHECK_EQUAL(all_info2
.out
.directory
);
1697 CHECK_EQUAL(all_info2
.out
.file_id
);
1698 CHECK_EQUAL(all_info2
.out
.ea_size
);
1699 CHECK_EQUAL(all_info2
.out
.access_mask
);
1700 CHECK_EQUAL(all_info2
.out
.position
);
1701 CHECK_EQUAL(all_info2
.out
.mode
);
1702 CHECK_EQUAL(all_info2
.out
.alignment_requirement
);
1703 CHECK_WSTR_EQUAL(all_info2
.out
.fname
);
1706 case RAW_FILEINFO_SMB2_ALL_EAS
:
1707 CHECK_EQUAL(all_eas
.out
.num_eas
);
1708 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1709 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1710 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1711 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1715 case RAW_FILEINFO_SEC_DESC
:
1716 CHECK_SECDESC(query_secdesc
.out
.sd
);
1719 /* Unhandled levels */
1720 case RAW_FILEINFO_EA_LIST
:
1721 case RAW_FILEINFO_UNIX_BASIC
:
1722 case RAW_FILEINFO_UNIX_LINK
:
1723 case RAW_FILEINFO_UNIX_INFO2
:
1733 generate openx operations
1735 static bool handler_smb_openx(int instance
)
1737 union smb_open parm
[NSERVERS
];
1738 NTSTATUS status
[NSERVERS
];
1740 parm
[0].openx
.level
= RAW_OPEN_OPENX
;
1741 parm
[0].openx
.in
.flags
= gen_openx_flags();
1742 parm
[0].openx
.in
.open_mode
= gen_openx_mode();
1743 parm
[0].openx
.in
.search_attrs
= gen_attrib();
1744 parm
[0].openx
.in
.file_attrs
= gen_attrib();
1745 parm
[0].openx
.in
.write_time
= gen_timet();
1746 parm
[0].openx
.in
.open_func
= gen_openx_func();
1747 parm
[0].openx
.in
.size
= gen_io_count();
1748 parm
[0].openx
.in
.timeout
= gen_timeout();
1749 parm
[0].openx
.in
.fname
= gen_fname_open(instance
);
1751 if (!options
.use_oplocks
) {
1752 /* mask out oplocks */
1753 parm
[0].openx
.in
.flags
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1754 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1758 GEN_CALL_SMB(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1760 CHECK_ATTRIB(openx
.out
.attrib
);
1761 CHECK_EQUAL(openx
.out
.size
);
1762 CHECK_EQUAL(openx
.out
.access
);
1763 CHECK_EQUAL(openx
.out
.ftype
);
1764 CHECK_EQUAL(openx
.out
.devstate
);
1765 CHECK_EQUAL(openx
.out
.action
);
1766 CHECK_EQUAL(openx
.out
.access_mask
);
1767 CHECK_EQUAL(openx
.out
.unknown
);
1768 CHECK_TIMES_EQUAL(openx
.out
.write_time
);
1770 /* open creates a new file handle */
1771 ADD_HANDLE_SMB(parm
[0].openx
.in
.fname
, openx
.out
.file
.fnum
);
1778 generate open operations
1780 static bool handler_smb_open(int instance
)
1782 union smb_open parm
[NSERVERS
];
1783 NTSTATUS status
[NSERVERS
];
1785 parm
[0].openold
.level
= RAW_OPEN_OPEN
;
1786 parm
[0].openold
.in
.open_mode
= gen_bits_mask2(0xF, 0xFFFF);
1787 parm
[0].openold
.in
.search_attrs
= gen_attrib();
1788 parm
[0].openold
.in
.fname
= gen_fname_open(instance
);
1790 if (!options
.use_oplocks
) {
1791 /* mask out oplocks */
1792 parm
[0].openold
.in
.open_mode
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1793 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1797 GEN_CALL_SMB(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1799 CHECK_ATTRIB(openold
.out
.attrib
);
1800 CHECK_TIMES_EQUAL(openold
.out
.write_time
);
1801 CHECK_EQUAL(openold
.out
.size
);
1802 CHECK_EQUAL(openold
.out
.rmode
);
1804 /* open creates a new file handle */
1805 ADD_HANDLE_SMB(parm
[0].openold
.in
.fname
, openold
.out
.file
.fnum
);
1812 generate ntcreatex operations
1814 static bool handler_smb_ntcreatex(int instance
)
1816 union smb_open parm
[NSERVERS
];
1817 NTSTATUS status
[NSERVERS
];
1819 parm
[0].ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
1820 parm
[0].ntcreatex
.in
.flags
= gen_ntcreatex_flags();
1821 parm
[0].ntcreatex
.in
.root_fid
.fnum
= gen_root_fid(instance
);
1822 parm
[0].ntcreatex
.in
.access_mask
= gen_access_mask();
1823 parm
[0].ntcreatex
.in
.alloc_size
= gen_alloc_size();
1824 parm
[0].ntcreatex
.in
.file_attr
= gen_attrib();
1825 parm
[0].ntcreatex
.in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
1826 parm
[0].ntcreatex
.in
.open_disposition
= gen_open_disp();
1827 parm
[0].ntcreatex
.in
.create_options
= gen_create_options();
1828 parm
[0].ntcreatex
.in
.impersonation
= gen_bits_mask2(0, 0xFFFFFFFF);
1829 parm
[0].ntcreatex
.in
.security_flags
= gen_bits_mask2(0, 0xFF);
1830 parm
[0].ntcreatex
.in
.fname
= gen_fname_open(instance
);
1832 if (!options
.use_oplocks
) {
1833 /* mask out oplocks */
1834 parm
[0].ntcreatex
.in
.flags
&= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK
|
1835 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
);
1839 if (parm
[0].ntcreatex
.in
.root_fid
.fnum
!= 0) {
1840 GEN_SET_FNUM_SMB(ntcreatex
.in
.root_fid
.fnum
);
1842 GEN_CALL_SMB(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1844 CHECK_EQUAL(ntcreatex
.out
.oplock_level
);
1845 CHECK_EQUAL(ntcreatex
.out
.create_action
);
1846 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.create_time
);
1847 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.access_time
);
1848 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.write_time
);
1849 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.change_time
);
1850 CHECK_ATTRIB(ntcreatex
.out
.attrib
);
1851 CHECK_EQUAL(ntcreatex
.out
.alloc_size
);
1852 CHECK_EQUAL(ntcreatex
.out
.size
);
1853 CHECK_EQUAL(ntcreatex
.out
.file_type
);
1854 CHECK_EQUAL(ntcreatex
.out
.ipc_state
);
1855 CHECK_EQUAL(ntcreatex
.out
.is_directory
);
1857 /* ntcreatex creates a new file handle */
1858 ADD_HANDLE_SMB(parm
[0].ntcreatex
.in
.fname
, ntcreatex
.out
.file
.fnum
);
1864 generate close operations
1866 static bool handler_smb_close(int instance
)
1868 union smb_close parm
[NSERVERS
];
1869 NTSTATUS status
[NSERVERS
];
1871 parm
[0].close
.level
= RAW_CLOSE_CLOSE
;
1872 parm
[0].close
.in
.file
.fnum
= gen_fnum_close(instance
);
1873 parm
[0].close
.in
.write_time
= gen_timet();
1876 GEN_SET_FNUM_SMB(close
.in
.file
.fnum
);
1877 GEN_CALL_SMB(smb_raw_close(tree
, &parm
[i
]));
1879 REMOVE_HANDLE_SMB(close
.in
.file
.fnum
);
1885 generate unlink operations
1887 static bool handler_smb_unlink(int instance
)
1889 union smb_unlink parm
[NSERVERS
];
1890 NTSTATUS status
[NSERVERS
];
1892 parm
[0].unlink
.in
.pattern
= gen_pattern();
1893 parm
[0].unlink
.in
.attrib
= gen_attrib();
1896 GEN_CALL_SMB(smb_raw_unlink(tree
, &parm
[i
]));
1902 generate chkpath operations
1904 static bool handler_smb_chkpath(int instance
)
1906 union smb_chkpath parm
[NSERVERS
];
1907 NTSTATUS status
[NSERVERS
];
1909 parm
[0].chkpath
.in
.path
= gen_fname_open(instance
);
1912 GEN_CALL_SMB(smb_raw_chkpath(tree
, &parm
[i
]));
1918 generate mkdir operations
1920 static bool handler_smb_mkdir(int instance
)
1922 union smb_mkdir parm
[NSERVERS
];
1923 NTSTATUS status
[NSERVERS
];
1925 parm
[0].mkdir
.level
= RAW_MKDIR_MKDIR
;
1926 parm
[0].mkdir
.in
.path
= gen_fname_open(instance
);
1929 GEN_CALL_SMB(smb_raw_mkdir(tree
, &parm
[i
]));
1935 generate rmdir operations
1937 static bool handler_smb_rmdir(int instance
)
1939 struct smb_rmdir parm
[NSERVERS
];
1940 NTSTATUS status
[NSERVERS
];
1942 parm
[0].in
.path
= gen_fname_open(instance
);
1945 GEN_CALL_SMB(smb_raw_rmdir(tree
, &parm
[i
]));
1951 generate rename operations
1953 static bool handler_smb_rename(int instance
)
1955 union smb_rename parm
[NSERVERS
];
1956 NTSTATUS status
[NSERVERS
];
1958 parm
[0].generic
.level
= RAW_RENAME_RENAME
;
1959 parm
[0].rename
.in
.pattern1
= gen_pattern();
1960 parm
[0].rename
.in
.pattern2
= gen_pattern();
1961 parm
[0].rename
.in
.attrib
= gen_attrib();
1964 GEN_CALL_SMB(smb_raw_rename(tree
, &parm
[i
]));
1970 generate ntrename operations
1972 static bool handler_smb_ntrename(int instance
)
1974 union smb_rename parm
[NSERVERS
];
1975 NTSTATUS status
[NSERVERS
];
1977 parm
[0].generic
.level
= RAW_RENAME_NTRENAME
;
1978 parm
[0].ntrename
.in
.old_name
= gen_fname();
1979 parm
[0].ntrename
.in
.new_name
= gen_fname();
1980 parm
[0].ntrename
.in
.attrib
= gen_attrib();
1981 parm
[0].ntrename
.in
.cluster_size
= gen_bits_mask2(0, 0xFFFFFFF);
1982 parm
[0].ntrename
.in
.flags
= gen_rename_flags();
1985 GEN_CALL_SMB(smb_raw_rename(tree
, &parm
[i
]));
1992 generate seek operations
1994 static bool handler_smb_seek(int instance
)
1996 union smb_seek parm
[NSERVERS
];
1997 NTSTATUS status
[NSERVERS
];
1999 parm
[0].lseek
.in
.file
.fnum
= gen_fnum(instance
);
2000 parm
[0].lseek
.in
.mode
= gen_bits_mask2(0x3, 0xFFFF);
2001 parm
[0].lseek
.in
.offset
= gen_offset();
2004 GEN_SET_FNUM_SMB(lseek
.in
.file
.fnum
);
2005 GEN_CALL_SMB(smb_raw_seek(tree
, &parm
[i
]));
2007 CHECK_EQUAL(lseek
.out
.offset
);
2014 generate readx operations
2016 static bool handler_smb_readx(int instance
)
2018 union smb_read parm
[NSERVERS
];
2019 NTSTATUS status
[NSERVERS
];
2021 parm
[0].readx
.level
= RAW_READ_READX
;
2022 parm
[0].readx
.in
.file
.fnum
= gen_fnum(instance
);
2023 parm
[0].readx
.in
.offset
= gen_offset();
2024 parm
[0].readx
.in
.mincnt
= gen_io_count();
2025 parm
[0].readx
.in
.maxcnt
= gen_io_count();
2026 parm
[0].readx
.in
.remaining
= gen_io_count();
2027 parm
[0].readx
.in
.read_for_execute
= gen_bool();
2028 parm
[0].readx
.out
.data
= talloc_array(current_op
.mem_ctx
, uint8_t,
2029 MAX(parm
[0].readx
.in
.mincnt
, parm
[0].readx
.in
.maxcnt
));
2032 GEN_SET_FNUM_SMB(readx
.in
.file
.fnum
);
2033 GEN_CALL_SMB(smb_raw_read(tree
, &parm
[i
]));
2035 CHECK_EQUAL(readx
.out
.remaining
);
2036 CHECK_EQUAL(readx
.out
.compaction_mode
);
2037 CHECK_EQUAL(readx
.out
.nread
);
2043 generate writex operations
2045 static bool handler_smb_writex(int instance
)
2047 union smb_write parm
[NSERVERS
];
2048 NTSTATUS status
[NSERVERS
];
2050 parm
[0].writex
.level
= RAW_WRITE_WRITEX
;
2051 parm
[0].writex
.in
.file
.fnum
= gen_fnum(instance
);
2052 parm
[0].writex
.in
.offset
= gen_offset();
2053 parm
[0].writex
.in
.wmode
= gen_bits_mask(0xFFFF);
2054 parm
[0].writex
.in
.remaining
= gen_io_count();
2055 parm
[0].writex
.in
.count
= gen_io_count();
2056 parm
[0].writex
.in
.data
= talloc_zero_array(current_op
.mem_ctx
, uint8_t, parm
[0].writex
.in
.count
);
2059 GEN_SET_FNUM_SMB(writex
.in
.file
.fnum
);
2060 GEN_CALL_SMB(smb_raw_write(tree
, &parm
[i
]));
2062 CHECK_EQUAL(writex
.out
.nwritten
);
2063 CHECK_EQUAL(writex
.out
.remaining
);
2069 generate lockingx operations
2071 static bool handler_smb_lockingx(int instance
)
2073 union smb_lock parm
[NSERVERS
];
2074 NTSTATUS status
[NSERVERS
];
2077 parm
[0].lockx
.level
= RAW_LOCK_LOCKX
;
2078 parm
[0].lockx
.in
.file
.fnum
= gen_fnum(instance
);
2079 parm
[0].lockx
.in
.mode
= gen_lock_mode();
2080 parm
[0].lockx
.in
.timeout
= gen_timeout();
2082 /* make sure we don't accidentially generate an oplock
2083 break ack - otherwise the server can just block forever */
2084 parm
[0].lockx
.in
.ulock_cnt
= gen_lock_count();
2085 parm
[0].lockx
.in
.lock_cnt
= gen_lock_count();
2086 nlocks
= parm
[0].lockx
.in
.ulock_cnt
+ parm
[0].lockx
.in
.lock_cnt
;
2087 } while (nlocks
== 0);
2090 parm
[0].lockx
.in
.locks
= talloc_array(current_op
.mem_ctx
,
2091 struct smb_lock_entry
,
2093 for (n
=0;n
<nlocks
;n
++) {
2094 parm
[0].lockx
.in
.locks
[n
].pid
= gen_pid();
2095 parm
[0].lockx
.in
.locks
[n
].offset
= gen_offset();
2096 parm
[0].lockx
.in
.locks
[n
].count
= gen_io_count();
2101 GEN_SET_FNUM_SMB(lockx
.in
.file
.fnum
);
2102 GEN_CALL_SMB(smb_raw_lock(tree
, &parm
[i
]));
2109 generate a fileinfo query structure
2111 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
2115 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2117 enum smb_setfileinfo_level level
;
2121 /* disabled until win2003 can handle them ... */
2122 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
2123 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
2125 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
2126 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
2127 LVL(POSITION_INFORMATION
), LVL(MODE_INFORMATION
),
2128 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
2129 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
2132 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
2133 } while (ignore_pattern(levels
[i
].name
));
2135 info
->generic
.level
= levels
[i
].level
;
2137 switch (info
->generic
.level
) {
2138 case RAW_SFILEINFO_SETATTR
:
2139 info
->setattr
.in
.attrib
= gen_attrib();
2140 info
->setattr
.in
.write_time
= gen_timet();
2142 case RAW_SFILEINFO_SETATTRE
:
2143 info
->setattre
.in
.create_time
= gen_timet();
2144 info
->setattre
.in
.access_time
= gen_timet();
2145 info
->setattre
.in
.write_time
= gen_timet();
2147 case RAW_SFILEINFO_STANDARD
:
2148 info
->standard
.in
.create_time
= gen_timet();
2149 info
->standard
.in
.access_time
= gen_timet();
2150 info
->standard
.in
.write_time
= gen_timet();
2152 case RAW_SFILEINFO_EA_SET
: {
2153 static struct ea_struct ea
;
2154 info
->ea_set
.in
.num_eas
= 1;
2155 info
->ea_set
.in
.eas
= &ea
;
2156 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
2159 case RAW_SFILEINFO_BASIC_INFO
:
2160 case RAW_SFILEINFO_BASIC_INFORMATION
:
2161 info
->basic_info
.in
.create_time
= gen_nttime();
2162 info
->basic_info
.in
.access_time
= gen_nttime();
2163 info
->basic_info
.in
.write_time
= gen_nttime();
2164 info
->basic_info
.in
.change_time
= gen_nttime();
2165 info
->basic_info
.in
.attrib
= gen_attrib();
2167 case RAW_SFILEINFO_DISPOSITION_INFO
:
2168 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
2169 info
->disposition_info
.in
.delete_on_close
= gen_bool();
2171 case RAW_SFILEINFO_ALLOCATION_INFO
:
2172 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
2173 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
2175 case RAW_SFILEINFO_END_OF_FILE_INFO
:
2176 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
2177 info
->end_of_file_info
.in
.size
= gen_offset();
2179 case RAW_SFILEINFO_RENAME_INFORMATION
:
2180 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2
:
2181 info
->rename_information
.in
.overwrite
= gen_bool();
2182 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
2183 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
2185 case RAW_SFILEINFO_POSITION_INFORMATION
:
2186 info
->position_information
.in
.position
= gen_offset();
2188 case RAW_SFILEINFO_MODE_INFORMATION
:
2189 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
2191 case RAW_SFILEINFO_FULL_EA_INFORMATION
:
2192 info
->full_ea_information
.in
.eas
= gen_ea_list();
2194 case RAW_SFILEINFO_GENERIC
:
2195 case RAW_SFILEINFO_SEC_DESC
:
2196 case RAW_SFILEINFO_UNIX_BASIC
:
2197 case RAW_SFILEINFO_UNIX_LINK
:
2198 case RAW_SFILEINFO_UNIX_HLINK
:
2199 case RAW_SFILEINFO_1023
:
2200 case RAW_SFILEINFO_1025
:
2201 case RAW_SFILEINFO_1029
:
2202 case RAW_SFILEINFO_1032
:
2203 case RAW_SFILEINFO_1039
:
2204 case RAW_SFILEINFO_1040
:
2205 case RAW_SFILEINFO_UNIX_INFO2
:
2213 generate a fileinfo query structure
2215 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
2219 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2221 enum smb_setfileinfo_level level
;
2224 struct levels smb_levels
[] = {
2225 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
2226 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
2227 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
2228 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
2229 LVL(POSITION_INFORMATION
), LVL(FULL_EA_INFORMATION
), LVL(MODE_INFORMATION
),
2230 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
2231 LVL(PIPE_INFORMATION
), LVL(VALID_DATA_INFORMATION
), LVL(SHORT_NAME_INFORMATION
),
2232 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2233 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2235 struct levels smb2_levels
[] = {
2236 LVL(BASIC_INFORMATION
),
2237 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
2238 LVL(POSITION_INFORMATION
), LVL(FULL_EA_INFORMATION
), LVL(MODE_INFORMATION
),
2239 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
2240 LVL(PIPE_INFORMATION
), LVL(VALID_DATA_INFORMATION
), LVL(SHORT_NAME_INFORMATION
),
2241 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2242 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2244 struct levels
*levels
= options
.smb2
?smb2_levels
:smb_levels
;
2245 uint32_t num_levels
= options
.smb2
?ARRAY_SIZE(smb2_levels
):ARRAY_SIZE(smb_levels
);
2248 i
= gen_int_range(0, num_levels
-1);
2249 } while (ignore_pattern(levels
[i
].name
));
2252 info
->generic
.level
= levels
[i
].level
;
2254 switch (info
->generic
.level
) {
2255 case RAW_SFILEINFO_SETATTR
:
2256 info
->setattr
.in
.attrib
= gen_attrib();
2257 info
->setattr
.in
.write_time
= gen_timet();
2259 case RAW_SFILEINFO_SETATTRE
:
2260 info
->setattre
.in
.create_time
= gen_timet();
2261 info
->setattre
.in
.access_time
= gen_timet();
2262 info
->setattre
.in
.write_time
= gen_timet();
2264 case RAW_SFILEINFO_STANDARD
:
2265 info
->standard
.in
.create_time
= gen_timet();
2266 info
->standard
.in
.access_time
= gen_timet();
2267 info
->standard
.in
.write_time
= gen_timet();
2269 case RAW_SFILEINFO_EA_SET
: {
2270 static struct ea_struct ea
;
2271 info
->ea_set
.in
.num_eas
= 1;
2272 info
->ea_set
.in
.eas
= &ea
;
2273 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
2276 case RAW_SFILEINFO_BASIC_INFO
:
2277 case RAW_SFILEINFO_BASIC_INFORMATION
:
2278 info
->basic_info
.in
.create_time
= gen_nttime();
2279 info
->basic_info
.in
.access_time
= gen_nttime();
2280 info
->basic_info
.in
.write_time
= gen_nttime();
2281 info
->basic_info
.in
.change_time
= gen_nttime();
2282 info
->basic_info
.in
.attrib
= gen_attrib();
2284 case RAW_SFILEINFO_DISPOSITION_INFO
:
2285 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
2286 info
->disposition_info
.in
.delete_on_close
= gen_bool();
2288 case RAW_SFILEINFO_ALLOCATION_INFO
:
2289 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
2290 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
2292 case RAW_SFILEINFO_END_OF_FILE_INFO
:
2293 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
2294 info
->end_of_file_info
.in
.size
= gen_offset();
2296 case RAW_SFILEINFO_RENAME_INFORMATION
:
2297 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2
:
2298 info
->rename_information
.in
.overwrite
= gen_bool();
2299 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
2300 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
2302 case RAW_SFILEINFO_POSITION_INFORMATION
:
2303 info
->position_information
.in
.position
= gen_offset();
2305 case RAW_SFILEINFO_MODE_INFORMATION
:
2306 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
2308 case RAW_SFILEINFO_FULL_EA_INFORMATION
:
2309 info
->full_ea_information
.in
.eas
= gen_ea_list();
2312 case RAW_SFILEINFO_GENERIC
:
2313 case RAW_SFILEINFO_SEC_DESC
:
2314 case RAW_SFILEINFO_1025
:
2315 case RAW_SFILEINFO_1029
:
2316 case RAW_SFILEINFO_1032
:
2317 case RAW_SFILEINFO_UNIX_BASIC
:
2318 case RAW_SFILEINFO_UNIX_INFO2
:
2319 case RAW_SFILEINFO_UNIX_LINK
:
2320 case RAW_SFILEINFO_UNIX_HLINK
:
2329 generate a fileinfo query structure
2331 static void gen_fileinfo_smb(int instance
, union smb_fileinfo
*info
)
2335 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2337 enum smb_fileinfo_level level
;
2340 LVL(GETATTR
), LVL(GETATTRE
), LVL(STANDARD
),
2341 LVL(EA_SIZE
), LVL(ALL_EAS
), LVL(IS_NAME_VALID
),
2342 LVL(BASIC_INFO
), LVL(STANDARD_INFO
), LVL(EA_INFO
),
2343 LVL(NAME_INFO
), LVL(ALL_INFO
), LVL(ALT_NAME_INFO
),
2344 LVL(STREAM_INFO
), LVL(COMPRESSION_INFO
), LVL(BASIC_INFORMATION
),
2345 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
2346 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
2347 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(ALL_INFORMATION
),
2348 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
2349 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
)
2352 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
2353 } while (ignore_pattern(levels
[i
].name
));
2355 info
->generic
.level
= levels
[i
].level
;
2359 generate qpathinfo operations
2361 static bool handler_smb_qpathinfo(int instance
)
2363 union smb_fileinfo parm
[NSERVERS
];
2364 NTSTATUS status
[NSERVERS
];
2366 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
2368 gen_fileinfo_smb(instance
, &parm
[0]);
2371 GEN_CALL_SMB(smb_raw_pathinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
2373 return cmp_fileinfo(instance
, parm
, status
);
2377 generate qfileinfo operations
2379 static bool handler_smb_qfileinfo(int instance
)
2381 union smb_fileinfo parm
[NSERVERS
];
2382 NTSTATUS status
[NSERVERS
];
2384 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
2386 gen_fileinfo_smb(instance
, &parm
[0]);
2389 GEN_SET_FNUM_SMB(generic
.in
.file
.fnum
);
2390 GEN_CALL_SMB(smb_raw_fileinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
2392 return cmp_fileinfo(instance
, parm
, status
);
2397 generate setpathinfo operations
2399 static bool handler_smb_spathinfo(int instance
)
2401 union smb_setfileinfo parm
[NSERVERS
];
2402 NTSTATUS status
[NSERVERS
];
2404 gen_setfileinfo(instance
, &parm
[0]);
2405 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
2409 /* a special case for the fid in a RENAME */
2410 if (parm
[0].generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
&&
2411 parm
[0].rename_information
.in
.root_fid
!= 0) {
2412 GEN_SET_FNUM_SMB(rename_information
.in
.root_fid
);
2415 GEN_CALL_SMB(smb_raw_setpathinfo(tree
, &parm
[i
]));
2422 generate setfileinfo operations
2424 static bool handler_smb_sfileinfo(int instance
)
2426 union smb_setfileinfo parm
[NSERVERS
];
2427 NTSTATUS status
[NSERVERS
];
2429 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
2431 gen_setfileinfo(instance
, &parm
[0]);
2434 GEN_SET_FNUM_SMB(generic
.in
.file
.fnum
);
2435 GEN_CALL_SMB(smb_raw_setfileinfo(tree
, &parm
[i
]));
2442 this is called when a change notify reply comes in
2444 static void async_notify_smb(struct smbcli_request
*req
)
2446 union smb_notify notify
;
2450 struct smbcli_transport
*transport
= req
->transport
;
2452 tid
= SVAL(req
->in
.hdr
, HDR_TID
);
2454 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
2455 status
= smb_raw_changenotify_recv(req
, current_op
.mem_ctx
, ¬ify
);
2456 if (NT_STATUS_IS_OK(status
) && notify
.nttrans
.out
.num_changes
> 0) {
2457 printf("notify tid=%d num_changes=%d action=%d name=%s\n",
2459 notify
.nttrans
.out
.num_changes
,
2460 notify
.nttrans
.out
.changes
[0].action
,
2461 notify
.nttrans
.out
.changes
[0].name
.s
);
2464 for (i
=0;i
<NSERVERS
;i
++) {
2465 for (j
=0;j
<NINSTANCES
;j
++) {
2466 if (transport
== servers
[i
].smb_tree
[j
]->session
->transport
&&
2467 tid
== servers
[i
].smb_tree
[j
]->tid
) {
2468 notifies
[i
][j
].notify_count
++;
2469 notifies
[i
][j
].status
= status
;
2470 notifies
[i
][j
].notify
= notify
;
2477 generate change notify operations
2479 static bool handler_smb_notify(int instance
)
2481 union smb_notify parm
[NSERVERS
];
2484 ZERO_STRUCT(parm
[0]);
2485 parm
[0].nttrans
.level
= RAW_NOTIFY_NTTRANS
;
2486 parm
[0].nttrans
.in
.buffer_size
= gen_io_count();
2487 parm
[0].nttrans
.in
.completion_filter
= gen_bits_mask(0xFF);
2488 parm
[0].nttrans
.in
.file
.fnum
= gen_fnum(instance
);
2489 parm
[0].nttrans
.in
.recursive
= gen_bool();
2492 GEN_SET_FNUM_SMB(nttrans
.in
.file
.fnum
);
2494 for (n
=0;n
<NSERVERS
;n
++) {
2495 struct smbcli_request
*req
;
2496 req
= smb_raw_changenotify_send(servers
[n
].smb_tree
[instance
], &parm
[n
]);
2497 req
->async
.fn
= async_notify_smb
;
2505 generate ntcreatex operations
2507 static bool handler_smb2_create(int instance
)
2509 struct smb2_create parm
[NSERVERS
];
2510 NTSTATUS status
[NSERVERS
];
2512 ZERO_STRUCT(parm
[0]);
2513 parm
[0].in
.security_flags
= gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF);
2514 parm
[0].in
.oplock_level
= gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF);
2515 parm
[0].in
.impersonation_level
= gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF);
2516 parm
[0].in
.create_flags
= gen_reserved64();
2517 parm
[0].in
.reserved
= gen_reserved64();
2518 parm
[0].in
.desired_access
= gen_access_mask();
2519 parm
[0].in
.file_attributes
= gen_attrib();
2520 parm
[0].in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
2521 parm
[0].in
.create_disposition
= gen_open_disp();
2522 parm
[0].in
.create_options
= gen_create_options();
2523 parm
[0].in
.fname
= gen_fname_open(instance
);
2524 parm
[0].in
.eas
= gen_ea_list();
2525 parm
[0].in
.alloc_size
= gen_alloc_size();
2526 parm
[0].in
.durable_open
= gen_bool();
2527 parm
[0].in
.query_maximal_access
= gen_bool();
2528 parm
[0].in
.timewarp
= gen_timewarp();
2529 parm
[0].in
.query_on_disk_id
= gen_bool();
2530 parm
[0].in
.sec_desc
= gen_sec_desc();
2532 if (!options
.use_oplocks
) {
2533 /* mask out oplocks */
2534 parm
[0].in
.oplock_level
= 0;
2537 if (options
.valid
) {
2538 parm
[0].in
.security_flags
&= 3;
2539 parm
[0].in
.oplock_level
&= 9;
2540 parm
[0].in
.impersonation_level
&= 3;
2544 GEN_CALL_SMB2(smb2_create(tree
, current_op
.mem_ctx
, &parm
[i
]));
2546 CHECK_EQUAL(out
.oplock_level
);
2547 CHECK_EQUAL(out
.reserved
);
2548 CHECK_EQUAL(out
.create_action
);
2549 CHECK_NTTIMES_EQUAL(out
.create_time
);
2550 CHECK_NTTIMES_EQUAL(out
.access_time
);
2551 CHECK_NTTIMES_EQUAL(out
.write_time
);
2552 CHECK_NTTIMES_EQUAL(out
.change_time
);
2553 CHECK_EQUAL(out
.alloc_size
);
2554 CHECK_EQUAL(out
.size
);
2555 CHECK_ATTRIB(out
.file_attr
);
2556 CHECK_EQUAL(out
.reserved2
);
2557 CHECK_EQUAL(out
.maximal_access
);
2559 /* ntcreatex creates a new file handle */
2560 ADD_HANDLE_SMB2(parm
[0].in
.fname
, out
.file
.handle
);
2566 generate close operations
2568 static bool handler_smb2_close(int instance
)
2570 struct smb2_close parm
[NSERVERS
];
2571 NTSTATUS status
[NSERVERS
];
2573 ZERO_STRUCT(parm
[0]);
2574 parm
[0].in
.file
.handle
.data
[0] = gen_fnum_close(instance
);
2575 parm
[0].in
.flags
= gen_bits_mask2(0x1, 0xFFFF);
2578 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2579 GEN_CALL_SMB2(smb2_close(tree
, &parm
[i
]));
2581 CHECK_EQUAL(out
.flags
);
2582 CHECK_EQUAL(out
._pad
);
2583 CHECK_NTTIMES_EQUAL(out
.create_time
);
2584 CHECK_NTTIMES_EQUAL(out
.access_time
);
2585 CHECK_NTTIMES_EQUAL(out
.write_time
);
2586 CHECK_NTTIMES_EQUAL(out
.change_time
);
2587 CHECK_EQUAL(out
.alloc_size
);
2588 CHECK_EQUAL(out
.size
);
2589 CHECK_ATTRIB(out
.file_attr
);
2591 REMOVE_HANDLE_SMB2(in
.file
.handle
);
2597 generate read operations
2599 static bool handler_smb2_read(int instance
)
2601 struct smb2_read parm
[NSERVERS
];
2602 NTSTATUS status
[NSERVERS
];
2604 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2605 parm
[0].in
.reserved
= gen_reserved8();
2606 parm
[0].in
.length
= gen_io_count();
2607 parm
[0].in
.offset
= gen_offset();
2608 parm
[0].in
.min_count
= gen_io_count();
2609 parm
[0].in
.channel
= gen_bits_mask2(0x0, 0xFFFFFFFF);
2610 parm
[0].in
.remaining
= gen_bits_mask2(0x0, 0xFFFFFFFF);
2611 parm
[0].in
.channel_offset
= gen_bits_mask2(0x0, 0xFFFF);
2612 parm
[0].in
.channel_length
= gen_bits_mask2(0x0, 0xFFFF);
2615 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2616 GEN_CALL_SMB2(smb2_read(tree
, current_op
.mem_ctx
, &parm
[i
]));
2618 CHECK_EQUAL(out
.remaining
);
2619 CHECK_EQUAL(out
.reserved
);
2620 CHECK_EQUAL(out
.data
.length
);
2626 generate write operations
2628 static bool handler_smb2_write(int instance
)
2630 struct smb2_write parm
[NSERVERS
];
2631 NTSTATUS status
[NSERVERS
];
2633 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2634 parm
[0].in
.offset
= gen_offset();
2635 parm
[0].in
.unknown1
= gen_bits_mask2(0, 0xFFFFFFFF);
2636 parm
[0].in
.unknown2
= gen_bits_mask2(0, 0xFFFFFFFF);
2637 parm
[0].in
.data
= data_blob_talloc(current_op
.mem_ctx
, NULL
,
2641 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2642 GEN_CALL_SMB2(smb2_write(tree
, &parm
[i
]));
2644 CHECK_EQUAL(out
._pad
);
2645 CHECK_EQUAL(out
.nwritten
);
2646 CHECK_EQUAL(out
.unknown1
);
2652 generate lockingx operations
2654 static bool handler_smb2_lock(int instance
)
2656 struct smb2_lock parm
[NSERVERS
];
2657 NTSTATUS status
[NSERVERS
];
2660 parm
[0].level
= RAW_LOCK_LOCKX
;
2661 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2662 parm
[0].in
.lock_count
= gen_lock_count();
2663 parm
[0].in
.lock_sequence
= gen_reserved32();
2665 parm
[0].in
.locks
= talloc_array(current_op
.mem_ctx
,
2666 struct smb2_lock_element
,
2667 parm
[0].in
.lock_count
);
2668 for (n
=0;n
<parm
[0].in
.lock_count
;n
++) {
2669 parm
[0].in
.locks
[n
].offset
= gen_offset();
2670 parm
[0].in
.locks
[n
].length
= gen_io_count();
2671 /* don't yet cope with async replies */
2672 parm
[0].in
.locks
[n
].flags
= gen_lock_flags_smb2() |
2673 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
2674 parm
[0].in
.locks
[n
].reserved
= gen_bits_mask2(0x0, 0xFFFFFFFF);
2678 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2679 GEN_CALL_SMB2(smb2_lock(tree
, &parm
[i
]));
2685 generate flush operations
2687 static bool handler_smb2_flush(int instance
)
2689 struct smb2_flush parm
[NSERVERS
];
2690 NTSTATUS status
[NSERVERS
];
2692 ZERO_STRUCT(parm
[0]);
2693 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2694 parm
[0].in
.reserved1
= gen_reserved16();
2695 parm
[0].in
.reserved2
= gen_reserved32();
2698 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2699 GEN_CALL_SMB2(smb2_flush(tree
, &parm
[i
]));
2701 CHECK_EQUAL(out
.reserved
);
2707 generate echo operations
2709 static bool handler_smb2_echo(int instance
)
2711 NTSTATUS status
[NSERVERS
];
2713 GEN_CALL_SMB2(smb2_keepalive(tree
->session
->transport
));
2721 generate a fileinfo query structure
2723 static void gen_fileinfo_smb2(int instance
, union smb_fileinfo
*info
)
2726 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2728 enum smb_fileinfo_level level
;
2731 LVL(BASIC_INFORMATION
),
2732 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
2733 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
2734 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(SMB2_ALL_INFORMATION
),
2735 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
2736 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
),
2737 LVL(SMB2_ALL_EAS
), LVL(SMB2_ALL_INFORMATION
), LVL(SEC_DESC
),
2740 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
2741 } while (ignore_pattern(levels
[i
].name
));
2743 info
->generic
.level
= levels
[i
].level
;
2747 generate qfileinfo operations
2749 static bool handler_smb2_qfileinfo(int instance
)
2751 union smb_fileinfo parm
[NSERVERS
];
2752 NTSTATUS status
[NSERVERS
];
2754 parm
[0].generic
.in
.file
.handle
.data
[0] = gen_fnum(instance
);
2756 gen_fileinfo_smb2(instance
, &parm
[0]);
2759 GEN_SET_FNUM_SMB2(generic
.in
.file
.handle
);
2760 GEN_CALL_SMB2(smb2_getinfo_file(tree
, current_op
.mem_ctx
, &parm
[i
]));
2762 return cmp_fileinfo(instance
, parm
, status
);
2767 generate setfileinfo operations
2769 static bool handler_smb2_sfileinfo(int instance
)
2771 union smb_setfileinfo parm
[NSERVERS
];
2772 NTSTATUS status
[NSERVERS
];
2774 gen_setfileinfo(instance
, &parm
[0]);
2775 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
2778 GEN_SET_FNUM_SMB2(generic
.in
.file
.handle
);
2779 GEN_CALL_SMB2(smb2_setinfo_file(tree
, &parm
[i
]));
2785 wipe any relevant files
2787 static void wipe_files(void)
2792 if (options
.skip_cleanup
) {
2796 for (i
=0;i
<NSERVERS
;i
++) {
2799 n
= smb2_deltree(servers
[i
].smb2_tree
[0], "gentest");
2801 n
= smbcli_deltree(servers
[i
].smb_tree
[0], "gentest");
2804 printf("Failed to wipe tree on server %d\n", i
);
2808 status
= smb2_util_mkdir(servers
[i
].smb2_tree
[0], "gentest");
2810 status
= smbcli_mkdir(servers
[i
].smb_tree
[0], "gentest");
2812 if (NT_STATUS_IS_ERR(status
)) {
2813 printf("Failed to create gentest on server %d - %s\n", i
, nt_errstr(status
));
2817 printf("Deleted %d files on server %d\n", n
, i
);
2823 dump the current seeds - useful for continuing a backtrack
2825 static void dump_seeds(void)
2830 if (!options
.seeds_file
) {
2833 f
= fopen("seeds.tmp", "w");
2836 for (i
=0;i
<options
.numops
;i
++) {
2837 fprintf(f
, "%u\n", op_parms
[i
].seed
);
2840 rename("seeds.tmp", options
.seeds_file
);
2846 the list of top-level operations that we will generate
2850 bool (*handler
)(int instance
);
2852 int count
, success_count
;
2854 {"CREATE", handler_smb2_create
, true},
2855 {"CLOSE", handler_smb2_close
, true},
2856 {"READ", handler_smb2_read
, true},
2857 {"WRITE", handler_smb2_write
, true},
2858 {"LOCK", handler_smb2_lock
, true},
2859 {"FLUSH", handler_smb2_flush
, true},
2860 {"ECHO", handler_smb2_echo
, true},
2861 {"QFILEINFO", handler_smb2_qfileinfo
, true},
2862 {"SFILEINFO", handler_smb2_sfileinfo
, true},
2864 {"OPEN", handler_smb_open
, false},
2865 {"OPENX", handler_smb_openx
, false},
2866 {"NTCREATEX", handler_smb_ntcreatex
, false},
2867 {"CLOSE", handler_smb_close
, false},
2868 {"UNLINK", handler_smb_unlink
, false},
2869 {"MKDIR", handler_smb_mkdir
, false},
2870 {"RMDIR", handler_smb_rmdir
, false},
2871 {"RENAME", handler_smb_rename
, false},
2872 {"NTRENAME", handler_smb_ntrename
, false},
2873 {"READX", handler_smb_readx
, false},
2874 {"WRITEX", handler_smb_writex
, false},
2875 {"CHKPATH", handler_smb_chkpath
, false},
2876 {"SEEK", handler_smb_seek
, false},
2877 {"LOCKINGX", handler_smb_lockingx
, false},
2878 {"QPATHINFO", handler_smb_qpathinfo
, false},
2879 {"QFILEINFO", handler_smb_qfileinfo
, false},
2880 {"SPATHINFO", handler_smb_spathinfo
, false},
2881 {"SFILEINFO", handler_smb_sfileinfo
, false},
2882 {"NOTIFY", handler_smb_notify
, false},
2883 {"SEEK", handler_smb_seek
, false},
2888 run the test with the current set of op_parms parameters
2889 return the number of operations that completed successfully
2891 static int run_test(struct tevent_context
*ev
, struct loadparm_context
*lp_ctx
)
2895 if (!connect_servers(ev
, lp_ctx
)) {
2896 printf("Failed to connect to servers\n");
2902 /* wipe any leftover files from old runs */
2905 /* reset the open handles array */
2906 memset(open_handles
, 0, options
.max_open_handles
* sizeof(open_handles
[0]));
2907 num_open_handles
= 0;
2909 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
2910 gen_ops
[i
].count
= 0;
2911 gen_ops
[i
].success_count
= 0;
2914 for (op
=0; op
<options
.numops
; op
++) {
2915 int instance
, which_op
;
2918 if (op_parms
[op
].disabled
) continue;
2920 srandom(op_parms
[op
].seed
);
2922 instance
= gen_int_range(0, NINSTANCES
-1);
2924 /* generate a non-ignored operation */
2926 which_op
= gen_int_range(0, ARRAY_SIZE(gen_ops
)-1);
2927 } while (ignore_pattern(gen_ops
[which_op
].name
) ||
2928 gen_ops
[which_op
].smb2
!= options
.smb2
);
2930 DEBUG(3,("Generating op %s on instance %d\n",
2931 gen_ops
[which_op
].name
, instance
));
2933 current_op
.seed
= op_parms
[op
].seed
;
2934 current_op
.opnum
= op
;
2935 current_op
.name
= gen_ops
[which_op
].name
;
2936 current_op
.status
= NT_STATUS_OK
;
2937 talloc_free(current_op
.mem_ctx
);
2938 current_op
.mem_ctx
= talloc_named(NULL
, 0, "%s", current_op
.name
);
2940 ret
= gen_ops
[which_op
].handler(instance
);
2942 gen_ops
[which_op
].count
++;
2943 if (NT_STATUS_IS_OK(current_op
.status
)) {
2944 gen_ops
[which_op
].success_count
++;
2948 printf("Failed at operation %d - %s\n",
2949 op
, gen_ops
[which_op
].name
);
2953 if (op
% 100 == 0) {
2958 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
2959 printf("Op %-10s got %d/%d success\n",
2961 gen_ops
[i
].success_count
,
2969 perform a backtracking analysis of the minimal set of operations
2970 to generate an error
2972 static void backtrack_analyze(struct tevent_context
*ev
,
2973 struct loadparm_context
*lp_ctx
)
2976 const char *mismatch
= current_op
.mismatch
;
2978 chunk
= options
.numops
/ 2;
2983 chunk
> 0 && base
+chunk
< options
.numops
&& options
.numops
> 1; ) {
2986 chunk
= MIN(chunk
, options
.numops
/ 2);
2988 /* mark this range as disabled */
2989 max
= MIN(options
.numops
, base
+chunk
);
2990 for (i
=base
;i
<max
; i
++) {
2991 op_parms
[i
].disabled
= true;
2993 printf("Testing %d ops with %d-%d disabled\n",
2994 options
.numops
, base
, max
-1);
2995 ret
= run_test(ev
, lp_ctx
);
2996 printf("Completed %d of %d ops\n", ret
, options
.numops
);
2997 for (i
=base
;i
<max
; i
++) {
2998 op_parms
[i
].disabled
= false;
3000 if (ret
== options
.numops
) {
3001 /* this chunk is needed */
3003 } else if (mismatch
!= current_op
.mismatch
&&
3004 strcmp(mismatch
, current_op
.mismatch
)) {
3006 printf("Different error in backtracking\n");
3007 } else if (ret
< base
) {
3008 printf("damn - inconsistent errors! found early error\n");
3009 options
.numops
= ret
+1;
3012 /* it failed - this chunk isn't needed for a failure */
3013 memmove(&op_parms
[base
], &op_parms
[max
],
3014 sizeof(op_parms
[0]) * (options
.numops
- max
));
3015 options
.numops
= (ret
+1) - (max
- base
);
3025 if (options
.analyze_continuous
&& chunk
== 0 && options
.numops
!= 1) {
3028 } while (chunk
> 0);
3030 printf("Reduced to %d ops\n", options
.numops
);
3031 ret
= run_test(ev
, lp_ctx
);
3032 if (ret
!= options
.numops
- 1) {
3033 printf("Inconsistent result? ret=%d numops=%d\n", ret
, options
.numops
);
3038 start the main gentest process
3040 static bool start_gentest(struct tevent_context
*ev
,
3041 struct loadparm_context
*lp_ctx
)
3046 /* allocate the open_handles array */
3047 open_handles
= calloc(options
.max_open_handles
, sizeof(open_handles
[0]));
3049 srandom(options
.seed
);
3050 op_parms
= calloc(options
.numops
, sizeof(op_parms
[0]));
3052 /* generate the seeds - after this everything is deterministic */
3053 if (options
.use_preset_seeds
) {
3055 char **preset
= file_lines_load(options
.seeds_file
, &numops
, 0, NULL
);
3057 printf("Failed to load %s - %s\n", options
.seeds_file
, strerror(errno
));
3060 if (numops
< options
.numops
) {
3061 options
.numops
= numops
;
3063 for (op
=0;op
<options
.numops
;op
++) {
3065 printf("Not enough seeds in %s\n", options
.seeds_file
);
3068 op_parms
[op
].seed
= atoi(preset
[op
]);
3070 printf("Loaded %d seeds from %s\n", options
.numops
, options
.seeds_file
);
3072 for (op
=0; op
<options
.numops
; op
++) {
3073 op_parms
[op
].seed
= random();
3077 ret
= run_test(ev
, lp_ctx
);
3079 if (ret
!= options
.numops
&& options
.analyze
) {
3080 options
.numops
= ret
+1;
3081 backtrack_analyze(ev
, lp_ctx
);
3082 } else if (options
.analyze_always
) {
3083 backtrack_analyze(ev
, lp_ctx
);
3084 } else if (options
.analyze_continuous
) {
3085 while (run_test(ev
, lp_ctx
) == options
.numops
) ;
3088 return ret
== options
.numops
;
3092 static void usage(poptContext pc
)
3096 gentest //server1/share1 //server2/share2 [options..]\n\
3098 poptPrintUsage(pc
, stdout
, 0);
3102 split a UNC name into server and share names
3104 static bool split_unc_name(const char *unc
, char **server
, char **share
)
3106 char *p
= strdup(unc
);
3107 if (!p
) return false;
3108 all_string_sub(p
, "\\", "/", 0);
3109 if (strncmp(p
, "//", 2) != 0) return false;
3112 p
= strchr(*server
, '/');
3113 if (!p
) return false;
3123 /****************************************************************************
3125 ****************************************************************************/
3126 int main(int argc
, char *argv
[])
3129 int i
, username_count
=0;
3131 char *ignore_file
=NULL
;
3132 struct tevent_context
*ev
;
3133 struct loadparm_context
*lp_ctx
;
3137 enum {OPT_UNCLIST
=1000};
3138 struct poptOption long_options
[] = {
3140 {"smb2", 0, POPT_ARG_NONE
, &options
.smb2
, 0, "use SMB2 protocol", NULL
},
3141 {"seed", 0, POPT_ARG_INT
, &options
.seed
, 0, "Seed to use for randomizer", NULL
},
3142 {"num-ops", 0, POPT_ARG_INT
, &options
.numops
, 0, "num ops", NULL
},
3143 {"oplocks", 0, POPT_ARG_NONE
, &options
.use_oplocks
,0, "use oplocks", NULL
},
3144 {"showall", 0, POPT_ARG_NONE
, &options
.showall
, 0, "display all operations", NULL
},
3145 {"analyse", 0, POPT_ARG_NONE
, &options
.analyze
, 0, "do backtrack analysis", NULL
},
3146 {"analysealways", 0, POPT_ARG_NONE
, &options
.analyze_always
, 0, "analysis always", NULL
},
3147 {"analysecontinuous", 0, POPT_ARG_NONE
, &options
.analyze_continuous
, 0, "analysis continuous", NULL
},
3148 {"ignore", 0, POPT_ARG_STRING
, &ignore_file
, 0, "ignore from file", NULL
},
3149 {"preset", 0, POPT_ARG_NONE
, &options
.use_preset_seeds
, 0, "use preset seeds", NULL
},
3150 {"fast", 0, POPT_ARG_NONE
, &options
.fast_reconnect
, 0, "use fast reconnect", NULL
},
3151 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
3152 {"seedsfile", 0, POPT_ARG_STRING
, &options
.seeds_file
, 0, "seed file", NULL
},
3153 { "user", 'U', POPT_ARG_STRING
, NULL
, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
3154 {"maskindexing", 0, POPT_ARG_NONE
, &options
.mask_indexing
, 0, "mask out the indexed file attrib", NULL
},
3155 {"noeas", 0, POPT_ARG_NONE
, &options
.no_eas
, 0, "don't use extended attributes", NULL
},
3156 {"noacls", 0, POPT_ARG_NONE
, &options
.no_acls
, 0, "don't use ACLs", NULL
},
3157 {"skip-cleanup", 0, POPT_ARG_NONE
, &options
.skip_cleanup
, 0, "don't delete files at start", NULL
},
3158 {"valid", 0, POPT_ARG_NONE
, &options
.valid
, 0, "generate only valid fields", NULL
},
3160 POPT_COMMON_CONNECTION
3161 POPT_COMMON_CREDENTIALS
3166 memset(&bad_smb2_handle
, 0xFF, sizeof(bad_smb2_handle
));
3169 options
.seed
= time(NULL
);
3170 options
.numops
= 1000;
3171 options
.max_open_handles
= 20;
3172 options
.seeds_file
= "gentest_seeds.dat";
3174 pc
= poptGetContext("gentest", argc
, (const char **) argv
, long_options
,
3175 POPT_CONTEXT_KEEP_FIRST
);
3177 poptSetOtherOptionHelp(pc
, "<unc1> <unc2>");
3179 lp_ctx
= cmdline_lp_ctx
;
3180 servers
[0].credentials
= cli_credentials_init(talloc_autofree_context());
3181 servers
[1].credentials
= cli_credentials_init(talloc_autofree_context());
3182 cli_credentials_guess(servers
[0].credentials
, lp_ctx
);
3183 cli_credentials_guess(servers
[1].credentials
, lp_ctx
);
3185 while((opt
= poptGetNextOpt(pc
)) != -1) {
3188 lpcfg_set_cmdline(cmdline_lp_ctx
, "torture:unclist", poptGetOptArg(pc
));
3191 if (username_count
== 2) {
3195 cli_credentials_parse_string(servers
[username_count
].credentials
, poptGetOptArg(pc
), CRED_SPECIFIED
);
3202 options
.ignore_patterns
= file_lines_load(ignore_file
, NULL
, 0, NULL
);
3205 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
3207 for (i
=0; i
<argc
; i
++) {
3208 if (argv_new
[i
] == NULL
) {
3214 if (!(argc_new
>= 3)) {
3221 setup_logging("gentest", DEBUG_STDOUT
);
3223 if (argc
< 3 || argv
[1][0] == '-') {
3228 setup_logging(argv
[0], DEBUG_STDOUT
);
3230 for (i
=0;i
<NSERVERS
;i
++) {
3231 const char *share
= argv
[1+i
];
3232 if (!split_unc_name(share
, &servers
[i
].server_name
, &servers
[i
].share_name
)) {
3233 printf("Invalid share name '%s'\n", share
);
3238 if (username_count
== 0) {
3242 if (username_count
== 1) {
3243 servers
[1].credentials
= servers
[0].credentials
;
3246 printf("seed=%u\n", options
.seed
);
3248 ev
= s4_event_context_init(talloc_autofree_context());
3250 gensec_init(lp_ctx
);
3252 ret
= start_gentest(ev
, lp_ctx
);
3255 printf("gentest completed - no errors\n");
3257 printf("gentest failed\n");