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/util/util_file.h"
24 #include "lib/cmdline/cmdline.h"
25 #include "lib/events/events.h"
26 #include "system/time.h"
27 #include "system/filesys.h"
28 #include "libcli/raw/request.h"
29 #include "libcli/libcli.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "libcli/smb2/smb2.h"
32 #include "libcli/smb2/smb2_calls.h"
33 #include "librpc/gen_ndr/security.h"
34 #include "librpc/gen_ndr/ndr_security.h"
35 #include "auth/credentials/credentials.h"
36 #include "libcli/resolve/resolve.h"
37 #include "auth/gensec/gensec.h"
38 #include "param/param.h"
39 #include "dynconfig/dynconfig.h"
40 #include "libcli/security/security.h"
41 #include "libcli/raw/raw_proto.h"
42 #include "../libcli/smb/smbXcli_base.h"
48 static struct gentest_options
{
52 int analyze_continuous
;
53 unsigned int max_open_handles
;
57 char **ignore_patterns
;
58 const char *seeds_file
;
69 /* mapping between open handles on the server and local handles */
72 unsigned int instance
;
73 struct smb2_handle smb2_handle
[NSERVERS
]; /* SMB2 */
74 uint16_t smb_handle
[NSERVERS
]; /* SMB */
77 static unsigned int num_open_handles
;
79 /* state information for the servers. We open NINSTANCES connections to
82 struct smb2_tree
*smb2_tree
[NINSTANCES
];
83 struct smbcli_tree
*smb_tree
[NINSTANCES
];
86 struct cli_credentials
*credentials
;
89 /* the seeds and flags for each operation */
96 /* oplock break info */
99 struct smb2_handle smb2_handle
;
104 } oplocks
[NSERVERS
][NINSTANCES
];
106 /* change notify reply info */
110 union smb_notify notify
;
111 } notifies
[NSERVERS
][NINSTANCES
];
113 /* info relevant to the current operation */
120 const char *mismatch
;
123 static struct smb2_handle bad_smb2_handle
;
126 #define BAD_HANDLE 0xFFFE
128 static bool oplock_handler_smb2(struct smb2_transport
*transport
, const struct smb2_handle
*handle
,
129 uint8_t level
, void *private_data
);
130 static void idle_func_smb2(struct smb2_transport
*transport
, void *private_data
);
131 static bool oplock_handler_smb(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private_data
);
132 static void idle_func_smb(struct smbcli_transport
*transport
, void *private_data
);
135 check if a string should be ignored. This is used as the basis
136 for all error ignore settings
138 static bool ignore_pattern(const char *str
)
141 if (!options
.ignore_patterns
) return false;
143 for (i
=0;options
.ignore_patterns
[i
];i
++) {
144 if (strcmp(options
.ignore_patterns
[i
], str
) == 0 ||
145 gen_fnmatch(options
.ignore_patterns
[i
], str
) == 0) {
146 DEBUG(2,("Ignoring '%s'\n", str
));
153 /*****************************************************
154 connect to the servers
155 *******************************************************/
156 static bool connect_servers_fast(void)
160 /* close all open files */
161 for (h
=0;h
<options
.max_open_handles
;h
++) {
162 if (!open_handles
[h
].active
) continue;
163 for (i
=0;i
<NSERVERS
;i
++) {
166 status
= smb2_util_close(servers
[i
].smb2_tree
[open_handles
[h
].instance
],
167 open_handles
[h
].smb2_handle
[i
]);
169 status
= smbcli_close(servers
[i
].smb_tree
[open_handles
[h
].instance
],
170 open_handles
[h
].smb_handle
[i
]);
172 if (NT_STATUS_IS_ERR(status
)) {
175 open_handles
[h
].active
= false;
185 /*****************************************************
186 connect to the servers
187 *******************************************************/
188 static bool connect_servers(struct tevent_context
*ev
,
189 struct loadparm_context
*lp_ctx
)
193 if (options
.fast_reconnect
&& servers
[0].smb2_tree
[0]) {
194 if (connect_servers_fast()) {
199 /* close any existing connections */
200 for (i
=0;i
<NSERVERS
;i
++) {
201 for (j
=0;j
<NINSTANCES
;j
++) {
202 if (servers
[i
].smb2_tree
[j
]) {
203 smb2_tdis(servers
[i
].smb2_tree
[j
]);
204 talloc_free(servers
[i
].smb2_tree
[j
]);
205 servers
[i
].smb2_tree
[j
] = NULL
;
207 if (servers
[i
].smb_tree
[j
]) {
208 smb_tree_disconnect(servers
[i
].smb_tree
[j
]);
209 talloc_free(servers
[i
].smb_tree
[j
]);
210 servers
[i
].smb_tree
[j
] = NULL
;
215 for (i
=0;i
<NSERVERS
;i
++) {
216 for (j
=0;j
<NINSTANCES
;j
++) {
218 struct smbcli_options smb_options
;
219 struct smbcli_session_options smb_session_options
;
220 lpcfg_smbcli_options(lp_ctx
, &smb_options
);
221 lpcfg_smbcli_session_options(lp_ctx
, &smb_session_options
);
223 printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
224 servers
[i
].server_name
, servers
[i
].share_name
,
225 cli_credentials_get_username(servers
[i
].credentials
),
228 cli_credentials_set_workstation(servers
[i
].credentials
,
229 "gentest", CRED_SPECIFIED
);
232 status
= smb2_connect(NULL
, servers
[i
].server_name
,
233 lpcfg_smb_ports(lp_ctx
),
234 servers
[i
].share_name
,
235 lpcfg_resolve_context(lp_ctx
),
236 servers
[i
].credentials
,
237 &servers
[i
].smb2_tree
[j
],
239 lpcfg_socket_options(lp_ctx
),
240 lpcfg_gensec_settings(lp_ctx
, lp_ctx
)
243 status
= smbcli_tree_full_connection(NULL
,
244 &servers
[i
].smb_tree
[j
],
245 servers
[i
].server_name
,
246 lpcfg_smb_ports(lp_ctx
),
247 servers
[i
].share_name
, "A:",
248 lpcfg_socket_options(lp_ctx
),
249 servers
[i
].credentials
,
250 lpcfg_resolve_context(lp_ctx
), ev
,
252 &smb_session_options
,
253 lpcfg_gensec_settings(lp_ctx
, lp_ctx
));
255 if (!NT_STATUS_IS_OK(status
)) {
256 printf("Failed to connect to \\\\%s\\%s - %s\n",
257 servers
[i
].server_name
, servers
[i
].share_name
,
263 servers
[i
].smb2_tree
[j
]->session
->transport
->oplock
.handler
= oplock_handler_smb2
;
264 servers
[i
].smb2_tree
[j
]->session
->transport
->oplock
.private_data
= (void *)(uintptr_t)((i
<<8)|j
);
265 smb2_transport_idle_handler(servers
[i
].smb2_tree
[j
]->session
->transport
,
266 idle_func_smb2
, 50000, NULL
);
268 smbcli_oplock_handler(servers
[i
].smb_tree
[j
]->session
->transport
, oplock_handler_smb
,
269 (void *)(uintptr_t)((i
<<8)|j
));
270 smbcli_transport_idle_handler(servers
[i
].smb_tree
[j
]->session
->transport
, idle_func_smb
,
271 50000, (void *)(uintptr_t)((i
<<8)|j
));
280 work out the time skew between the servers - be conservative
282 static unsigned int time_skew(void)
288 struct smbXcli_conn
*c0
, *c1
;
290 c0
= servers
[0].smb2_tree
[0]->session
->transport
->conn
;
291 c1
= servers
[1].smb2_tree
[0]->session
->transport
->conn
;
293 nt0
= smbXcli_conn_server_system_time(c0
);
294 nt1
= smbXcli_conn_server_system_time(c1
);
296 nt0
= servers
[0].smb_tree
[0]->session
->transport
->negotiate
.server_time
;
297 nt1
= servers
[1].smb_tree
[0]->session
->transport
->negotiate
.server_time
;
299 /* Samba's NTTIME is unsigned, abs() won't work! */
309 static bool smb2_handle_equal(const struct smb2_handle
*h1
, const struct smb2_handle
*h2
)
311 return memcmp(h1
, h2
, sizeof(struct smb2_handle
)) == 0;
315 turn a server handle into a local handle
317 static unsigned int fnum_to_handle_smb2(int server
, int instance
, struct smb2_handle server_handle
)
320 for (i
=0;i
<options
.max_open_handles
;i
++) {
321 if (!open_handles
[i
].active
||
322 instance
!= open_handles
[i
].instance
) continue;
323 if (smb2_handle_equal(&open_handles
[i
].smb2_handle
[server
], &server_handle
)) {
327 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
333 turn a server handle into a local handle
335 static unsigned int fnum_to_handle_smb(int server
, int instance
, uint16_t server_handle
)
338 for (i
=0;i
<options
.max_open_handles
;i
++) {
339 if (!open_handles
[i
].active
||
340 instance
!= open_handles
[i
].instance
) continue;
341 if (open_handles
[i
].smb_handle
[server
] == server_handle
) {
345 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
351 add some newly opened handles
353 static void gen_add_handle_smb2(int instance
, const char *name
, struct smb2_handle handles
[NSERVERS
])
356 for (h
=0;h
<options
.max_open_handles
;h
++) {
357 if (!open_handles
[h
].active
) break;
359 if (h
== options
.max_open_handles
) {
360 /* we have to force close a random handle */
361 h
= random() % options
.max_open_handles
;
362 for (i
=0;i
<NSERVERS
;i
++) {
364 status
= smb2_util_close(servers
[i
].smb2_tree
[open_handles
[h
].instance
],
365 open_handles
[h
].smb2_handle
[i
]);
366 if (NT_STATUS_IS_ERR(status
)) {
367 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
371 printf("Recovered handle %d\n", h
);
374 for (i
=0;i
<NSERVERS
;i
++) {
375 open_handles
[h
].smb2_handle
[i
] = handles
[i
];
376 open_handles
[h
].instance
= instance
;
377 open_handles
[h
].active
= true;
378 open_handles
[h
].name
= name
;
382 printf("OPEN num_open_handles=%d h=%d (%s)\n",
383 num_open_handles
, h
, name
);
387 add some newly opened handles
389 static void gen_add_handle_smb(int instance
, const char *name
, uint16_t handles
[NSERVERS
])
392 for (h
=0;h
<options
.max_open_handles
;h
++) {
393 if (!open_handles
[h
].active
) break;
395 if (h
== options
.max_open_handles
) {
396 /* we have to force close a random handle */
397 h
= random() % options
.max_open_handles
;
398 for (i
=0;i
<NSERVERS
;i
++) {
400 status
= smbcli_close(servers
[i
].smb_tree
[open_handles
[h
].instance
],
401 open_handles
[h
].smb_handle
[i
]);
402 if (NT_STATUS_IS_ERR(status
)) {
403 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
407 printf("Recovered handle %d\n", h
);
410 for (i
=0;i
<NSERVERS
;i
++) {
411 open_handles
[h
].smb_handle
[i
] = handles
[i
];
412 open_handles
[h
].instance
= instance
;
413 open_handles
[h
].active
= true;
414 open_handles
[h
].name
= name
;
418 printf("OPEN num_open_handles=%d h=%d (%s)\n",
419 num_open_handles
, h
, name
);
424 remove a closed handle
426 static void gen_remove_handle_smb2(int instance
, struct smb2_handle handles
[NSERVERS
])
429 for (h
=0;h
<options
.max_open_handles
;h
++) {
430 if (instance
== open_handles
[h
].instance
&&
431 smb2_handle_equal(&open_handles
[h
].smb2_handle
[0], &handles
[0])) {
432 open_handles
[h
].active
= false;
434 printf("CLOSE num_open_handles=%d h=%d (%s)\n",
436 open_handles
[h
].name
);
440 printf("Removing invalid handle!?\n");
445 remove a closed handle
447 static void gen_remove_handle_smb(int instance
, uint16_t handles
[NSERVERS
])
450 for (h
=0;h
<options
.max_open_handles
;h
++) {
451 if (instance
== open_handles
[h
].instance
&&
452 open_handles
[h
].smb_handle
[0] == handles
[0]) {
453 open_handles
[h
].active
= false;
455 printf("CLOSE num_open_handles=%d h=%d (%s)\n",
457 open_handles
[h
].name
);
461 printf("Removing invalid handle!?\n");
466 return true with 'chance' probability as a percentage
468 static bool gen_chance(unsigned int chance
)
470 return ((random() % 100) <= chance
);
474 map an internal handle number to a server handle
476 static struct smb2_handle
gen_lookup_handle_smb2(int server
, uint16_t handle
)
478 if (handle
== BAD_HANDLE
) return bad_smb2_handle
;
479 return open_handles
[handle
].smb2_handle
[server
];
483 map an internal handle number to a server handle
485 static uint16_t gen_lookup_handle_smb(int server
, uint16_t handle
)
487 if (handle
== BAD_HANDLE
) return BAD_HANDLE
;
488 return open_handles
[handle
].smb_handle
[server
];
494 static uint16_t gen_fnum(int instance
)
499 if (gen_chance(20)) return BAD_HANDLE
;
501 while (num_open_handles
> 0 && count
++ < 10*options
.max_open_handles
) {
502 h
= random() % options
.max_open_handles
;
503 if (open_handles
[h
].active
&&
504 open_handles
[h
].instance
== instance
) {
512 return a file handle, but skewed so we don't close the last
513 couple of handles too readily
515 static uint16_t gen_fnum_close(int instance
)
517 if (num_open_handles
< 5) {
518 if (gen_chance(90)) return BAD_HANDLE
;
521 return gen_fnum(instance
);
525 generate an integer in a specified range
527 static int gen_int_range(uint64_t min
, uint64_t max
)
529 unsigned int r
= random();
530 return min
+ (r
% (1+max
-min
));
534 return a fnum for use as a root fid
535 be careful to call GEN_SET_FNUM() when you use this!
537 static uint16_t gen_root_fid(int instance
)
539 if (gen_chance(5)) return gen_fnum(instance
);
544 generate a file offset
546 static int gen_offset(void)
548 if (gen_chance(20)) return 0;
549 // if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
550 return gen_int_range(0, 1024*1024);
556 static int gen_io_count(void)
558 if (gen_chance(20)) return 0;
559 // if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
560 return gen_int_range(0, 4096);
566 static const char *gen_fname(void)
568 const char *names
[] = {"gentest\\gentest.dat",
573 "gentest\\foo4:teststream1",
574 "gentest\\foo4:teststream2",
576 "gentest\\foo5.exe:teststream3",
577 "gentest\\foo5.exe:teststream4",
580 "gentest\\blah\\blergh.txt",
581 "gentest\\blah\\blergh2",
582 "gentest\\blah\\blergh3.txt",
583 "gentest\\blah\\blergh4",
584 "gentest\\blah\\blergh5.txt",
585 "gentest\\blah\\blergh5",
588 "gentest\\a_very_long_name.bin",
594 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
595 } while (ignore_pattern(names
[i
]));
601 generate a filename with a higher chance of choosing an already
604 static const char *gen_fname_open(int instance
)
607 h
= gen_fnum(instance
);
608 if (h
== BAD_HANDLE
) {
611 return open_handles
[h
].name
;
615 generate a wildcard pattern
617 static const char *gen_pattern(void)
620 const char *names
[] = {"gentest\\*.dat",
623 "gentest\\blah\\*.*",
627 if (gen_chance(50)) return gen_fname();
630 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
631 } while (ignore_pattern(names
[i
]));
636 static uint32_t gen_bits_levels(int nlevels
, ...)
642 va_start(ap
, nlevels
);
643 for (i
=0;i
<nlevels
;i
++) {
644 pct
= va_arg(ap
, uint32_t);
645 mask
= va_arg(ap
, uint32_t);
646 if (pct
== 100 || gen_chance(pct
)) {
648 return mask
& random();
658 static uint32_t gen_bits_mask(unsigned int mask
)
660 unsigned int ret
= random();
665 generate a bitmask with high probability of the first mask
666 and low of the second
668 static uint32_t gen_bits_mask2(uint32_t mask1
, uint32_t mask2
)
670 if (!options
.valid
&& gen_chance(10)) return gen_bits_mask(mask2
);
671 return gen_bits_mask(mask1
);
675 generate reserved values
677 static uint64_t gen_reserved8(void)
679 if (options
.valid
) return 0;
680 return gen_bits_mask(0xFF);
683 static uint64_t gen_reserved16(void)
685 if (options
.valid
) return 0;
686 return gen_bits_mask(0xFFFF);
689 static uint64_t gen_reserved32(void)
691 if (options
.valid
) return 0;
692 return gen_bits_mask(0xFFFFFFFF);
695 static uint64_t gen_reserved64(void)
697 if (options
.valid
) return 0;
698 return gen_bits_mask(0xFFFFFFFF) | (((uint64_t)gen_bits_mask(0xFFFFFFFF))<<32);
706 static bool gen_bool(void)
708 return gen_bits_mask2(0x1, 0xFF);
712 generate ntrename flags
714 static uint16_t gen_rename_flags(void)
716 if (gen_chance(30)) return RENAME_FLAG_RENAME
;
717 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK
;
718 if (gen_chance(30)) return RENAME_FLAG_COPY
;
719 return gen_bits_mask(0xFFFF);
725 static uint16_t gen_pid(void)
727 if (gen_chance(10)) return gen_bits_mask(0xFFFF);
732 return a set of lock flags
734 static uint16_t gen_lock_flags_smb2(void)
736 if (!options
.valid
&& gen_chance(5)) return gen_bits_mask(0xFFFF);
737 if (gen_chance(20)) return gen_bits_mask(0x1F);
738 if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK
;
739 return gen_bits_mask(SMB2_LOCK_FLAG_SHARED
|
740 SMB2_LOCK_FLAG_EXCLUSIVE
|
741 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
);
745 generate a lock count
747 static off_t
gen_lock_count(void)
749 return gen_int_range(0, 3);
753 generate a NT access mask
755 static uint32_t gen_access_mask(void)
758 if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED
;
759 if (gen_chance(70)) return SEC_FILE_ALL
;
760 ret
= gen_bits_mask(0xFFFFFFFF);
761 if (options
.valid
) ret
&= ~SEC_MASK_INVALID
;
766 return a lockingx lock mode
768 static uint16_t gen_lock_mode(void)
770 if (!options
.valid
&& gen_chance(5)) return gen_bits_mask(0xFFFF);
771 if (gen_chance(20)) return gen_bits_mask(0x1F);
772 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK
| LOCKING_ANDX_LARGE_FILES
);
776 generate a ntcreatex flags field
778 static uint32_t gen_ntcreatex_flags(void)
780 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED
;
781 return gen_bits_mask2(0x1F, 0xFFFFFFFF);
785 generate a ntcreatex create options bitfield
787 static uint32_t gen_create_options(void)
789 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
790 if (gen_chance(50)) return 0;
791 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE
| NTCREATEX_OPTIONS_DIRECTORY
);
795 generate a ntcreatex open disposition
797 static uint32_t gen_open_disp(void)
799 if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF
;
800 if (!options
.valid
&& gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
801 return gen_int_range(0, 5);
805 generate an openx open mode
807 static uint16_t gen_openx_mode(void)
809 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFF);
810 if (gen_chance(20)) return gen_bits_mask(0xFF);
811 return OPENX_MODE_DENY_NONE
| gen_bits_mask(0x3);
815 generate an openx flags field
817 static uint16_t gen_openx_flags(void)
819 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFF);
820 return gen_bits_mask(0x7);
824 generate an openx open function
826 static uint16_t gen_openx_func(void)
828 if (!options
.valid
&& gen_chance(20)) return gen_bits_mask(0xFFFF);
829 return gen_bits_mask(0x13);
833 generate a file attrib combination
835 static uint32_t gen_attrib(void)
838 if (gen_chance(20)) {
839 ret
= gen_bits_mask(0xFFFFFFFF);
840 if (options
.valid
) ret
&= FILE_ATTRIBUTE_ALL_MASK
;
843 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_DIRECTORY
);
847 generate a unix timestamp
849 static time_t gen_timet(void)
851 if (gen_chance(30)) return 0;
852 return (time_t)random();
856 generate a milliseconds protocol timeout
858 static uint32_t gen_timeout(void)
860 if (gen_chance(98)) return 0;
861 return random() % 50;
867 static NTTIME
gen_nttime(void)
870 unix_to_nt_time(&ret
, gen_timet());
875 generate a timewarp value
877 static NTTIME
gen_timewarp(void)
879 NTTIME ret
= gen_nttime();
880 if (gen_chance(98)) ret
= 0;
885 generate a file allocation size
887 static unsigned int gen_alloc_size(void)
891 if (gen_chance(30)) return 0;
893 ret
= random() % 4*1024*1024;
894 /* give a high chance of a round number */
895 if (gen_chance(60)) {
896 ret
&= ~(1024*1024 - 1);
902 generate an ea_struct
904 static struct ea_struct
gen_ea_struct(void)
907 const char *names
[] = {"EAONE",
912 "AVERYLONGATTRIBUTENAME"};
913 const char *values
[] = {"VALUE1",
918 "ASOMEWHATLONGERATTRIBUTEVALUE"};
924 i
= gen_int_range(0, ARRAY_SIZE(names
)-1);
925 } while (ignore_pattern(names
[i
]));
927 ea
.name
.s
= names
[i
];
930 i
= gen_int_range(0, ARRAY_SIZE(values
)-1);
931 } while (ignore_pattern(values
[i
]));
933 ea
.value
= data_blob(values
[i
], strlen(values
[i
]));
935 if (gen_chance(10)) ea
.flags
= gen_bits_mask(0xFF);
942 generate an ea_struct
944 static struct smb_ea_list
gen_ea_list(void)
946 struct smb_ea_list eas
;
948 if (options
.no_eas
) {
952 eas
.num_eas
= gen_int_range(0, 3);
953 eas
.eas
= talloc_array(current_op
.mem_ctx
, struct ea_struct
, eas
.num_eas
);
954 for (i
=0;i
<eas
.num_eas
;i
++) {
955 eas
.eas
[i
] = gen_ea_struct();
960 /* generate a security descriptor */
961 static struct security_descriptor
*gen_sec_desc(void)
963 struct security_descriptor
*sd
;
964 if (options
.no_acls
|| gen_chance(90)) return NULL
;
966 sd
= security_descriptor_dacl_create(current_op
.mem_ctx
,
969 SEC_ACE_TYPE_ACCESS_ALLOWED
,
970 SEC_FILE_WRITE_DATA
| SEC_STD_WRITE_DAC
,
971 SEC_ACE_FLAG_OBJECT_INHERIT
,
973 SEC_ACE_TYPE_ACCESS_ALLOWED
,
974 SEC_FILE_ALL
| SEC_STD_ALL
,
981 static void oplock_handler_close_recv_smb(struct smbcli_request
*req
)
984 status
= smbcli_request_simple_recv(req
);
985 if (!NT_STATUS_IS_OK(status
)) {
986 printf("close failed in oplock_handler\n");
987 smb_panic("close failed in oplock_handler");
992 the oplock handler will either ack the break or close the file
994 static bool oplock_handler_smb(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *private_data
)
999 struct smbcli_tree
*tree
= NULL
;
1000 struct smbcli_request
*req
;
1002 srandom(current_op
.seed
);
1003 do_close
= gen_chance(50);
1005 for (i
=0;i
<NSERVERS
;i
++) {
1006 for (j
=0;j
<NINSTANCES
;j
++) {
1007 if (transport
== servers
[i
].smb_tree
[j
]->session
->transport
&&
1008 tid
== servers
[i
].smb_tree
[j
]->tid
) {
1009 oplocks
[i
][j
].got_break
= true;
1010 oplocks
[i
][j
].smb_handle
= fnum
;
1011 oplocks
[i
][j
].handle
= fnum_to_handle_smb(i
, j
, fnum
);
1012 oplocks
[i
][j
].level
= level
;
1013 oplocks
[i
][j
].do_close
= do_close
;
1014 tree
= servers
[i
].smb_tree
[j
];
1020 printf("Oplock break not for one of our trees!?\n");
1025 printf("oplock ack fnum=%d\n", fnum
);
1026 return smbcli_oplock_ack(tree
, fnum
, level
);
1029 printf("oplock close fnum=%d\n", fnum
);
1031 io
.close
.level
= RAW_CLOSE_CLOSE
;
1032 io
.close
.in
.file
.fnum
= fnum
;
1033 io
.close
.in
.write_time
= 0;
1034 req
= smb_raw_close_send(tree
, &io
);
1037 printf("WARNING: close failed in oplock_handler_close\n");
1041 req
->async
.fn
= oplock_handler_close_recv_smb
;
1042 req
->async
.private_data
= NULL
;
1049 the idle function tries to cope with getting an oplock break on a connection, and
1050 an operation on another connection blocking until that break is acked
1051 we check for operations on all transports in the idle function
1053 static void idle_func_smb(struct smbcli_transport
*transport
, void *private_data
)
1056 for (i
=0;i
<NSERVERS
;i
++) {
1057 for (j
=0;j
<NINSTANCES
;j
++) {
1058 if (servers
[i
].smb_tree
[j
] &&
1059 transport
!= servers
[i
].smb_tree
[j
]->session
->transport
) {
1060 smbcli_transport_process(servers
[i
].smb_tree
[j
]->session
->transport
);
1067 static void oplock_handler_close_recv_smb2(struct smb2_request
*req
)
1070 struct smb2_close io
;
1071 status
= smb2_close_recv(req
, &io
);
1072 if (!NT_STATUS_IS_OK(status
)) {
1073 printf("close failed in oplock_handler\n");
1074 smb_panic("close failed in oplock_handler");
1078 static void oplock_handler_ack_callback_smb2(struct smb2_request
*req
)
1081 struct smb2_break br
;
1083 status
= smb2_break_recv(req
, &br
);
1084 if (!NT_STATUS_IS_OK(status
)) {
1085 printf("oplock break ack failed in oplock_handler\n");
1086 smb_panic("oplock break ack failed in oplock_handler");
1090 static bool send_oplock_ack_smb2(struct smb2_tree
*tree
, struct smb2_handle handle
,
1093 struct smb2_break br
;
1094 struct smb2_request
*req
;
1097 br
.in
.file
.handle
= handle
;
1098 br
.in
.oplock_level
= level
;
1099 br
.in
.reserved
= gen_reserved8();
1100 br
.in
.reserved2
= gen_reserved32();
1102 req
= smb2_break_send(tree
, &br
);
1103 if (req
== NULL
) return false;
1104 req
->async
.fn
= oplock_handler_ack_callback_smb2
;
1105 req
->async
.private_data
= NULL
;
1110 the oplock handler will either ack the break or close the file
1112 static bool oplock_handler_smb2(struct smb2_transport
*transport
, const struct smb2_handle
*handle
,
1113 uint8_t level
, void *private_data
)
1115 struct smb2_close io
;
1118 struct smb2_tree
*tree
= NULL
;
1119 struct smb2_request
*req
;
1121 srandom(current_op
.seed
);
1122 do_close
= gen_chance(50);
1124 i
= ((uintptr_t)private_data
) >> 8;
1125 j
= ((uintptr_t)private_data
) & 0xFF;
1127 if (i
>= NSERVERS
|| j
>= NINSTANCES
) {
1128 printf("Bad private_data in oplock_handler\n");
1132 oplocks
[i
][j
].got_break
= true;
1133 oplocks
[i
][j
].smb2_handle
= *handle
;
1134 oplocks
[i
][j
].handle
= fnum_to_handle_smb2(i
, j
, *handle
);
1135 oplocks
[i
][j
].level
= level
;
1136 oplocks
[i
][j
].do_close
= do_close
;
1137 tree
= talloc_get_type(servers
[i
].smb2_tree
[j
], struct smb2_tree
);
1140 printf("Oplock break not for one of our trees!?\n");
1145 printf("oplock ack handle=%d\n", oplocks
[i
][j
].handle
);
1146 return send_oplock_ack_smb2(tree
, *handle
, level
);
1149 printf("oplock close fnum=%d\n", oplocks
[i
][j
].handle
);
1152 io
.in
.file
.handle
= *handle
;
1154 req
= smb2_close_send(tree
, &io
);
1157 printf("WARNING: close failed in oplock_handler_close\n");
1161 req
->async
.fn
= oplock_handler_close_recv_smb2
;
1162 req
->async
.private_data
= NULL
;
1169 the idle function tries to cope with getting an oplock break on a connection, and
1170 an operation on another connection blocking until that break is acked
1171 we check for operations on all transports in the idle function
1173 static void idle_func_smb2(struct smb2_transport
*transport
, void *private_data
)
1176 for (i
=0;i
<NSERVERS
;i
++) {
1177 for (j
=0;j
<NINSTANCES
;j
++) {
1178 if (servers
[i
].smb2_tree
[j
] &&
1179 transport
!= servers
[i
].smb2_tree
[j
]->session
->transport
) {
1180 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1189 compare NTSTATUS, using checking ignored patterns
1191 static bool compare_status(NTSTATUS status1
, NTSTATUS status2
)
1195 if (NT_STATUS_EQUAL(status1
, status2
)) return true;
1197 /* one code being an error and the other OK is always an error */
1198 if (NT_STATUS_IS_OK(status1
) || NT_STATUS_IS_OK(status2
)) {
1199 current_op
.mismatch
= nt_errstr(status1
);
1203 /* if we are ignoring one of the status codes then consider this a match */
1204 if (ignore_pattern(nt_errstr(status1
)) ||
1205 ignore_pattern(nt_errstr(status2
))) {
1209 /* also support ignore patterns of the form NT_STATUS_XX:NT_STATUS_YY
1210 meaning that the first server returns NT_STATUS_XX and the 2nd
1211 returns NT_STATUS_YY */
1212 s
= talloc_asprintf(current_op
.mem_ctx
, "%s:%s",
1214 nt_errstr(status2
));
1215 if (ignore_pattern(s
)) {
1219 current_op
.mismatch
= nt_errstr(status1
);
1224 check for pending packets on all connections
1226 static void check_pending(void)
1232 for (j
=0;j
<NINSTANCES
;j
++) {
1233 for (i
=0;i
<NSERVERS
;i
++) {
1234 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
1240 check that the same oplock breaks have been received by all instances
1242 static bool check_oplocks(const char *call
)
1247 if (!options
.use_oplocks
|| options
.smb2
) {
1248 /* no smb2 oplocks in gentest yet */
1255 for (j
=0;j
<NINSTANCES
;j
++) {
1256 for (i
=1;i
<NSERVERS
;i
++) {
1257 if (oplocks
[0][j
].got_break
!= oplocks
[i
][j
].got_break
||
1258 oplocks
[0][j
].handle
!= oplocks
[i
][j
].handle
||
1259 oplocks
[0][j
].level
!= oplocks
[i
][j
].level
) {
1260 if (tries
++ < 10) goto again
;
1261 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
1262 oplocks
[0][j
].got_break
,
1263 oplocks
[0][j
].handle
,
1264 oplocks
[0][j
].level
,
1265 oplocks
[i
][j
].got_break
,
1266 oplocks
[i
][j
].handle
,
1267 oplocks
[i
][j
].level
);
1268 current_op
.mismatch
= "oplock break";
1274 /* if we got a break and closed then remove the handle */
1275 for (j
=0;j
<NINSTANCES
;j
++) {
1276 if (oplocks
[0][j
].got_break
&&
1277 oplocks
[0][j
].do_close
) {
1278 uint16_t fnums
[NSERVERS
];
1279 for (i
=0;i
<NSERVERS
;i
++) {
1280 fnums
[i
] = oplocks
[i
][j
].smb_handle
;
1282 gen_remove_handle_smb(j
, fnums
);
1291 check that the same change notify info has been received by all instances
1293 static bool check_notifies(const char *call
)
1299 /* no smb2 notifies in gentest yet */
1306 for (j
=0;j
<NINSTANCES
;j
++) {
1307 for (i
=1;i
<NSERVERS
;i
++) {
1309 union smb_notify not1
, not2
;
1311 if (notifies
[0][j
].notify_count
!= notifies
[i
][j
].notify_count
) {
1312 if (tries
++ < 10) goto again
;
1313 printf("Notify count inconsistent %d %d\n",
1314 notifies
[0][j
].notify_count
,
1315 notifies
[i
][j
].notify_count
);
1316 current_op
.mismatch
= "notify count";
1320 if (notifies
[0][j
].notify_count
== 0) continue;
1322 if (!NT_STATUS_EQUAL(notifies
[0][j
].status
,
1323 notifies
[i
][j
].status
)) {
1324 printf("Notify status mismatch - %s - %s\n",
1325 nt_errstr(notifies
[0][j
].status
),
1326 nt_errstr(notifies
[i
][j
].status
));
1327 current_op
.mismatch
= "Notify status";
1331 if (!NT_STATUS_IS_OK(notifies
[0][j
].status
)) {
1335 not1
= notifies
[0][j
].notify
;
1336 not2
= notifies
[i
][j
].notify
;
1338 for (n
=0;n
<not1
.nttrans
.out
.num_changes
;n
++) {
1339 if (not1
.nttrans
.out
.changes
[n
].action
!=
1340 not2
.nttrans
.out
.changes
[n
].action
) {
1341 printf("Notify action %d inconsistent %d %d\n", n
,
1342 not1
.nttrans
.out
.changes
[n
].action
,
1343 not2
.nttrans
.out
.changes
[n
].action
);
1344 current_op
.mismatch
= "notify action";
1347 if (strcmp(not1
.nttrans
.out
.changes
[n
].name
.s
,
1348 not2
.nttrans
.out
.changes
[n
].name
.s
)) {
1349 printf("Notify name %d inconsistent %s %s\n", n
,
1350 not1
.nttrans
.out
.changes
[n
].name
.s
,
1351 not2
.nttrans
.out
.changes
[n
].name
.s
);
1352 current_op
.mismatch
= "notify name";
1355 if (not1
.nttrans
.out
.changes
[n
].name
.private_length
!=
1356 not2
.nttrans
.out
.changes
[n
].name
.private_length
) {
1357 printf("Notify name length %d inconsistent %d %d\n", n
,
1358 not1
.nttrans
.out
.changes
[n
].name
.private_length
,
1359 not2
.nttrans
.out
.changes
[n
].name
.private_length
);
1360 current_op
.mismatch
= "notify name length";
1367 ZERO_STRUCT(notifies
);
1372 #define GEN_COPY_PARM do { \
1374 for (i=1;i<NSERVERS;i++) { \
1375 parm[i] = parm[0]; \
1379 #define GEN_CALL(call, treetype, treefield) do { \
1381 ZERO_STRUCT(oplocks); \
1382 ZERO_STRUCT(notifies); \
1383 for (i=0;i<NSERVERS;i++) { \
1384 struct treetype *tree = servers[i].treefield[instance]; \
1387 current_op.status = status[0]; \
1388 for (i=1;i<NSERVERS;i++) { \
1389 if (!compare_status(status[0], status[1])) { \
1390 printf("status different in %s - %s %s\n", #call, \
1391 nt_errstr(status[0]), nt_errstr(status[i])); \
1392 current_op.mismatch = nt_errstr(status[0]); \
1396 if (!check_oplocks(#call)) return false; \
1397 if (!check_notifies(#call)) return false; \
1398 if (!NT_STATUS_IS_OK(status[0])) { \
1403 #define GEN_CALL_SMB(call) GEN_CALL(call, smbcli_tree, smb_tree)
1404 #define GEN_CALL_SMB2(call) GEN_CALL(call, smb2_tree, smb2_tree)
1406 #define ADD_HANDLE_SMB2(name, field) do { \
1407 struct smb2_handle handles[NSERVERS]; \
1409 for (i=0;i<NSERVERS;i++) { \
1410 handles[i] = parm[i].field; \
1412 gen_add_handle_smb2(instance, name, handles); \
1415 #define REMOVE_HANDLE_SMB2(field) do { \
1416 struct smb2_handle handles[NSERVERS]; \
1418 for (i=0;i<NSERVERS;i++) { \
1419 handles[i] = parm[i].field; \
1421 gen_remove_handle_smb2(instance, handles); \
1424 #define ADD_HANDLE_SMB(name, field) do { \
1425 uint16_t handles[NSERVERS]; \
1427 for (i=0;i<NSERVERS;i++) { \
1428 handles[i] = parm[i].field; \
1430 gen_add_handle_smb(instance, name, handles); \
1433 #define REMOVE_HANDLE_SMB(field) do { \
1434 uint16_t handles[NSERVERS]; \
1436 for (i=0;i<NSERVERS;i++) { \
1437 handles[i] = parm[i].field; \
1439 gen_remove_handle_smb(instance, handles); \
1442 #define GEN_SET_FNUM_SMB2(field) do { \
1444 for (i=0;i<NSERVERS;i++) { \
1445 parm[i].field = gen_lookup_handle_smb2(i, parm[i].field.data[0]); \
1449 #define GEN_SET_FNUM_SMB(field) do { \
1451 for (i=0;i<NSERVERS;i++) { \
1452 parm[i].field = gen_lookup_handle_smb(i, parm[i].field); \
1456 #define CHECK_EQUAL(field) do { \
1457 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
1458 current_op.mismatch = #field; \
1459 printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \
1460 (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \
1465 #define CHECK_SECDESC(field) do { \
1466 if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \
1467 current_op.mismatch = #field; \
1468 printf("Mismatch in %s\n", #field); \
1473 #define CHECK_ATTRIB(field) do { \
1474 if (!options.mask_indexing) { \
1475 CHECK_EQUAL(field); \
1476 } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \
1477 current_op.mismatch = #field; \
1478 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1479 (int)parm[0].field, (int)parm[1].field); \
1484 #define CHECK_WSTR_EQUAL(field) do { \
1485 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
1486 current_op.mismatch = #field; \
1487 printf("%s is NULL!\n", #field); \
1490 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1491 current_op.mismatch = #field; \
1492 printf("Mismatch in %s - %s %s\n", #field, \
1493 parm[0].field.s, parm[1].field.s); \
1496 CHECK_EQUAL(field.private_length); \
1499 #define CHECK_BLOB_EQUAL(field) do { \
1500 if (((parm[0].field.data == NULL && parm[1].field.data != NULL) || \
1501 (parm[1].field.data == NULL && parm[0].field.data != NULL) || \
1502 (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0)) && !ignore_pattern(#field)) { \
1503 current_op.mismatch = #field; \
1504 printf("Mismatch in %s\n", #field); \
1507 CHECK_EQUAL(field.length); \
1510 #define CHECK_TIMES_EQUAL(field) do { \
1511 if (labs(parm[0].field - parm[1].field) > time_skew() && \
1512 !ignore_pattern(#field)) { \
1513 current_op.mismatch = #field; \
1514 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1515 (int)parm[0].field, (int)parm[1].field); \
1520 #define CHECK_NTTIMES_EQUAL(field) do { \
1521 if (labs(nt_time_to_unix(parm[0].field) - \
1522 nt_time_to_unix(parm[1].field)) > time_skew() && \
1523 !ignore_pattern(#field)) { \
1524 current_op.mismatch = #field; \
1525 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1526 (int)nt_time_to_unix(parm[0].field), \
1527 (int)nt_time_to_unix(parm[1].field)); \
1534 compare returned fileinfo structures
1536 static bool cmp_fileinfo(int instance
,
1537 union smb_fileinfo parm
[NSERVERS
],
1538 NTSTATUS status
[NSERVERS
])
1541 enum smb_fileinfo_level level
= parm
[0].generic
.level
;
1543 if (level
== RAW_FILEINFO_ALL_INFORMATION
&&
1545 level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
1549 case RAW_FILEINFO_GENERIC
:
1552 case RAW_FILEINFO_GETATTR
:
1553 CHECK_ATTRIB(getattr
.out
.attrib
);
1554 CHECK_EQUAL(getattr
.out
.size
);
1555 CHECK_TIMES_EQUAL(getattr
.out
.write_time
);
1558 case RAW_FILEINFO_GETATTRE
:
1559 CHECK_TIMES_EQUAL(getattre
.out
.create_time
);
1560 CHECK_TIMES_EQUAL(getattre
.out
.access_time
);
1561 CHECK_TIMES_EQUAL(getattre
.out
.write_time
);
1562 CHECK_EQUAL(getattre
.out
.size
);
1563 CHECK_EQUAL(getattre
.out
.alloc_size
);
1564 CHECK_ATTRIB(getattre
.out
.attrib
);
1567 case RAW_FILEINFO_STANDARD
:
1568 CHECK_TIMES_EQUAL(standard
.out
.create_time
);
1569 CHECK_TIMES_EQUAL(standard
.out
.access_time
);
1570 CHECK_TIMES_EQUAL(standard
.out
.write_time
);
1571 CHECK_EQUAL(standard
.out
.size
);
1572 CHECK_EQUAL(standard
.out
.alloc_size
);
1573 CHECK_ATTRIB(standard
.out
.attrib
);
1576 case RAW_FILEINFO_EA_SIZE
:
1577 CHECK_TIMES_EQUAL(ea_size
.out
.create_time
);
1578 CHECK_TIMES_EQUAL(ea_size
.out
.access_time
);
1579 CHECK_TIMES_EQUAL(ea_size
.out
.write_time
);
1580 CHECK_EQUAL(ea_size
.out
.size
);
1581 CHECK_EQUAL(ea_size
.out
.alloc_size
);
1582 CHECK_ATTRIB(ea_size
.out
.attrib
);
1583 CHECK_EQUAL(ea_size
.out
.ea_size
);
1586 case RAW_FILEINFO_ALL_EAS
:
1587 CHECK_EQUAL(all_eas
.out
.num_eas
);
1588 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1589 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1590 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1591 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1595 case RAW_FILEINFO_IS_NAME_VALID
:
1598 case RAW_FILEINFO_BASIC_INFO
:
1599 case RAW_FILEINFO_BASIC_INFORMATION
:
1600 CHECK_NTTIMES_EQUAL(basic_info
.out
.create_time
);
1601 CHECK_NTTIMES_EQUAL(basic_info
.out
.access_time
);
1602 CHECK_NTTIMES_EQUAL(basic_info
.out
.write_time
);
1603 CHECK_NTTIMES_EQUAL(basic_info
.out
.change_time
);
1604 CHECK_ATTRIB(basic_info
.out
.attrib
);
1607 case RAW_FILEINFO_STANDARD_INFO
:
1608 case RAW_FILEINFO_STANDARD_INFORMATION
:
1609 CHECK_EQUAL(standard_info
.out
.alloc_size
);
1610 CHECK_EQUAL(standard_info
.out
.size
);
1611 CHECK_EQUAL(standard_info
.out
.nlink
);
1612 CHECK_EQUAL(standard_info
.out
.delete_pending
);
1613 CHECK_EQUAL(standard_info
.out
.directory
);
1616 case RAW_FILEINFO_EA_INFO
:
1617 case RAW_FILEINFO_EA_INFORMATION
:
1618 CHECK_EQUAL(ea_info
.out
.ea_size
);
1621 case RAW_FILEINFO_NAME_INFO
:
1622 case RAW_FILEINFO_NAME_INFORMATION
:
1623 CHECK_WSTR_EQUAL(name_info
.out
.fname
);
1626 case RAW_FILEINFO_ALL_INFO
:
1627 case RAW_FILEINFO_ALL_INFORMATION
:
1628 CHECK_NTTIMES_EQUAL(all_info
.out
.create_time
);
1629 CHECK_NTTIMES_EQUAL(all_info
.out
.access_time
);
1630 CHECK_NTTIMES_EQUAL(all_info
.out
.write_time
);
1631 CHECK_NTTIMES_EQUAL(all_info
.out
.change_time
);
1632 CHECK_ATTRIB(all_info
.out
.attrib
);
1633 CHECK_EQUAL(all_info
.out
.alloc_size
);
1634 CHECK_EQUAL(all_info
.out
.size
);
1635 CHECK_EQUAL(all_info
.out
.nlink
);
1636 CHECK_EQUAL(all_info
.out
.delete_pending
);
1637 CHECK_EQUAL(all_info
.out
.directory
);
1638 CHECK_EQUAL(all_info
.out
.ea_size
);
1639 CHECK_WSTR_EQUAL(all_info
.out
.fname
);
1642 case RAW_FILEINFO_ALT_NAME_INFO
:
1643 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
1644 case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION
:
1645 CHECK_WSTR_EQUAL(alt_name_info
.out
.fname
);
1648 case RAW_FILEINFO_STREAM_INFO
:
1649 case RAW_FILEINFO_STREAM_INFORMATION
:
1650 CHECK_EQUAL(stream_info
.out
.num_streams
);
1651 for (i
=0;i
<parm
[0].stream_info
.out
.num_streams
;i
++) {
1652 CHECK_EQUAL(stream_info
.out
.streams
[i
].size
);
1653 CHECK_EQUAL(stream_info
.out
.streams
[i
].alloc_size
);
1654 CHECK_WSTR_EQUAL(stream_info
.out
.streams
[i
].stream_name
);
1658 case RAW_FILEINFO_COMPRESSION_INFO
:
1659 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
1660 CHECK_EQUAL(compression_info
.out
.compressed_size
);
1661 CHECK_EQUAL(compression_info
.out
.format
);
1662 CHECK_EQUAL(compression_info
.out
.unit_shift
);
1663 CHECK_EQUAL(compression_info
.out
.chunk_shift
);
1664 CHECK_EQUAL(compression_info
.out
.cluster_shift
);
1667 case RAW_FILEINFO_INTERNAL_INFORMATION
:
1668 CHECK_EQUAL(internal_information
.out
.file_id
);
1671 case RAW_FILEINFO_ACCESS_INFORMATION
:
1672 CHECK_EQUAL(access_information
.out
.access_flags
);
1675 case RAW_FILEINFO_POSITION_INFORMATION
:
1676 CHECK_EQUAL(position_information
.out
.position
);
1679 case RAW_FILEINFO_MODE_INFORMATION
:
1680 CHECK_EQUAL(mode_information
.out
.mode
);
1683 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
1684 CHECK_EQUAL(alignment_information
.out
.alignment_requirement
);
1687 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
1688 CHECK_NTTIMES_EQUAL(network_open_information
.out
.create_time
);
1689 CHECK_NTTIMES_EQUAL(network_open_information
.out
.access_time
);
1690 CHECK_NTTIMES_EQUAL(network_open_information
.out
.write_time
);
1691 CHECK_NTTIMES_EQUAL(network_open_information
.out
.change_time
);
1692 CHECK_EQUAL(network_open_information
.out
.alloc_size
);
1693 CHECK_EQUAL(network_open_information
.out
.size
);
1694 CHECK_ATTRIB(network_open_information
.out
.attrib
);
1697 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
1698 CHECK_ATTRIB(attribute_tag_information
.out
.attrib
);
1699 CHECK_EQUAL(attribute_tag_information
.out
.reparse_tag
);
1702 case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION
:
1703 CHECK_WSTR_EQUAL(normalized_name_info
.out
.fname
);
1706 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
1707 CHECK_NTTIMES_EQUAL(all_info2
.out
.create_time
);
1708 CHECK_NTTIMES_EQUAL(all_info2
.out
.access_time
);
1709 CHECK_NTTIMES_EQUAL(all_info2
.out
.write_time
);
1710 CHECK_NTTIMES_EQUAL(all_info2
.out
.change_time
);
1711 CHECK_ATTRIB(all_info2
.out
.attrib
);
1712 CHECK_EQUAL(all_info2
.out
.unknown1
);
1713 CHECK_EQUAL(all_info2
.out
.alloc_size
);
1714 CHECK_EQUAL(all_info2
.out
.size
);
1715 CHECK_EQUAL(all_info2
.out
.nlink
);
1716 CHECK_EQUAL(all_info2
.out
.delete_pending
);
1717 CHECK_EQUAL(all_info2
.out
.directory
);
1718 CHECK_EQUAL(all_info2
.out
.file_id
);
1719 CHECK_EQUAL(all_info2
.out
.ea_size
);
1720 CHECK_EQUAL(all_info2
.out
.access_mask
);
1721 CHECK_EQUAL(all_info2
.out
.position
);
1722 CHECK_EQUAL(all_info2
.out
.mode
);
1723 CHECK_EQUAL(all_info2
.out
.alignment_requirement
);
1724 CHECK_WSTR_EQUAL(all_info2
.out
.fname
);
1727 case RAW_FILEINFO_SMB2_ALL_EAS
:
1728 CHECK_EQUAL(all_eas
.out
.num_eas
);
1729 for (i
=0;i
<parm
[0].all_eas
.out
.num_eas
;i
++) {
1730 CHECK_EQUAL(all_eas
.out
.eas
[i
].flags
);
1731 CHECK_WSTR_EQUAL(all_eas
.out
.eas
[i
].name
);
1732 CHECK_BLOB_EQUAL(all_eas
.out
.eas
[i
].value
);
1736 case RAW_FILEINFO_SEC_DESC
:
1737 CHECK_SECDESC(query_secdesc
.out
.sd
);
1740 /* Unhandled levels */
1741 case RAW_FILEINFO_EA_LIST
:
1742 case RAW_FILEINFO_UNIX_BASIC
:
1743 case RAW_FILEINFO_UNIX_LINK
:
1744 case RAW_FILEINFO_UNIX_INFO2
:
1754 generate openx operations
1756 static bool handler_smb_openx(int instance
)
1758 union smb_open parm
[NSERVERS
] = {0};
1759 NTSTATUS status
[NSERVERS
];
1761 parm
[0].openx
.level
= RAW_OPEN_OPENX
;
1762 parm
[0].openx
.in
.flags
= gen_openx_flags();
1763 parm
[0].openx
.in
.open_mode
= gen_openx_mode();
1764 parm
[0].openx
.in
.search_attrs
= gen_attrib();
1765 parm
[0].openx
.in
.file_attrs
= gen_attrib();
1766 parm
[0].openx
.in
.write_time
= gen_timet();
1767 parm
[0].openx
.in
.open_func
= gen_openx_func();
1768 parm
[0].openx
.in
.size
= gen_io_count();
1769 parm
[0].openx
.in
.timeout
= gen_timeout();
1770 parm
[0].openx
.in
.fname
= gen_fname_open(instance
);
1772 if (!options
.use_oplocks
) {
1773 /* mask out oplocks */
1774 parm
[0].openx
.in
.flags
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1775 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1779 GEN_CALL_SMB(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1781 CHECK_ATTRIB(openx
.out
.attrib
);
1782 CHECK_EQUAL(openx
.out
.size
);
1783 CHECK_EQUAL(openx
.out
.access
);
1784 CHECK_EQUAL(openx
.out
.ftype
);
1785 CHECK_EQUAL(openx
.out
.devstate
);
1786 CHECK_EQUAL(openx
.out
.action
);
1787 CHECK_EQUAL(openx
.out
.access_mask
);
1788 CHECK_EQUAL(openx
.out
.unknown
);
1789 CHECK_TIMES_EQUAL(openx
.out
.write_time
);
1791 /* open creates a new file handle */
1792 ADD_HANDLE_SMB(parm
[0].openx
.in
.fname
, openx
.out
.file
.fnum
);
1799 generate open operations
1801 static bool handler_smb_open(int instance
)
1803 union smb_open parm
[NSERVERS
] = {0};
1804 NTSTATUS status
[NSERVERS
];
1806 parm
[0].openold
.level
= RAW_OPEN_OPEN
;
1807 parm
[0].openold
.in
.open_mode
= gen_bits_mask2(0xF, 0xFFFF);
1808 parm
[0].openold
.in
.search_attrs
= gen_attrib();
1809 parm
[0].openold
.in
.fname
= gen_fname_open(instance
);
1811 if (!options
.use_oplocks
) {
1812 /* mask out oplocks */
1813 parm
[0].openold
.in
.open_mode
&= ~(OPENX_FLAGS_REQUEST_OPLOCK
|
1814 OPENX_FLAGS_REQUEST_BATCH_OPLOCK
);
1818 GEN_CALL_SMB(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1820 CHECK_ATTRIB(openold
.out
.attrib
);
1821 CHECK_TIMES_EQUAL(openold
.out
.write_time
);
1822 CHECK_EQUAL(openold
.out
.size
);
1823 CHECK_EQUAL(openold
.out
.rmode
);
1825 /* open creates a new file handle */
1826 ADD_HANDLE_SMB(parm
[0].openold
.in
.fname
, openold
.out
.file
.fnum
);
1833 generate ntcreatex operations
1835 static bool handler_smb_ntcreatex(int instance
)
1837 union smb_open parm
[NSERVERS
] = {0};
1838 NTSTATUS status
[NSERVERS
];
1840 parm
[0].ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
1841 parm
[0].ntcreatex
.in
.flags
= gen_ntcreatex_flags();
1842 parm
[0].ntcreatex
.in
.root_fid
.fnum
= gen_root_fid(instance
);
1843 parm
[0].ntcreatex
.in
.access_mask
= gen_access_mask();
1844 parm
[0].ntcreatex
.in
.alloc_size
= gen_alloc_size();
1845 parm
[0].ntcreatex
.in
.file_attr
= gen_attrib();
1846 parm
[0].ntcreatex
.in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
1847 parm
[0].ntcreatex
.in
.open_disposition
= gen_open_disp();
1848 parm
[0].ntcreatex
.in
.create_options
= gen_create_options();
1849 parm
[0].ntcreatex
.in
.impersonation
= gen_bits_mask2(0, 0xFFFFFFFF);
1850 parm
[0].ntcreatex
.in
.security_flags
= gen_bits_mask2(0, 0xFF);
1851 parm
[0].ntcreatex
.in
.fname
= gen_fname_open(instance
);
1853 if (!options
.use_oplocks
) {
1854 /* mask out oplocks */
1855 parm
[0].ntcreatex
.in
.flags
&= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK
|
1856 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
);
1860 if (parm
[0].ntcreatex
.in
.root_fid
.fnum
!= 0) {
1861 GEN_SET_FNUM_SMB(ntcreatex
.in
.root_fid
.fnum
);
1863 GEN_CALL_SMB(smb_raw_open(tree
, current_op
.mem_ctx
, &parm
[i
]));
1865 CHECK_EQUAL(ntcreatex
.out
.oplock_level
);
1866 CHECK_EQUAL(ntcreatex
.out
.create_action
);
1867 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.create_time
);
1868 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.access_time
);
1869 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.write_time
);
1870 CHECK_NTTIMES_EQUAL(ntcreatex
.out
.change_time
);
1871 CHECK_ATTRIB(ntcreatex
.out
.attrib
);
1872 CHECK_EQUAL(ntcreatex
.out
.alloc_size
);
1873 CHECK_EQUAL(ntcreatex
.out
.size
);
1874 CHECK_EQUAL(ntcreatex
.out
.file_type
);
1875 CHECK_EQUAL(ntcreatex
.out
.ipc_state
);
1876 CHECK_EQUAL(ntcreatex
.out
.is_directory
);
1878 /* ntcreatex creates a new file handle */
1879 ADD_HANDLE_SMB(parm
[0].ntcreatex
.in
.fname
, ntcreatex
.out
.file
.fnum
);
1885 generate close operations
1887 static bool handler_smb_close(int instance
)
1889 union smb_close parm
[NSERVERS
] = {0};
1890 NTSTATUS status
[NSERVERS
];
1892 parm
[0].close
.level
= RAW_CLOSE_CLOSE
;
1893 parm
[0].close
.in
.file
.fnum
= gen_fnum_close(instance
);
1894 parm
[0].close
.in
.write_time
= gen_timet();
1897 GEN_SET_FNUM_SMB(close
.in
.file
.fnum
);
1898 GEN_CALL_SMB(smb_raw_close(tree
, &parm
[i
]));
1900 REMOVE_HANDLE_SMB(close
.in
.file
.fnum
);
1906 generate unlink operations
1908 static bool handler_smb_unlink(int instance
)
1910 union smb_unlink parm
[NSERVERS
] = {0};
1911 NTSTATUS status
[NSERVERS
];
1913 parm
[0].unlink
.in
.pattern
= gen_pattern();
1914 parm
[0].unlink
.in
.attrib
= gen_attrib();
1917 GEN_CALL_SMB(smb_raw_unlink(tree
, &parm
[i
]));
1923 generate chkpath operations
1925 static bool handler_smb_chkpath(int instance
)
1927 union smb_chkpath parm
[NSERVERS
] = {0};
1928 NTSTATUS status
[NSERVERS
];
1930 parm
[0].chkpath
.in
.path
= gen_fname_open(instance
);
1933 GEN_CALL_SMB(smb_raw_chkpath(tree
, &parm
[i
]));
1939 generate mkdir operations
1941 static bool handler_smb_mkdir(int instance
)
1943 union smb_mkdir parm
[NSERVERS
] = {0};
1944 NTSTATUS status
[NSERVERS
];
1946 parm
[0].mkdir
.level
= RAW_MKDIR_MKDIR
;
1947 parm
[0].mkdir
.in
.path
= gen_fname_open(instance
);
1950 GEN_CALL_SMB(smb_raw_mkdir(tree
, &parm
[i
]));
1956 generate rmdir operations
1958 static bool handler_smb_rmdir(int instance
)
1960 struct smb_rmdir parm
[NSERVERS
] = {0};
1961 NTSTATUS status
[NSERVERS
];
1963 parm
[0].in
.path
= gen_fname_open(instance
);
1966 GEN_CALL_SMB(smb_raw_rmdir(tree
, &parm
[i
]));
1972 generate rename operations
1974 static bool handler_smb_rename(int instance
)
1976 union smb_rename parm
[NSERVERS
] = {0};
1977 NTSTATUS status
[NSERVERS
];
1979 parm
[0].generic
.level
= RAW_RENAME_RENAME
;
1980 parm
[0].rename
.in
.pattern1
= gen_pattern();
1981 parm
[0].rename
.in
.pattern2
= gen_pattern();
1982 parm
[0].rename
.in
.attrib
= gen_attrib();
1985 GEN_CALL_SMB(smb_raw_rename(tree
, &parm
[i
]));
1991 generate ntrename operations
1993 static bool handler_smb_ntrename(int instance
)
1995 union smb_rename parm
[NSERVERS
] = {0};
1996 NTSTATUS status
[NSERVERS
];
1998 parm
[0].generic
.level
= RAW_RENAME_NTRENAME
;
1999 parm
[0].ntrename
.in
.old_name
= gen_fname();
2000 parm
[0].ntrename
.in
.new_name
= gen_fname();
2001 parm
[0].ntrename
.in
.attrib
= gen_attrib();
2002 parm
[0].ntrename
.in
.cluster_size
= gen_bits_mask2(0, 0xFFFFFFF);
2003 parm
[0].ntrename
.in
.flags
= gen_rename_flags();
2006 GEN_CALL_SMB(smb_raw_rename(tree
, &parm
[i
]));
2013 generate seek operations
2015 static bool handler_smb_seek(int instance
)
2017 union smb_seek parm
[NSERVERS
] = {0};
2018 NTSTATUS status
[NSERVERS
];
2020 parm
[0].lseek
.in
.file
.fnum
= gen_fnum(instance
);
2021 parm
[0].lseek
.in
.mode
= gen_bits_mask2(0x3, 0xFFFF);
2022 parm
[0].lseek
.in
.offset
= gen_offset();
2025 GEN_SET_FNUM_SMB(lseek
.in
.file
.fnum
);
2026 GEN_CALL_SMB(smb_raw_seek(tree
, &parm
[i
]));
2028 CHECK_EQUAL(lseek
.out
.offset
);
2035 generate readx operations
2037 static bool handler_smb_readx(int instance
)
2039 union smb_read parm
[NSERVERS
] = {0};
2040 NTSTATUS status
[NSERVERS
];
2042 parm
[0].readx
.level
= RAW_READ_READX
;
2043 parm
[0].readx
.in
.file
.fnum
= gen_fnum(instance
);
2044 parm
[0].readx
.in
.offset
= gen_offset();
2045 parm
[0].readx
.in
.mincnt
= gen_io_count();
2046 parm
[0].readx
.in
.maxcnt
= gen_io_count();
2047 parm
[0].readx
.in
.remaining
= gen_io_count();
2048 parm
[0].readx
.in
.read_for_execute
= gen_bool();
2049 parm
[0].readx
.out
.data
= talloc_array(current_op
.mem_ctx
, uint8_t,
2050 MAX(parm
[0].readx
.in
.mincnt
, parm
[0].readx
.in
.maxcnt
));
2053 GEN_SET_FNUM_SMB(readx
.in
.file
.fnum
);
2054 GEN_CALL_SMB(smb_raw_read(tree
, &parm
[i
]));
2056 CHECK_EQUAL(readx
.out
.remaining
);
2057 CHECK_EQUAL(readx
.out
.compaction_mode
);
2058 CHECK_EQUAL(readx
.out
.nread
);
2064 generate writex operations
2066 static bool handler_smb_writex(int instance
)
2068 union smb_write parm
[NSERVERS
] = {0};
2069 NTSTATUS status
[NSERVERS
];
2071 parm
[0].writex
.level
= RAW_WRITE_WRITEX
;
2072 parm
[0].writex
.in
.file
.fnum
= gen_fnum(instance
);
2073 parm
[0].writex
.in
.offset
= gen_offset();
2074 parm
[0].writex
.in
.wmode
= gen_bits_mask(0xFFFF);
2075 parm
[0].writex
.in
.remaining
= gen_io_count();
2076 parm
[0].writex
.in
.count
= gen_io_count();
2077 parm
[0].writex
.in
.data
= talloc_zero_array(current_op
.mem_ctx
, uint8_t, parm
[0].writex
.in
.count
);
2080 GEN_SET_FNUM_SMB(writex
.in
.file
.fnum
);
2081 GEN_CALL_SMB(smb_raw_write(tree
, &parm
[i
]));
2083 CHECK_EQUAL(writex
.out
.nwritten
);
2084 CHECK_EQUAL(writex
.out
.remaining
);
2090 generate lockingx operations
2092 static bool handler_smb_lockingx(int instance
)
2094 union smb_lock parm
[NSERVERS
] = {0};
2095 NTSTATUS status
[NSERVERS
];
2098 parm
[0].lockx
.level
= RAW_LOCK_LOCKX
;
2099 parm
[0].lockx
.in
.file
.fnum
= gen_fnum(instance
);
2100 parm
[0].lockx
.in
.mode
= gen_lock_mode();
2101 parm
[0].lockx
.in
.timeout
= gen_timeout();
2103 /* make sure we don't accidentally generate an oplock
2104 break ack - otherwise the server can just block forever */
2105 parm
[0].lockx
.in
.ulock_cnt
= gen_lock_count();
2106 parm
[0].lockx
.in
.lock_cnt
= gen_lock_count();
2107 nlocks
= parm
[0].lockx
.in
.ulock_cnt
+ parm
[0].lockx
.in
.lock_cnt
;
2108 } while (nlocks
== 0);
2111 parm
[0].lockx
.in
.locks
= talloc_array(current_op
.mem_ctx
,
2112 struct smb_lock_entry
,
2114 for (n
=0;n
<nlocks
;n
++) {
2115 parm
[0].lockx
.in
.locks
[n
].pid
= gen_pid();
2116 parm
[0].lockx
.in
.locks
[n
].offset
= gen_offset();
2117 parm
[0].lockx
.in
.locks
[n
].count
= gen_io_count();
2122 GEN_SET_FNUM_SMB(lockx
.in
.file
.fnum
);
2123 GEN_CALL_SMB(smb_raw_lock(tree
, &parm
[i
]));
2130 generate a fileinfo query structure
2132 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
2136 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2138 enum smb_setfileinfo_level level
;
2142 /* disabled until win2003 can handle them ... */
2143 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
2144 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
2146 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
2147 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
2148 LVL(POSITION_INFORMATION
), LVL(MODE_INFORMATION
),
2149 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
2150 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
2153 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
2154 } while (ignore_pattern(levels
[i
].name
));
2156 info
->generic
.level
= levels
[i
].level
;
2158 switch (info
->generic
.level
) {
2159 case RAW_SFILEINFO_SETATTR
:
2160 info
->setattr
.in
.attrib
= gen_attrib();
2161 info
->setattr
.in
.write_time
= gen_timet();
2163 case RAW_SFILEINFO_SETATTRE
:
2164 info
->setattre
.in
.create_time
= gen_timet();
2165 info
->setattre
.in
.access_time
= gen_timet();
2166 info
->setattre
.in
.write_time
= gen_timet();
2168 case RAW_SFILEINFO_STANDARD
:
2169 info
->standard
.in
.create_time
= gen_timet();
2170 info
->standard
.in
.access_time
= gen_timet();
2171 info
->standard
.in
.write_time
= gen_timet();
2173 case RAW_SFILEINFO_EA_SET
: {
2174 static struct ea_struct ea
;
2175 info
->ea_set
.in
.num_eas
= 1;
2176 info
->ea_set
.in
.eas
= &ea
;
2177 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
2180 case RAW_SFILEINFO_BASIC_INFO
:
2181 case RAW_SFILEINFO_BASIC_INFORMATION
:
2182 info
->basic_info
.in
.create_time
= gen_nttime();
2183 info
->basic_info
.in
.access_time
= gen_nttime();
2184 info
->basic_info
.in
.write_time
= gen_nttime();
2185 info
->basic_info
.in
.change_time
= gen_nttime();
2186 info
->basic_info
.in
.attrib
= gen_attrib();
2188 case RAW_SFILEINFO_DISPOSITION_INFO
:
2189 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
2190 info
->disposition_info
.in
.delete_on_close
= gen_bool();
2192 case RAW_SFILEINFO_ALLOCATION_INFO
:
2193 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
2194 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
2196 case RAW_SFILEINFO_END_OF_FILE_INFO
:
2197 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
2198 info
->end_of_file_info
.in
.size
= gen_offset();
2200 case RAW_SFILEINFO_RENAME_INFORMATION
:
2201 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2
:
2202 info
->rename_information
.in
.overwrite
= gen_bool();
2203 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
2204 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
2206 case RAW_SFILEINFO_POSITION_INFORMATION
:
2207 info
->position_information
.in
.position
= gen_offset();
2209 case RAW_SFILEINFO_MODE_INFORMATION
:
2210 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
2212 case RAW_SFILEINFO_FULL_EA_INFORMATION
:
2213 info
->full_ea_information
.in
.eas
= gen_ea_list();
2215 case RAW_SFILEINFO_GENERIC
:
2216 case RAW_SFILEINFO_SEC_DESC
:
2217 case RAW_SFILEINFO_UNIX_BASIC
:
2218 case RAW_SFILEINFO_UNIX_LINK
:
2219 case RAW_SFILEINFO_UNIX_HLINK
:
2220 case RAW_SFILEINFO_1023
:
2221 case RAW_SFILEINFO_1025
:
2222 case RAW_SFILEINFO_1029
:
2223 case RAW_SFILEINFO_1032
:
2224 case RAW_SFILEINFO_1039
:
2225 case RAW_SFILEINFO_1040
:
2226 case RAW_SFILEINFO_UNIX_INFO2
:
2234 generate a fileinfo query structure
2236 static void gen_setfileinfo(int instance
, union smb_setfileinfo
*info
)
2240 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
2242 enum smb_setfileinfo_level level
;
2245 struct levels smb_levels
[] = {
2246 LVL(EA_SET
), LVL(BASIC_INFO
), LVL(DISPOSITION_INFO
),
2247 LVL(STANDARD
), LVL(ALLOCATION_INFO
), LVL(END_OF_FILE_INFO
),
2248 LVL(SETATTR
), LVL(SETATTRE
), LVL(BASIC_INFORMATION
),
2249 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
2250 LVL(POSITION_INFORMATION
), LVL(FULL_EA_INFORMATION
), LVL(MODE_INFORMATION
),
2251 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
2252 LVL(PIPE_INFORMATION
), LVL(VALID_DATA_INFORMATION
), LVL(SHORT_NAME_INFORMATION
),
2253 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2254 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2256 struct levels smb2_levels
[] = {
2257 LVL(BASIC_INFORMATION
),
2258 LVL(RENAME_INFORMATION
), LVL(DISPOSITION_INFORMATION
),
2259 LVL(POSITION_INFORMATION
), LVL(FULL_EA_INFORMATION
), LVL(MODE_INFORMATION
),
2260 LVL(ALLOCATION_INFORMATION
), LVL(END_OF_FILE_INFORMATION
),
2261 LVL(PIPE_INFORMATION
), LVL(VALID_DATA_INFORMATION
), LVL(SHORT_NAME_INFORMATION
),
2262 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
2263 LVL(1041), LVL(1042), LVL(1043), LVL(1044),
2265 struct levels
*levels
= options
.smb2
?smb2_levels
:smb_levels
;
2266 uint32_t num_levels
= options
.smb2
?ARRAY_SIZE(smb2_levels
):ARRAY_SIZE(smb_levels
);
2269 i
= gen_int_range(0, num_levels
-1);
2270 } while (ignore_pattern(levels
[i
].name
));
2273 info
->generic
.level
= levels
[i
].level
;
2275 switch (info
->generic
.level
) {
2276 case RAW_SFILEINFO_SETATTR
:
2277 info
->setattr
.in
.attrib
= gen_attrib();
2278 info
->setattr
.in
.write_time
= gen_timet();
2280 case RAW_SFILEINFO_SETATTRE
:
2281 info
->setattre
.in
.create_time
= gen_timet();
2282 info
->setattre
.in
.access_time
= gen_timet();
2283 info
->setattre
.in
.write_time
= gen_timet();
2285 case RAW_SFILEINFO_STANDARD
:
2286 info
->standard
.in
.create_time
= gen_timet();
2287 info
->standard
.in
.access_time
= gen_timet();
2288 info
->standard
.in
.write_time
= gen_timet();
2290 case RAW_SFILEINFO_EA_SET
: {
2291 static struct ea_struct ea
;
2292 info
->ea_set
.in
.num_eas
= 1;
2293 info
->ea_set
.in
.eas
= &ea
;
2294 info
->ea_set
.in
.eas
[0] = gen_ea_struct();
2297 case RAW_SFILEINFO_BASIC_INFO
:
2298 case RAW_SFILEINFO_BASIC_INFORMATION
:
2299 info
->basic_info
.in
.create_time
= gen_nttime();
2300 info
->basic_info
.in
.access_time
= gen_nttime();
2301 info
->basic_info
.in
.write_time
= gen_nttime();
2302 info
->basic_info
.in
.change_time
= gen_nttime();
2303 info
->basic_info
.in
.attrib
= gen_attrib();
2305 case RAW_SFILEINFO_DISPOSITION_INFO
:
2306 case RAW_SFILEINFO_DISPOSITION_INFORMATION
:
2307 info
->disposition_info
.in
.delete_on_close
= gen_bool();
2309 case RAW_SFILEINFO_ALLOCATION_INFO
:
2310 case RAW_SFILEINFO_ALLOCATION_INFORMATION
:
2311 info
->allocation_info
.in
.alloc_size
= gen_alloc_size();
2313 case RAW_SFILEINFO_END_OF_FILE_INFO
:
2314 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
2315 info
->end_of_file_info
.in
.size
= gen_offset();
2317 case RAW_SFILEINFO_RENAME_INFORMATION
:
2318 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2
:
2319 info
->rename_information
.in
.overwrite
= gen_bool();
2320 info
->rename_information
.in
.root_fid
= gen_root_fid(instance
);
2321 info
->rename_information
.in
.new_name
= gen_fname_open(instance
);
2323 case RAW_SFILEINFO_POSITION_INFORMATION
:
2324 info
->position_information
.in
.position
= gen_offset();
2326 case RAW_SFILEINFO_MODE_INFORMATION
:
2327 info
->mode_information
.in
.mode
= gen_bits_mask(0xFFFFFFFF);
2329 case RAW_SFILEINFO_FULL_EA_INFORMATION
:
2330 info
->full_ea_information
.in
.eas
= gen_ea_list();
2333 case RAW_SFILEINFO_GENERIC
:
2334 case RAW_SFILEINFO_SEC_DESC
:
2335 case RAW_SFILEINFO_1025
:
2336 case RAW_SFILEINFO_1029
:
2337 case RAW_SFILEINFO_1032
:
2338 case RAW_SFILEINFO_UNIX_BASIC
:
2339 case RAW_SFILEINFO_UNIX_INFO2
:
2340 case RAW_SFILEINFO_UNIX_LINK
:
2341 case RAW_SFILEINFO_UNIX_HLINK
:
2342 case RAW_SFILEINFO_LINK_INFORMATION
:
2343 case RAW_SFILEINFO_PIPE_INFORMATION
:
2344 case RAW_SFILEINFO_VALID_DATA_INFORMATION
:
2345 case RAW_SFILEINFO_SHORT_NAME_INFORMATION
:
2346 case RAW_SFILEINFO_1027
:
2347 case RAW_SFILEINFO_1030
:
2348 case RAW_SFILEINFO_1031
:
2349 case RAW_SFILEINFO_1036
:
2350 case RAW_SFILEINFO_1041
:
2351 case RAW_SFILEINFO_1042
:
2352 case RAW_SFILEINFO_1043
:
2353 case RAW_SFILEINFO_1044
:
2362 generate a fileinfo query structure
2364 static void gen_fileinfo_smb(int instance
, union smb_fileinfo
*info
)
2368 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2370 enum smb_fileinfo_level level
;
2373 LVL(GETATTR
), LVL(GETATTRE
), LVL(STANDARD
),
2374 LVL(EA_SIZE
), LVL(ALL_EAS
), LVL(IS_NAME_VALID
),
2375 LVL(BASIC_INFO
), LVL(STANDARD_INFO
), LVL(EA_INFO
),
2376 LVL(NAME_INFO
), LVL(ALL_INFO
), LVL(ALT_NAME_INFO
),
2377 LVL(STREAM_INFO
), LVL(COMPRESSION_INFO
), LVL(BASIC_INFORMATION
),
2378 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
2379 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
2380 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(ALL_INFORMATION
),
2381 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
2382 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
)
2385 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
2386 } while (ignore_pattern(levels
[i
].name
));
2388 info
->generic
.level
= levels
[i
].level
;
2392 generate qpathinfo operations
2394 static bool handler_smb_qpathinfo(int instance
)
2396 union smb_fileinfo parm
[NSERVERS
] = {0};
2397 NTSTATUS status
[NSERVERS
];
2399 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
2401 gen_fileinfo_smb(instance
, &parm
[0]);
2404 GEN_CALL_SMB(smb_raw_pathinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
2406 return cmp_fileinfo(instance
, parm
, status
);
2410 generate qfileinfo operations
2412 static bool handler_smb_qfileinfo(int instance
)
2414 union smb_fileinfo parm
[NSERVERS
] = {0};
2415 NTSTATUS status
[NSERVERS
];
2417 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
2419 gen_fileinfo_smb(instance
, &parm
[0]);
2422 GEN_SET_FNUM_SMB(generic
.in
.file
.fnum
);
2423 GEN_CALL_SMB(smb_raw_fileinfo(tree
, current_op
.mem_ctx
, &parm
[i
]));
2425 return cmp_fileinfo(instance
, parm
, status
);
2430 generate setpathinfo operations
2432 static bool handler_smb_spathinfo(int instance
)
2434 union smb_setfileinfo parm
[NSERVERS
] = {0};
2435 NTSTATUS status
[NSERVERS
];
2437 gen_setfileinfo(instance
, &parm
[0]);
2438 parm
[0].generic
.in
.file
.path
= gen_fname_open(instance
);
2442 /* a special case for the fid in a RENAME */
2443 if (parm
[0].generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
&&
2444 parm
[0].rename_information
.in
.root_fid
!= 0) {
2445 GEN_SET_FNUM_SMB(rename_information
.in
.root_fid
);
2448 GEN_CALL_SMB(smb_raw_setpathinfo(tree
, &parm
[i
]));
2455 generate setfileinfo operations
2457 static bool handler_smb_sfileinfo(int instance
)
2459 union smb_setfileinfo parm
[NSERVERS
] = {0};
2460 NTSTATUS status
[NSERVERS
];
2462 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
2464 gen_setfileinfo(instance
, &parm
[0]);
2467 GEN_SET_FNUM_SMB(generic
.in
.file
.fnum
);
2468 GEN_CALL_SMB(smb_raw_setfileinfo(tree
, &parm
[i
]));
2475 this is called when a change notify reply comes in
2477 static void async_notify_smb(struct smbcli_request
*req
)
2479 union smb_notify notify
;
2483 struct smbcli_transport
*transport
= req
->transport
;
2486 tid
= req
->tree
->tid
;
2489 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
2490 status
= smb_raw_changenotify_recv(req
, current_op
.mem_ctx
, ¬ify
);
2491 if (NT_STATUS_IS_OK(status
) && notify
.nttrans
.out
.num_changes
> 0) {
2492 printf("notify tid=%d num_changes=%d action=%d name=%s\n",
2494 notify
.nttrans
.out
.num_changes
,
2495 notify
.nttrans
.out
.changes
[0].action
,
2496 notify
.nttrans
.out
.changes
[0].name
.s
);
2499 for (i
=0;i
<NSERVERS
;i
++) {
2500 for (j
=0;j
<NINSTANCES
;j
++) {
2501 if (transport
== servers
[i
].smb_tree
[j
]->session
->transport
&&
2502 tid
== servers
[i
].smb_tree
[j
]->tid
) {
2503 notifies
[i
][j
].notify_count
++;
2504 notifies
[i
][j
].status
= status
;
2505 notifies
[i
][j
].notify
= notify
;
2512 generate change notify operations
2514 static bool handler_smb_notify(int instance
)
2516 union smb_notify parm
[NSERVERS
] = {0};
2519 parm
[0].nttrans
.level
= RAW_NOTIFY_NTTRANS
;
2520 parm
[0].nttrans
.in
.buffer_size
= gen_io_count();
2521 parm
[0].nttrans
.in
.completion_filter
= gen_bits_mask(0xFF);
2522 parm
[0].nttrans
.in
.file
.fnum
= gen_fnum(instance
);
2523 parm
[0].nttrans
.in
.recursive
= gen_bool();
2526 GEN_SET_FNUM_SMB(nttrans
.in
.file
.fnum
);
2528 for (n
=0;n
<NSERVERS
;n
++) {
2529 struct smbcli_request
*req
;
2530 req
= smb_raw_changenotify_send(servers
[n
].smb_tree
[instance
], &parm
[n
]);
2531 req
->async
.fn
= async_notify_smb
;
2539 generate ntcreatex operations
2541 static bool handler_smb2_create(int instance
)
2543 struct smb2_create parm
[NSERVERS
] = {0};
2544 NTSTATUS status
[NSERVERS
];
2546 ZERO_STRUCT(parm
[0]);
2547 parm
[0].in
.security_flags
= gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF);
2548 parm
[0].in
.oplock_level
= gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF);
2549 parm
[0].in
.impersonation_level
= gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF);
2550 parm
[0].in
.create_flags
= gen_reserved64();
2551 parm
[0].in
.reserved
= gen_reserved64();
2552 parm
[0].in
.desired_access
= gen_access_mask();
2553 parm
[0].in
.file_attributes
= gen_attrib();
2554 parm
[0].in
.share_access
= gen_bits_mask2(0x7, 0xFFFFFFFF);
2555 parm
[0].in
.create_disposition
= gen_open_disp();
2556 parm
[0].in
.create_options
= gen_create_options();
2557 parm
[0].in
.fname
= gen_fname_open(instance
);
2558 parm
[0].in
.eas
= gen_ea_list();
2559 parm
[0].in
.alloc_size
= gen_alloc_size();
2560 parm
[0].in
.durable_open
= gen_bool();
2561 parm
[0].in
.query_maximal_access
= gen_bool();
2562 parm
[0].in
.timewarp
= gen_timewarp();
2563 parm
[0].in
.query_on_disk_id
= gen_bool();
2564 parm
[0].in
.sec_desc
= gen_sec_desc();
2566 if (!options
.use_oplocks
) {
2567 /* mask out oplocks */
2568 parm
[0].in
.oplock_level
= 0;
2571 if (options
.valid
) {
2572 parm
[0].in
.security_flags
&= 3;
2573 parm
[0].in
.oplock_level
&= 9;
2574 parm
[0].in
.impersonation_level
&= 3;
2578 GEN_CALL_SMB2(smb2_create(tree
, current_op
.mem_ctx
, &parm
[i
]));
2580 CHECK_EQUAL(out
.oplock_level
);
2581 CHECK_EQUAL(out
.reserved
);
2582 CHECK_EQUAL(out
.create_action
);
2583 CHECK_NTTIMES_EQUAL(out
.create_time
);
2584 CHECK_NTTIMES_EQUAL(out
.access_time
);
2585 CHECK_NTTIMES_EQUAL(out
.write_time
);
2586 CHECK_NTTIMES_EQUAL(out
.change_time
);
2587 CHECK_EQUAL(out
.alloc_size
);
2588 CHECK_EQUAL(out
.size
);
2589 CHECK_ATTRIB(out
.file_attr
);
2590 CHECK_EQUAL(out
.reserved2
);
2591 CHECK_EQUAL(out
.maximal_access
);
2593 /* ntcreatex creates a new file handle */
2594 ADD_HANDLE_SMB2(parm
[0].in
.fname
, out
.file
.handle
);
2600 generate close operations
2602 static bool handler_smb2_close(int instance
)
2604 struct smb2_close parm
[NSERVERS
] = {0};
2605 NTSTATUS status
[NSERVERS
];
2607 ZERO_STRUCT(parm
[0]);
2608 parm
[0].in
.file
.handle
.data
[0] = gen_fnum_close(instance
);
2609 parm
[0].in
.flags
= gen_bits_mask2(0x1, 0xFFFF);
2612 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2613 GEN_CALL_SMB2(smb2_close(tree
, &parm
[i
]));
2615 CHECK_EQUAL(out
.flags
);
2616 CHECK_EQUAL(out
._pad
);
2617 CHECK_NTTIMES_EQUAL(out
.create_time
);
2618 CHECK_NTTIMES_EQUAL(out
.access_time
);
2619 CHECK_NTTIMES_EQUAL(out
.write_time
);
2620 CHECK_NTTIMES_EQUAL(out
.change_time
);
2621 CHECK_EQUAL(out
.alloc_size
);
2622 CHECK_EQUAL(out
.size
);
2623 CHECK_ATTRIB(out
.file_attr
);
2625 REMOVE_HANDLE_SMB2(in
.file
.handle
);
2631 generate read operations
2633 static bool handler_smb2_read(int instance
)
2635 struct smb2_read parm
[NSERVERS
] = {0};
2636 NTSTATUS status
[NSERVERS
];
2638 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2639 parm
[0].in
.reserved
= gen_reserved8();
2640 parm
[0].in
.length
= gen_io_count();
2641 parm
[0].in
.offset
= gen_offset();
2642 parm
[0].in
.min_count
= gen_io_count();
2643 parm
[0].in
.channel
= gen_bits_mask2(0x0, 0xFFFFFFFF);
2644 parm
[0].in
.remaining
= gen_bits_mask2(0x0, 0xFFFFFFFF);
2645 parm
[0].in
.channel_offset
= gen_bits_mask2(0x0, 0xFFFF);
2646 parm
[0].in
.channel_length
= gen_bits_mask2(0x0, 0xFFFF);
2649 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2650 GEN_CALL_SMB2(smb2_read(tree
, current_op
.mem_ctx
, &parm
[i
]));
2652 CHECK_EQUAL(out
.remaining
);
2653 CHECK_EQUAL(out
.reserved
);
2654 CHECK_EQUAL(out
.data
.length
);
2660 generate write operations
2662 static bool handler_smb2_write(int instance
)
2664 struct smb2_write parm
[NSERVERS
] = {0};
2665 NTSTATUS status
[NSERVERS
];
2667 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2668 parm
[0].in
.offset
= gen_offset();
2669 parm
[0].in
.unknown1
= gen_bits_mask2(0, 0xFFFFFFFF);
2670 parm
[0].in
.unknown2
= gen_bits_mask2(0, 0xFFFFFFFF);
2671 parm
[0].in
.data
= data_blob_talloc(current_op
.mem_ctx
, NULL
,
2675 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2676 GEN_CALL_SMB2(smb2_write(tree
, &parm
[i
]));
2678 CHECK_EQUAL(out
._pad
);
2679 CHECK_EQUAL(out
.nwritten
);
2680 CHECK_EQUAL(out
.unknown1
);
2686 generate lockingx operations
2688 static bool handler_smb2_lock(int instance
)
2690 struct smb2_lock parm
[NSERVERS
] = {0};
2691 NTSTATUS status
[NSERVERS
];
2694 parm
[0].level
= RAW_LOCK_LOCKX
;
2695 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2696 parm
[0].in
.lock_count
= gen_lock_count();
2697 parm
[0].in
.lock_sequence
= gen_reserved32();
2699 parm
[0].in
.locks
= talloc_array(current_op
.mem_ctx
,
2700 struct smb2_lock_element
,
2701 parm
[0].in
.lock_count
);
2702 for (n
=0;n
<parm
[0].in
.lock_count
;n
++) {
2703 parm
[0].in
.locks
[n
].offset
= gen_offset();
2704 parm
[0].in
.locks
[n
].length
= gen_io_count();
2705 /* don't yet cope with async replies */
2706 parm
[0].in
.locks
[n
].flags
= gen_lock_flags_smb2() |
2707 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
;
2708 parm
[0].in
.locks
[n
].reserved
= gen_bits_mask2(0x0, 0xFFFFFFFF);
2712 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2713 GEN_CALL_SMB2(smb2_lock(tree
, &parm
[i
]));
2719 generate flush operations
2721 static bool handler_smb2_flush(int instance
)
2723 struct smb2_flush parm
[NSERVERS
] = {0};
2724 NTSTATUS status
[NSERVERS
];
2726 ZERO_STRUCT(parm
[0]);
2727 parm
[0].in
.file
.handle
.data
[0] = gen_fnum(instance
);
2728 parm
[0].in
.reserved1
= gen_reserved16();
2729 parm
[0].in
.reserved2
= gen_reserved32();
2732 GEN_SET_FNUM_SMB2(in
.file
.handle
);
2733 GEN_CALL_SMB2(smb2_flush(tree
, &parm
[i
]));
2735 CHECK_EQUAL(out
.reserved
);
2741 generate echo operations
2743 static bool handler_smb2_echo(int instance
)
2745 NTSTATUS status
[NSERVERS
];
2747 GEN_CALL_SMB2(smb2_keepalive(tree
->session
->transport
));
2755 generate a fileinfo query structure
2757 static void gen_fileinfo_smb2(int instance
, union smb_fileinfo
*info
)
2760 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
2762 enum smb_fileinfo_level level
;
2765 LVL(BASIC_INFORMATION
),
2766 LVL(STANDARD_INFORMATION
), LVL(INTERNAL_INFORMATION
), LVL(EA_INFORMATION
),
2767 LVL(ACCESS_INFORMATION
), LVL(NAME_INFORMATION
), LVL(POSITION_INFORMATION
),
2768 LVL(MODE_INFORMATION
), LVL(ALIGNMENT_INFORMATION
), LVL(SMB2_ALL_INFORMATION
),
2769 LVL(ALT_NAME_INFORMATION
), LVL(STREAM_INFORMATION
), LVL(COMPRESSION_INFORMATION
),
2770 LVL(NETWORK_OPEN_INFORMATION
), LVL(ATTRIBUTE_TAG_INFORMATION
),
2771 LVL(SMB2_ALL_EAS
), LVL(SMB2_ALL_INFORMATION
), LVL(SEC_DESC
),
2774 i
= gen_int_range(0, ARRAY_SIZE(levels
)-1);
2775 } while (ignore_pattern(levels
[i
].name
));
2777 info
->generic
.level
= levels
[i
].level
;
2781 generate qfileinfo operations
2783 static bool handler_smb2_qfileinfo(int instance
)
2785 union smb_fileinfo parm
[NSERVERS
] = {0};
2786 NTSTATUS status
[NSERVERS
];
2788 parm
[0].generic
.in
.file
.handle
.data
[0] = gen_fnum(instance
);
2790 gen_fileinfo_smb2(instance
, &parm
[0]);
2793 GEN_SET_FNUM_SMB2(generic
.in
.file
.handle
);
2794 GEN_CALL_SMB2(smb2_getinfo_file(tree
, current_op
.mem_ctx
, &parm
[i
]));
2796 return cmp_fileinfo(instance
, parm
, status
);
2801 generate setfileinfo operations
2803 static bool handler_smb2_sfileinfo(int instance
)
2805 union smb_setfileinfo parm
[NSERVERS
] = {0};
2806 NTSTATUS status
[NSERVERS
];
2808 gen_setfileinfo(instance
, &parm
[0]);
2809 parm
[0].generic
.in
.file
.fnum
= gen_fnum(instance
);
2812 GEN_SET_FNUM_SMB2(generic
.in
.file
.handle
);
2813 GEN_CALL_SMB2(smb2_setinfo_file(tree
, &parm
[i
]));
2819 wipe any relevant files
2821 static void wipe_files(void)
2826 if (options
.skip_cleanup
) {
2830 for (i
=0;i
<NSERVERS
;i
++) {
2833 n
= smb2_deltree(servers
[i
].smb2_tree
[0], "gentest");
2835 n
= smbcli_deltree(servers
[i
].smb_tree
[0], "gentest");
2838 printf("Failed to wipe tree on server %d\n", i
);
2842 status
= smb2_util_mkdir(servers
[i
].smb2_tree
[0], "gentest");
2844 status
= smbcli_mkdir(servers
[i
].smb_tree
[0], "gentest");
2846 if (NT_STATUS_IS_ERR(status
)) {
2847 printf("Failed to create gentest on server %d - %s\n", i
, nt_errstr(status
));
2851 printf("Deleted %d files on server %d\n", n
, i
);
2857 dump the current seeds - useful for continuing a backtrack
2859 static void dump_seeds(void)
2864 if (!options
.seeds_file
) {
2867 f
= fopen("seeds.tmp", "w");
2870 for (i
=0;i
<options
.numops
;i
++) {
2871 fprintf(f
, "%u\n", op_parms
[i
].seed
);
2874 rename("seeds.tmp", options
.seeds_file
);
2880 the list of top-level operations that we will generate
2884 bool (*handler
)(int instance
);
2886 int count
, success_count
;
2890 .handler
= handler_smb2_create
,
2895 .handler
= handler_smb2_close
,
2900 .handler
= handler_smb2_read
,
2905 .handler
= handler_smb2_write
,
2910 .handler
= handler_smb2_lock
,
2915 .handler
= handler_smb2_flush
,
2920 .handler
= handler_smb2_echo
,
2924 .name
= "QFILEINFO",
2925 .handler
= handler_smb2_qfileinfo
,
2929 .name
= "SFILEINFO",
2930 .handler
= handler_smb2_sfileinfo
,
2936 .handler
= handler_smb_open
,
2941 .handler
= handler_smb_openx
,
2945 .name
= "NTCREATEX",
2946 .handler
= handler_smb_ntcreatex
,
2951 .handler
= handler_smb_close
,
2956 .handler
= handler_smb_unlink
,
2961 .handler
= handler_smb_mkdir
,
2966 .handler
= handler_smb_rmdir
,
2971 .handler
= handler_smb_rename
,
2976 .handler
= handler_smb_ntrename
,
2981 .handler
= handler_smb_readx
,
2986 .handler
= handler_smb_writex
,
2991 .handler
= handler_smb_chkpath
,
2996 .handler
= handler_smb_seek
,
3001 .handler
= handler_smb_lockingx
,
3005 .name
= "QPATHINFO",
3006 .handler
= handler_smb_qpathinfo
,
3010 .name
= "QFILEINFO",
3011 .handler
= handler_smb_qfileinfo
,
3015 .name
= "SPATHINFO",
3016 .handler
= handler_smb_spathinfo
,
3020 .name
= "SFILEINFO",
3021 .handler
= handler_smb_sfileinfo
,
3026 .handler
= handler_smb_notify
,
3033 run the test with the current set of op_parms parameters
3034 return the number of operations that completed successfully
3036 static int run_test(struct tevent_context
*ev
, struct loadparm_context
*lp_ctx
)
3040 if (!connect_servers(ev
, lp_ctx
)) {
3041 printf("Failed to connect to servers\n");
3047 /* wipe any leftover files from old runs */
3050 /* reset the open handles array */
3051 memset(open_handles
, 0, options
.max_open_handles
* sizeof(open_handles
[0]));
3052 num_open_handles
= 0;
3054 /* reset the counts from previous runs */
3055 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
3056 gen_ops
[i
].count
= 0;
3057 gen_ops
[i
].success_count
= 0;
3060 for (op
=0; op
<options
.numops
; op
++) {
3061 int instance
, which_op
;
3064 if (op_parms
[op
].disabled
) continue;
3066 srandom(op_parms
[op
].seed
);
3068 instance
= gen_int_range(0, NINSTANCES
-1);
3070 /* generate a non-ignored operation */
3072 which_op
= gen_int_range(0, ARRAY_SIZE(gen_ops
)-1);
3073 } while (ignore_pattern(gen_ops
[which_op
].name
) ||
3074 gen_ops
[which_op
].smb2
!= options
.smb2
);
3076 DEBUG(3,("Generating op %s on instance %d\n",
3077 gen_ops
[which_op
].name
, instance
));
3079 current_op
.seed
= op_parms
[op
].seed
;
3080 current_op
.opnum
= op
;
3081 current_op
.name
= gen_ops
[which_op
].name
;
3082 current_op
.status
= NT_STATUS_OK
;
3083 talloc_free(current_op
.mem_ctx
);
3084 current_op
.mem_ctx
= talloc_named(NULL
, 0, "%s", current_op
.name
);
3086 ret
= gen_ops
[which_op
].handler(instance
);
3088 gen_ops
[which_op
].count
++;
3089 if (NT_STATUS_IS_OK(current_op
.status
)) {
3090 gen_ops
[which_op
].success_count
++;
3094 printf("Failed at operation %d - %s\n",
3095 op
, gen_ops
[which_op
].name
);
3099 if (op
% 100 == 0) {
3104 for (i
=0;i
<ARRAY_SIZE(gen_ops
);i
++) {
3105 printf("Op %-10s got %d/%d success\n",
3107 gen_ops
[i
].success_count
,
3115 perform a backtracking analysis of the minimal set of operations
3116 to generate an error
3118 static void backtrack_analyze(struct tevent_context
*ev
,
3119 struct loadparm_context
*lp_ctx
)
3122 const char *mismatch
= current_op
.mismatch
;
3124 chunk
= options
.numops
/ 2;
3129 chunk
> 0 && base
+chunk
< options
.numops
&& options
.numops
> 1; ) {
3132 chunk
= MIN(chunk
, options
.numops
/ 2);
3134 /* mark this range as disabled */
3135 max
= MIN(options
.numops
, base
+chunk
);
3136 for (i
=base
;i
<max
; i
++) {
3137 op_parms
[i
].disabled
= true;
3139 printf("Testing %d ops with %d-%d disabled\n",
3140 options
.numops
, base
, max
-1);
3141 ret
= run_test(ev
, lp_ctx
);
3142 printf("Completed %d of %d ops\n", ret
, options
.numops
);
3143 for (i
=base
;i
<max
; i
++) {
3144 op_parms
[i
].disabled
= false;
3146 if (ret
== options
.numops
) {
3147 /* this chunk is needed */
3149 } else if (mismatch
!= current_op
.mismatch
&&
3150 strcmp(mismatch
, current_op
.mismatch
)) {
3152 printf("Different error in backtracking\n");
3153 } else if (ret
< base
) {
3154 printf("damn - inconsistent errors! found early error\n");
3155 options
.numops
= ret
+1;
3158 /* it failed - this chunk isn't needed for a failure */
3159 memmove(&op_parms
[base
], &op_parms
[max
],
3160 sizeof(op_parms
[0]) * (options
.numops
- max
));
3161 options
.numops
= (ret
+1) - (max
- base
);
3171 if (options
.analyze_continuous
&& chunk
== 0 && options
.numops
!= 1) {
3174 } while (chunk
> 0);
3176 printf("Reduced to %d ops\n", options
.numops
);
3177 ret
= run_test(ev
, lp_ctx
);
3178 if (ret
!= options
.numops
- 1) {
3179 printf("Inconsistent result? ret=%d numops=%d\n", ret
, options
.numops
);
3184 start the main gentest process
3186 static bool start_gentest(struct tevent_context
*ev
,
3187 struct loadparm_context
*lp_ctx
)
3192 /* allocate the open_handles array */
3193 open_handles
= calloc(options
.max_open_handles
, sizeof(open_handles
[0]));
3194 if (open_handles
== NULL
) {
3195 printf("Unable to allocate memory for open_handles array.\n");
3199 srandom(options
.seed
);
3200 op_parms
= calloc(options
.numops
, sizeof(op_parms
[0]));
3201 if (op_parms
== NULL
) {
3202 printf("Unable to allocate memory for op_parms.\n");
3206 /* generate the seeds - after this everything is deterministic */
3207 if (options
.use_preset_seeds
) {
3209 char **preset
= file_lines_load(options
.seeds_file
, &numops
, 0, NULL
);
3211 printf("Failed to load %s - %s\n", options
.seeds_file
, strerror(errno
));
3214 if (numops
< options
.numops
) {
3215 options
.numops
= numops
;
3217 for (op
=0;op
<options
.numops
;op
++) {
3219 printf("Not enough seeds in %s\n", options
.seeds_file
);
3222 op_parms
[op
].seed
= atoi(preset
[op
]);
3224 printf("Loaded %d seeds from %s\n", options
.numops
, options
.seeds_file
);
3226 for (op
=0; op
<options
.numops
; op
++) {
3227 op_parms
[op
].seed
= random();
3231 ret
= run_test(ev
, lp_ctx
);
3233 if (ret
!= options
.numops
&& options
.analyze
) {
3234 options
.numops
= ret
+1;
3235 backtrack_analyze(ev
, lp_ctx
);
3236 } else if (options
.analyze_always
) {
3237 backtrack_analyze(ev
, lp_ctx
);
3238 } else if (options
.analyze_continuous
) {
3239 while (run_test(ev
, lp_ctx
) == options
.numops
) ;
3242 return ret
== options
.numops
;
3246 static void usage(poptContext pc
)
3250 gentest //server1/share1 //server2/share2 [options..]\n\
3252 poptPrintUsage(pc
, stdout
, 0);
3256 split a UNC name into server and share names
3258 static bool split_unc_name(const char *unc
, char **server
, char **share
)
3260 char *p
= strdup(unc
);
3261 if (!p
) return false;
3262 all_string_sub(p
, "\\", "/", 0);
3263 if (strncmp(p
, "//", 2) != 0) return false;
3266 p
= strchr(*server
, '/');
3267 if (!p
) return false;
3277 /****************************************************************************
3279 ****************************************************************************/
3280 int main(int argc
, const char *argv
[])
3283 int i
, username_count
=0;
3285 char *ignore_file
=NULL
;
3286 struct tevent_context
*ev
;
3287 struct loadparm_context
*lp_ctx
;
3296 struct poptOption long_options
[] = {
3298 {"smb2", 0, POPT_ARG_NONE
, &options
.smb2
, 0, "use SMB2 protocol", NULL
},
3299 {"seed", 0, POPT_ARG_INT
, &options
.seed
, 0, "Seed to use for randomizer", NULL
},
3300 {"num-ops", 0, POPT_ARG_INT
, &options
.numops
, 0, "num ops", NULL
},
3301 {"oplocks", 0, POPT_ARG_NONE
, &options
.use_oplocks
,0, "use oplocks", NULL
},
3302 {"showall", 0, POPT_ARG_NONE
, &options
.showall
, 0, "display all operations", NULL
},
3303 {"analyse", 0, POPT_ARG_NONE
, &options
.analyze
, 0, "do backtrack analysis", NULL
},
3304 {"analysealways", 0, POPT_ARG_NONE
, &options
.analyze_always
, 0, "analysis always", NULL
},
3305 {"analysecontinuous", 0, POPT_ARG_NONE
, &options
.analyze_continuous
, 0, "analysis continuous", NULL
},
3306 {"ignore", 0, POPT_ARG_STRING
, &ignore_file
, 0, "ignore from file", NULL
},
3307 {"preset", 0, POPT_ARG_NONE
, &options
.use_preset_seeds
, 0, "use preset seeds", NULL
},
3308 {"fast", 0, POPT_ARG_NONE
, &options
.fast_reconnect
, 0, "use fast reconnect", NULL
},
3309 {"unclist", 0, POPT_ARG_STRING
, NULL
, OPT_UNCLIST
, "unclist", NULL
},
3310 {"seedsfile", 0, POPT_ARG_STRING
, &options
.seeds_file
, 0, "seed file", NULL
},
3311 {"user1", 0, POPT_ARG_STRING
, NULL
, OPT_USER1
, "Set first network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
3312 {"user2", 0, POPT_ARG_STRING
, NULL
, OPT_USER2
, "Set second network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
3313 {"maskindexing", 0, POPT_ARG_NONE
, &options
.mask_indexing
, 0, "mask out the indexed file attrib", NULL
},
3314 {"noeas", 0, POPT_ARG_NONE
, &options
.no_eas
, 0, "don't use extended attributes", NULL
},
3315 {"noacls", 0, POPT_ARG_NONE
, &options
.no_acls
, 0, "don't use ACLs", NULL
},
3316 {"skip-cleanup", 0, POPT_ARG_NONE
, &options
.skip_cleanup
, 0, "don't delete files at start", NULL
},
3317 {"valid", 0, POPT_ARG_NONE
, &options
.valid
, 0, "generate only valid fields", NULL
},
3319 POPT_COMMON_CONNECTION
3320 POPT_COMMON_CREDENTIALS
3325 TALLOC_CTX
*mem_ctx
= NULL
;
3328 memset(&bad_smb2_handle
, 0xFF, sizeof(bad_smb2_handle
));
3331 options
.seed
= time(NULL
);
3332 options
.numops
= 1000;
3333 options
.max_open_handles
= 20;
3334 options
.seeds_file
= "gentest_seeds.dat";
3336 mem_ctx
= talloc_named_const(NULL
, 0, "gentest_ctx");
3337 if (mem_ctx
== NULL
) {
3338 printf("Unable to allocate gentest_ctx\n");
3342 ok
= samba_cmdline_init(mem_ctx
,
3343 SAMBA_CMDLINE_CONFIG_CLIENT
,
3344 false /* require_smbconf */);
3346 DBG_ERR("Failed to init cmdline parser!\n");
3347 TALLOC_FREE(mem_ctx
);
3351 pc
= samba_popt_get_context(getprogname(),
3355 POPT_CONTEXT_KEEP_FIRST
);
3357 DBG_ERR("Failed to setup popt context!\n");
3358 TALLOC_FREE(mem_ctx
);
3362 poptSetOtherOptionHelp(pc
, "<unc1> <unc2>");
3364 lp_ctx
= samba_cmdline_get_lp_ctx();
3365 servers
[0].credentials
= cli_credentials_init(mem_ctx
);
3366 servers
[1].credentials
= cli_credentials_init(mem_ctx
);
3367 cli_credentials_guess(servers
[0].credentials
, lp_ctx
);
3368 cli_credentials_guess(servers
[1].credentials
, lp_ctx
);
3370 while((opt
= poptGetNextOpt(pc
)) != -1) {
3373 lpcfg_set_cmdline(lp_ctx
, "torture:unclist", poptGetOptArg(pc
));
3376 cli_credentials_parse_string(servers
[0].credentials
,
3382 cli_credentials_parse_string(servers
[1].credentials
,
3387 case POPT_ERROR_BADOPT
:
3388 fprintf(stderr
, "\nInvalid option %s: %s\n\n",
3389 poptBadOption(pc
, 0), poptStrerror(opt
));
3390 poptPrintUsage(pc
, stderr
, 0);
3396 options
.ignore_patterns
= file_lines_load(ignore_file
, NULL
, 0, NULL
);
3399 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
3401 for (i
=0; i
<argc
; i
++) {
3402 if (argv_new
[i
] == NULL
) {
3408 if (!(argc_new
>= 3)) {
3410 talloc_free(mem_ctx
);
3416 setup_logging("gentest", DEBUG_STDOUT
);
3418 if (argc
< 3 || argv
[1][0] == '-') {
3420 talloc_free(mem_ctx
);
3424 setup_logging(argv
[0], DEBUG_STDOUT
);
3426 for (i
=0;i
<NSERVERS
;i
++) {
3427 const char *share
= argv
[1+i
];
3428 if (!split_unc_name(share
, &servers
[i
].server_name
, &servers
[i
].share_name
)) {
3429 printf("Invalid share name '%s'\n", share
);
3430 poptFreeContext(pc
);
3431 talloc_free(mem_ctx
);
3436 if (username_count
== 0) {
3438 poptFreeContext(pc
);
3439 talloc_free(mem_ctx
);
3442 if (username_count
== 1) {
3443 servers
[1].credentials
= servers
[0].credentials
;
3446 printf("seed=%u\n", options
.seed
);
3448 ev
= s4_event_context_init(mem_ctx
);
3452 ret
= start_gentest(ev
, lp_ctx
);
3455 printf("gentest completed - no errors\n");
3457 printf("gentest failed\n");
3460 poptFreeContext(pc
);
3461 talloc_free(mem_ctx
);