X-Git-Url: http://git.samba.org/samba.git/?p=sfrench%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source4%2Ftorture%2Fgentest.c;h=0677d9ac8e29e0ecb19686dcfd1871d4623241e8;hp=9e5ef73ea6a306525b37fe6cf6461ea1f3452d5c;hb=183c379fe58ca60f5ef2d1f2033d035d4117ac8f;hpb=771b347f9b185895390445be96081c781e28a26d diff --git a/source4/torture/gentest.c b/source4/torture/gentest.c index 9e5ef73ea6a..0677d9ac8e2 100644 --- a/source4/torture/gentest.c +++ b/source4/torture/gentest.c @@ -1,7 +1,9 @@ /* Unix SMB/CIFS implementation. - generic testing tool - Copyright (C) Andrew Tridgell 2003 + + generic testing tool - version with both SMB and SMB2 support + + Copyright (C) Andrew Tridgell 2003-2008 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,42 +20,56 @@ */ #include "includes.h" +#include "lib/cmdline/popt_common.h" +#include "lib/events/events.h" #include "system/time.h" #include "system/filesys.h" #include "libcli/raw/request.h" #include "libcli/libcli.h" #include "libcli/raw/libcliraw.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" #include "librpc/gen_ndr/security.h" +#include "librpc/gen_ndr/ndr_security.h" #include "auth/credentials/credentials.h" #include "libcli/resolve/resolve.h" #include "auth/gensec/gensec.h" #include "param/param.h" -#include "dynconfig.h" +#include "dynconfig/dynconfig.h" +#include "libcli/security/security.h" +#include "libcli/raw/raw_proto.h" #define NSERVERS 2 #define NINSTANCES 2 /* global options */ static struct gentest_options { - bool showall; - bool analyze; - bool analyze_always; - bool analyze_continuous; + int showall; + int analyze; + int analyze_always; + int analyze_continuous; uint_t max_open_handles; uint_t seed; uint_t numops; - bool use_oplocks; + int use_oplocks; char **ignore_patterns; const char *seeds_file; - bool use_preset_seeds; - bool fast_reconnect; + int use_preset_seeds; + int fast_reconnect; + int mask_indexing; + int no_eas; + int no_acls; + int skip_cleanup; + int valid; + int smb2; } options; /* mapping between open handles on the server and local handles */ static struct { bool active; uint_t instance; - uint_t server_fnum[NSERVERS]; + struct smb2_handle smb2_handle[NSERVERS]; /* SMB2 */ + uint16_t smb_handle[NSERVERS]; /* SMB */ const char *name; } *open_handles; static uint_t num_open_handles; @@ -61,7 +77,8 @@ static uint_t num_open_handles; /* state information for the servers. We open NINSTANCES connections to each server */ static struct { - struct smbcli_state *cli[NINSTANCES]; + struct smb2_tree *smb2_tree[NINSTANCES]; + struct smbcli_tree *smb_tree[NINSTANCES]; char *server_name; char *share_name; struct cli_credentials *credentials; @@ -77,7 +94,8 @@ static struct { /* oplock break info */ static struct { bool got_break; - uint16_t fnum; + struct smb2_handle smb2_handle; + uint16_t smb_handle; uint16_t handle; uint8_t level; bool do_close; @@ -97,14 +115,19 @@ static struct { NTSTATUS status; uint_t opnum; TALLOC_CTX *mem_ctx; + const char *mismatch; } current_op; +static struct smb2_handle bad_smb2_handle; #define BAD_HANDLE 0xFFFE -static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private); -static void idle_func(struct smbcli_transport *transport, void *private); +static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, + uint8_t level, void *private_data); +static void idle_func_smb2(struct smb2_transport *transport, void *private); +static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private); +static void idle_func_smb(struct smbcli_transport *transport, void *private); /* check if a string should be ignored. This is used as the basis @@ -136,8 +159,15 @@ static bool connect_servers_fast(void) for (h=0;htree, - open_handles[h].server_fnum[i])))) { + NTSTATUS status; + if (options.smb2) { + status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance], + open_handles[h].smb2_handle[i]); + } else { + status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], + open_handles[h].smb_handle[i]); + } + if (NT_STATUS_IS_ERR(status)) { return false; } open_handles[h].active = false; @@ -153,11 +183,12 @@ static bool connect_servers_fast(void) /***************************************************** connect to the servers *******************************************************/ -static bool connect_servers(struct loadparm_context *lp_ctx) +static bool connect_servers(struct tevent_context *ev, + struct loadparm_context *lp_ctx) { int i, j; - if (options.fast_reconnect && servers[0].cli[0]) { + if (options.fast_reconnect && servers[0].smb2_tree[0]) { if (connect_servers_fast()) { return true; } @@ -166,10 +197,15 @@ static bool connect_servers(struct loadparm_context *lp_ctx) /* close any existing connections */ for (i=0;iusername, j); @@ -184,13 +225,31 @@ static bool connect_servers(struct loadparm_context *lp_ctx) cli_credentials_set_workstation(servers[i].credentials, "gentest", CRED_SPECIFIED); - status = smbcli_full_connection(NULL, &servers[i].cli[j], - servers[i].server_name, - lp_smb_ports(lp_ctx), - servers[i].share_name, NULL, - servers[i].credentials, - lp_resolve_context(lp_ctx), - NULL); + if (options.smb2) { + status = smb2_connect(NULL, servers[i].server_name, + lp_smb_ports(lp_ctx), + servers[i].share_name, + lp_resolve_context(lp_ctx), + servers[i].credentials, + &servers[i].smb2_tree[j], + ev, &smb_options, + lp_socket_options(lp_ctx), + lp_gensec_settings(lp_ctx, lp_ctx) + ); + } else { + status = smbcli_tree_full_connection(NULL, + &servers[i].smb_tree[j], + servers[i].server_name, + lp_smb_ports(lp_ctx), + servers[i].share_name, "A:", + lp_socket_options(lp_ctx), + servers[i].credentials, + lp_resolve_context(lp_ctx), ev, + &smb_options, + &smb_session_options, + lp_iconv_convenience(lp_ctx), + lp_gensec_settings(lp_ctx, lp_ctx)); + } if (!NT_STATUS_IS_OK(status)) { printf("Failed to connect to \\\\%s\\%s - %s\n", servers[i].server_name, servers[i].share_name, @@ -198,8 +257,17 @@ static bool connect_servers(struct loadparm_context *lp_ctx) return false; } - smbcli_oplock_handler(servers[i].cli[j]->transport, oplock_handler, NULL); - smbcli_transport_idle_handler(servers[i].cli[j]->transport, idle_func, 50000, NULL); + if (options.smb2) { + servers[i].smb2_tree[j]->session->transport->oplock.handler = oplock_handler_smb2; + servers[i].smb2_tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j); + smb2_transport_idle_handler(servers[i].smb2_tree[j]->session->transport, + idle_func_smb2, 50000, NULL); + } else { + smbcli_oplock_handler(servers[i].smb_tree[j]->session->transport, oplock_handler_smb, + (void *)(uintptr_t)((i<<8)|j)); + smbcli_transport_idle_handler(servers[i].smb_tree[j]->session->transport, idle_func_smb, + 50000, (void *)(uintptr_t)((i<<8)|j)); + } } } @@ -212,33 +280,98 @@ static bool connect_servers(struct loadparm_context *lp_ctx) static uint_t time_skew(void) { uint_t ret; - ret = labs(servers[0].cli[0]->transport->negotiate.server_time - - servers[1].cli[0]->transport->negotiate.server_time); + if (options.smb2) { + ret = labs(servers[0].smb2_tree[0]->session->transport->negotiate.system_time - + servers[1].smb2_tree[0]->session->transport->negotiate.system_time); + } else { + ret = labs(servers[0].smb_tree[0]->session->transport->negotiate.server_time - + servers[1].smb_tree[0]->session->transport->negotiate.server_time); + } return ret + 300; } + +static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2) +{ + return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0; +} + +/* + turn a server handle into a local handle +*/ +static uint_t fnum_to_handle_smb2(int server, int instance, struct smb2_handle server_handle) +{ + uint_t i; + for (i=0;itree, - open_handles[h].server_fnum[i])))) { + NTSTATUS status; + status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], + open_handles[h].smb_handle[i]); + if (NT_STATUS_IS_ERR(status)) { printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n", - smbcli_errstr(servers[i].cli[open_handles[h].instance]->tree)); + nt_errstr(status)); } } printf("Recovered handle %d\n", h); num_open_handles--; } for (i=0;itransport; - - tid = SVAL(req->in.hdr, HDR_TID); - - notify.nttrans.level = RAW_NOTIFY_NTTRANS; - status = smb_raw_changenotify_recv(req, current_op.mem_ctx, ¬ify); - if (NT_STATUS_IS_OK(status)) { - printf("notify tid=%d num_changes=%d action=%d name=%s\n", - tid, - notify.nttrans.out.num_changes, - notify.nttrans.out.changes[0].action, - notify.nttrans.out.changes[0].name.s); + struct smb_ea_list eas; + int i; + if (options.no_eas) { + ZERO_STRUCT(eas); + return eas; } - - for (i=0;itransport && - tid == servers[i].cli[j]->tree->tid) { - notifies[i][j].notify_count++; - notifies[i][j].status = status; - notifies[i][j].notify = notify; - } - } + eas.num_eas = gen_int_range(0, 3); + eas.eas = talloc_array(current_op.mem_ctx, struct ea_struct, eas.num_eas); + for (i=0;itransport && - tid == servers[i].cli[j]->tree->tid) { + if (transport == servers[i].smb_tree[j]->session->transport && + tid == servers[i].smb_tree[j]->tid) { oplocks[i][j].got_break = true; - oplocks[i][j].fnum = fnum; - oplocks[i][j].handle = fnum_to_handle(i, j, fnum); + oplocks[i][j].smb_handle = fnum; + oplocks[i][j].handle = fnum_to_handle_smb(i, j, fnum); oplocks[i][j].level = level; oplocks[i][j].do_close = do_close; - tree = servers[i].cli[j]->tree; + tree = servers[i].smb_tree[j]; } } } @@ -778,7 +1023,7 @@ static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uin return false; } - req->async.fn = oplock_handler_close_recv; + req->async.fn = oplock_handler_close_recv_smb; req->async.private = NULL; return true; @@ -790,84 +1035,226 @@ static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uin an operation on another connection blocking until that break is acked we check for operations on all transports in the idle function */ -static void idle_func(struct smbcli_transport *transport, void *private) +static void idle_func_smb(struct smbcli_transport *transport, void *private) { int i, j; for (i=0;itransport) { - smbcli_transport_process(servers[i].cli[j]->transport); + if (servers[i].smb_tree[j] && + transport != servers[i].smb_tree[j]->session->transport) { + smbcli_transport_process(servers[i].smb_tree[j]->session->transport); } } } } - -/* - compare NTSTATUS, using checking ignored patterns -*/ -static bool compare_status(NTSTATUS status1, NTSTATUS status2) +static void oplock_handler_close_recv_smb2(struct smb2_request *req) { - if (NT_STATUS_EQUAL(status1, status2)) return true; + NTSTATUS status; + struct smb2_close io; + status = smb2_close_recv(req, &io); + if (!NT_STATUS_IS_OK(status)) { + printf("close failed in oplock_handler\n"); + smb_panic("close failed in oplock_handler"); + } +} - /* one code being an error and the other OK is always an error */ - if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) return false; +static void oplock_handler_ack_callback_smb2(struct smb2_request *req) +{ + NTSTATUS status; + struct smb2_break br; - /* if we are ignoring one of the status codes then consider this a match */ - if (ignore_pattern(nt_errstr(status1)) || - ignore_pattern(nt_errstr(status2))) { - return true; + status = smb2_break_recv(req, &br); + if (!NT_STATUS_IS_OK(status)) { + printf("oplock break ack failed in oplock_handler\n"); + smb_panic("oplock break ack failed in oplock_handler"); } - return false; } - -/* - check for pending packets on all connections -*/ -static void check_pending(void) +static bool send_oplock_ack_smb2(struct smb2_tree *tree, struct smb2_handle handle, + uint8_t level) { - int i, j; + struct smb2_break br; + struct smb2_request *req; - msleep(20); + ZERO_STRUCT(br); + br.in.file.handle = handle; + br.in.oplock_level = level; + br.in.reserved = gen_reserved8(); + br.in.reserved2 = gen_reserved32(); - for (j=0;jtransport); - } - } + req = smb2_break_send(tree, &br); + if (req == NULL) return false; + req->async.fn = oplock_handler_ack_callback_smb2; + req->async.private_data = NULL; + return true; } /* - check that the same oplock breaks have been received by all instances + the oplock handler will either ack the break or close the file */ -static bool check_oplocks(const char *call) +static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, + uint8_t level, void *private_data) { - int i, j; - int tries = 0; + struct smb2_close io; + unsigned i, j; + bool do_close; + struct smb2_tree *tree = NULL; + struct smb2_request *req; -again: - check_pending(); + srandom(current_op.seed); + do_close = gen_chance(50); - for (j=0;j> 8; + j = ((uintptr_t)private_data) & 0xFF; + + if (i >= NSERVERS || j >= NINSTANCES) { + printf("Bad private_data in oplock_handler\n"); + return false; + } + + oplocks[i][j].got_break = true; + oplocks[i][j].smb2_handle = *handle; + oplocks[i][j].handle = fnum_to_handle_smb2(i, j, *handle); + oplocks[i][j].level = level; + oplocks[i][j].do_close = do_close; + tree = talloc_get_type(servers[i].smb2_tree[j], struct smb2_tree); + + if (!tree) { + printf("Oplock break not for one of our trees!?\n"); + return false; + } + + if (!do_close) { + printf("oplock ack handle=%d\n", oplocks[i][j].handle); + return send_oplock_ack_smb2(tree, *handle, level); + } + + printf("oplock close fnum=%d\n", oplocks[i][j].handle); + + ZERO_STRUCT(io); + io.in.file.handle = *handle; + io.in.flags = 0; + req = smb2_close_send(tree, &io); + + if (req == NULL) { + printf("WARNING: close failed in oplock_handler_close\n"); + return false; + } + + req->async.fn = oplock_handler_close_recv_smb2; + req->async.private_data = NULL; + + return true; +} + + +/* + the idle function tries to cope with getting an oplock break on a connection, and + an operation on another connection blocking until that break is acked + we check for operations on all transports in the idle function +*/ +static void idle_func_smb2(struct smb2_transport *transport, void *private) +{ + int i, j; + for (i=0;isession->transport) { + // smb2_transport_process(servers[i].smb2_tree[j]->session->transport); + } + } + } + +} + + +/* + compare NTSTATUS, using checking ignored patterns +*/ +static bool compare_status(NTSTATUS status1, NTSTATUS status2) +{ + char *s; + + if (NT_STATUS_EQUAL(status1, status2)) return true; + + /* one code being an error and the other OK is always an error */ + if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) { + current_op.mismatch = nt_errstr(status1); + return false; + } + + /* if we are ignoring one of the status codes then consider this a match */ + if (ignore_pattern(nt_errstr(status1)) || + ignore_pattern(nt_errstr(status2))) { + return true; + } + + /* also support ignore patterns of the form NT_STATUS_XX:NT_STATUS_YY + meaning that the first server returns NT_STATUS_XX and the 2nd + returns NT_STATUS_YY */ + s = talloc_asprintf(current_op.mem_ctx, "%s:%s", + nt_errstr(status1), + nt_errstr(status2)); + if (ignore_pattern(s)) { + return true; + } + + current_op.mismatch = nt_errstr(status1); + return false; +} + +/* + check for pending packets on all connections +*/ +static void check_pending(void) +{ + int i, j; + + msleep(20); + + for (j=0;jsession->transport); + } + } +} + +/* + check that the same oplock breaks have been received by all instances +*/ +static bool check_oplocks(const char *call) +{ + int i, j; + int tries = 0; + + if (!options.use_oplocks || options.smb2) { + /* no smb2 oplocks in gentest yet */ + return true; + } + +again: + check_pending(); + + for (j=0;jtree; \ + struct treetype *tree = servers[i].treefield[instance]; \ status[i] = call; \ } \ current_op.status = status[0]; \ for (i=1;idacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ + printf("Mismatch in %s\n", #field); \ + return false; \ + } \ +} while(0) + +#define CHECK_ATTRIB(field) do { \ + if (!options.mask_indexing) { \ + CHECK_EQUAL(field); \ + } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)parm[0].field, (int)parm[1].field); \ return false; \ @@ -1023,10 +1468,12 @@ again: #define CHECK_WSTR_EQUAL(field) do { \ if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \ + current_op.mismatch = #field; \ printf("%s is NULL!\n", #field); \ return false; \ } \ if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - %s %s\n", #field, \ parm[0].field.s, parm[1].field.s); \ return false; \ @@ -1035,7 +1482,10 @@ again: } while(0) #define CHECK_BLOB_EQUAL(field) do { \ - if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \ + if (((parm[0].field.data == NULL && parm[1].field.data != NULL) || \ + (parm[1].field.data == NULL && parm[0].field.data != NULL) || \ + (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0)) && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s\n", #field); \ return false; \ } \ @@ -1045,6 +1495,7 @@ again: #define CHECK_TIMES_EQUAL(field) do { \ if (labs(parm[0].field - parm[1].field) > time_skew() && \ !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)parm[0].field, (int)parm[1].field); \ return false; \ @@ -1055,6 +1506,7 @@ again: if (labs(nt_time_to_unix(parm[0].field) - \ nt_time_to_unix(parm[1].field)) > time_skew() && \ !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)nt_time_to_unix(parm[0].field), \ (int)nt_time_to_unix(parm[1].field)); \ @@ -1062,89 +1514,305 @@ again: } \ } while(0) + /* - generate openx operations + compare returned fileinfo structures */ -static bool handler_openx(int instance) +static bool cmp_fileinfo(int instance, + union smb_fileinfo parm[NSERVERS], + NTSTATUS status[NSERVERS]) { - union smb_open parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - parm[0].openx.level = RAW_OPEN_OPENX; - parm[0].openx.in.flags = gen_openx_flags(); - parm[0].openx.in.open_mode = gen_openx_mode(); - parm[0].openx.in.search_attrs = gen_attrib(); - parm[0].openx.in.file_attrs = gen_attrib(); - parm[0].openx.in.write_time = gen_timet(); - parm[0].openx.in.open_func = gen_openx_func(); - parm[0].openx.in.size = gen_io_count(); - parm[0].openx.in.timeout = gen_timeout(); - parm[0].openx.in.fname = gen_fname_open(instance); + int i; + enum smb_fileinfo_level level = parm[0].generic.level; - if (!options.use_oplocks) { - /* mask out oplocks */ - parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK| - OPENX_FLAGS_REQUEST_BATCH_OPLOCK); + if (level == RAW_FILEINFO_ALL_INFORMATION && + options.smb2) { + level = RAW_FILEINFO_SMB2_ALL_INFORMATION; } - - GEN_COPY_PARM; - GEN_CALL(smb_raw_open(tree, current_op.mem_ctx, &parm[i])); - CHECK_EQUAL(openx.out.attrib); - CHECK_EQUAL(openx.out.size); - CHECK_EQUAL(openx.out.access); - CHECK_EQUAL(openx.out.ftype); - CHECK_EQUAL(openx.out.devstate); - CHECK_EQUAL(openx.out.action); - CHECK_EQUAL(openx.out.access_mask); - CHECK_EQUAL(openx.out.unknown); - CHECK_TIMES_EQUAL(openx.out.write_time); + switch (level) { + case RAW_FILEINFO_GENERIC: + return false; - /* open creates a new file handle */ - ADD_HANDLE(parm[0].openx.in.fname, openx.out.file.fnum); + case RAW_FILEINFO_GETATTR: + CHECK_ATTRIB(getattr.out.attrib); + CHECK_EQUAL(getattr.out.size); + CHECK_TIMES_EQUAL(getattr.out.write_time); + break; - return true; -} + case RAW_FILEINFO_GETATTRE: + CHECK_TIMES_EQUAL(getattre.out.create_time); + CHECK_TIMES_EQUAL(getattre.out.access_time); + CHECK_TIMES_EQUAL(getattre.out.write_time); + CHECK_EQUAL(getattre.out.size); + CHECK_EQUAL(getattre.out.alloc_size); + CHECK_ATTRIB(getattre.out.attrib); + break; + case RAW_FILEINFO_STANDARD: + CHECK_TIMES_EQUAL(standard.out.create_time); + CHECK_TIMES_EQUAL(standard.out.access_time); + CHECK_TIMES_EQUAL(standard.out.write_time); + CHECK_EQUAL(standard.out.size); + CHECK_EQUAL(standard.out.alloc_size); + CHECK_ATTRIB(standard.out.attrib); + break; -/* - generate open operations -*/ -static bool handler_open(int instance) -{ - union smb_open parm[NSERVERS]; - NTSTATUS status[NSERVERS]; + case RAW_FILEINFO_EA_SIZE: + CHECK_TIMES_EQUAL(ea_size.out.create_time); + CHECK_TIMES_EQUAL(ea_size.out.access_time); + CHECK_TIMES_EQUAL(ea_size.out.write_time); + CHECK_EQUAL(ea_size.out.size); + CHECK_EQUAL(ea_size.out.alloc_size); + CHECK_ATTRIB(ea_size.out.attrib); + CHECK_EQUAL(ea_size.out.ea_size); + break; - parm[0].openold.level = RAW_OPEN_OPEN; - parm[0].openold.in.open_mode = gen_bits_mask2(0xF, 0xFFFF); - parm[0].openold.in.search_attrs = gen_attrib(); - parm[0].openold.in.fname = gen_fname_open(instance); + case RAW_FILEINFO_ALL_EAS: + CHECK_EQUAL(all_eas.out.num_eas); + for (i=0;igeneric.level = levels[i].level; -} - -/* - compare returned fileinfo structures -*/ -static bool cmp_fileinfo(int instance, - union smb_fileinfo parm[NSERVERS], - NTSTATUS status[NSERVERS]) -{ - int i; - switch (parm[0].generic.level) { - case RAW_FILEINFO_GENERIC: - return false; - - case RAW_FILEINFO_GETATTR: - CHECK_EQUAL(getattr.out.attrib); - CHECK_EQUAL(getattr.out.size); - CHECK_TIMES_EQUAL(getattr.out.write_time); + switch (info->generic.level) { + case RAW_SFILEINFO_SETATTR: + info->setattr.in.attrib = gen_attrib(); + info->setattr.in.write_time = gen_timet(); break; - - case RAW_FILEINFO_GETATTRE: - CHECK_TIMES_EQUAL(getattre.out.create_time); - CHECK_TIMES_EQUAL(getattre.out.access_time); - CHECK_TIMES_EQUAL(getattre.out.write_time); - CHECK_EQUAL(getattre.out.size); - CHECK_EQUAL(getattre.out.alloc_size); - CHECK_EQUAL(getattre.out.attrib); + case RAW_SFILEINFO_SETATTRE: + info->setattre.in.create_time = gen_timet(); + info->setattre.in.access_time = gen_timet(); + info->setattre.in.write_time = gen_timet(); break; - - case RAW_FILEINFO_STANDARD: - CHECK_TIMES_EQUAL(standard.out.create_time); - CHECK_TIMES_EQUAL(standard.out.access_time); - CHECK_TIMES_EQUAL(standard.out.write_time); - CHECK_EQUAL(standard.out.size); - CHECK_EQUAL(standard.out.alloc_size); - CHECK_EQUAL(standard.out.attrib); + case RAW_SFILEINFO_STANDARD: + info->standard.in.create_time = gen_timet(); + info->standard.in.access_time = gen_timet(); + info->standard.in.write_time = gen_timet(); break; - - case RAW_FILEINFO_EA_SIZE: - CHECK_TIMES_EQUAL(ea_size.out.create_time); - CHECK_TIMES_EQUAL(ea_size.out.access_time); - CHECK_TIMES_EQUAL(ea_size.out.write_time); - CHECK_EQUAL(ea_size.out.size); - CHECK_EQUAL(ea_size.out.alloc_size); - CHECK_EQUAL(ea_size.out.attrib); - CHECK_EQUAL(ea_size.out.ea_size); + case RAW_SFILEINFO_EA_SET: { + static struct ea_struct ea; + info->ea_set.in.num_eas = 1; + info->ea_set.in.eas = &ea; + info->ea_set.in.eas[0] = gen_ea_struct(); + } break; - - case RAW_FILEINFO_ALL_EAS: - CHECK_EQUAL(all_eas.out.num_eas); - for (i=0;ibasic_info.in.create_time = gen_nttime(); + info->basic_info.in.access_time = gen_nttime(); + info->basic_info.in.write_time = gen_nttime(); + info->basic_info.in.change_time = gen_nttime(); + info->basic_info.in.attrib = gen_attrib(); break; - - case RAW_FILEINFO_IS_NAME_VALID: + case RAW_SFILEINFO_DISPOSITION_INFO: + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + info->disposition_info.in.delete_on_close = gen_bool(); break; - - case RAW_FILEINFO_BASIC_INFO: - case RAW_FILEINFO_BASIC_INFORMATION: - CHECK_NTTIMES_EQUAL(basic_info.out.create_time); - CHECK_NTTIMES_EQUAL(basic_info.out.access_time); - CHECK_NTTIMES_EQUAL(basic_info.out.write_time); - CHECK_NTTIMES_EQUAL(basic_info.out.change_time); - CHECK_EQUAL(basic_info.out.attrib); + case RAW_SFILEINFO_ALLOCATION_INFO: + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + info->allocation_info.in.alloc_size = gen_alloc_size(); break; - - case RAW_FILEINFO_STANDARD_INFO: - case RAW_FILEINFO_STANDARD_INFORMATION: - CHECK_EQUAL(standard_info.out.alloc_size); - CHECK_EQUAL(standard_info.out.size); - CHECK_EQUAL(standard_info.out.nlink); - CHECK_EQUAL(standard_info.out.delete_pending); - CHECK_EQUAL(standard_info.out.directory); + case RAW_SFILEINFO_END_OF_FILE_INFO: + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + info->end_of_file_info.in.size = gen_offset(); break; - - case RAW_FILEINFO_EA_INFO: - case RAW_FILEINFO_EA_INFORMATION: - CHECK_EQUAL(ea_info.out.ea_size); + case RAW_SFILEINFO_RENAME_INFORMATION: + case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: + info->rename_information.in.overwrite = gen_bool(); + info->rename_information.in.root_fid = gen_root_fid(instance); + info->rename_information.in.new_name = gen_fname_open(instance); break; - - case RAW_FILEINFO_NAME_INFO: - case RAW_FILEINFO_NAME_INFORMATION: - CHECK_WSTR_EQUAL(name_info.out.fname); + case RAW_SFILEINFO_POSITION_INFORMATION: + info->position_information.in.position = gen_offset(); + break; + case RAW_SFILEINFO_MODE_INFORMATION: + info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); + break; + case RAW_SFILEINFO_FULL_EA_INFORMATION: + info->full_ea_information.in.eas = gen_ea_list(); + break; + case RAW_SFILEINFO_GENERIC: + case RAW_SFILEINFO_SEC_DESC: + case RAW_SFILEINFO_UNIX_BASIC: + case RAW_SFILEINFO_UNIX_LINK: + case RAW_SFILEINFO_UNIX_HLINK: + case RAW_SFILEINFO_1023: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_1039: + case RAW_SFILEINFO_1040: + case RAW_SFILEINFO_UNIX_INFO2: + /* Untested */ break; + } +} +#endif - case RAW_FILEINFO_ALL_INFO: - case RAW_FILEINFO_ALL_INFORMATION: - CHECK_NTTIMES_EQUAL(all_info.out.create_time); - CHECK_NTTIMES_EQUAL(all_info.out.access_time); - CHECK_NTTIMES_EQUAL(all_info.out.write_time); - CHECK_NTTIMES_EQUAL(all_info.out.change_time); - CHECK_EQUAL(all_info.out.attrib); - CHECK_EQUAL(all_info.out.alloc_size); - CHECK_EQUAL(all_info.out.size); - CHECK_EQUAL(all_info.out.nlink); - CHECK_EQUAL(all_info.out.delete_pending); - CHECK_EQUAL(all_info.out.directory); - CHECK_EQUAL(all_info.out.ea_size); - CHECK_WSTR_EQUAL(all_info.out.fname); +/* + generate a fileinfo query structure +*/ +static void gen_setfileinfo(int instance, union smb_setfileinfo *info) +{ + int i; + #undef LVL + #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v} + struct levels { + enum smb_setfileinfo_level level; + const char *name; + }; + struct levels smb_levels[] = { + LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), + LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), + LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION), + LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), + LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION), + LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), + LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION), + LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036), + LVL(1041), LVL(1042), LVL(1043), LVL(1044), + }; + struct levels smb2_levels[] = { + LVL(BASIC_INFORMATION), + LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), + LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION), + LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), + LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION), + LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036), + LVL(1041), LVL(1042), LVL(1043), LVL(1044), + }; + struct levels *levels = options.smb2?smb2_levels:smb_levels; + uint32_t num_levels = options.smb2?ARRAY_SIZE(smb2_levels):ARRAY_SIZE(smb_levels); + + do { + i = gen_int_range(0, num_levels-1); + } while (ignore_pattern(levels[i].name)); + + ZERO_STRUCTP(info); + info->generic.level = levels[i].level; + + switch (info->generic.level) { + case RAW_SFILEINFO_SETATTR: + info->setattr.in.attrib = gen_attrib(); + info->setattr.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_SETATTRE: + info->setattre.in.create_time = gen_timet(); + info->setattre.in.access_time = gen_timet(); + info->setattre.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_STANDARD: + info->standard.in.create_time = gen_timet(); + info->standard.in.access_time = gen_timet(); + info->standard.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_EA_SET: { + static struct ea_struct ea; + info->ea_set.in.num_eas = 1; + info->ea_set.in.eas = &ea; + info->ea_set.in.eas[0] = gen_ea_struct(); + break; + } + case RAW_SFILEINFO_BASIC_INFO: + case RAW_SFILEINFO_BASIC_INFORMATION: + info->basic_info.in.create_time = gen_nttime(); + info->basic_info.in.access_time = gen_nttime(); + info->basic_info.in.write_time = gen_nttime(); + info->basic_info.in.change_time = gen_nttime(); + info->basic_info.in.attrib = gen_attrib(); + break; + case RAW_SFILEINFO_DISPOSITION_INFO: + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + info->disposition_info.in.delete_on_close = gen_bool(); + break; + case RAW_SFILEINFO_ALLOCATION_INFO: + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + info->allocation_info.in.alloc_size = gen_alloc_size(); + break; + case RAW_SFILEINFO_END_OF_FILE_INFO: + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + info->end_of_file_info.in.size = gen_offset(); + break; + case RAW_SFILEINFO_RENAME_INFORMATION: + case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: + info->rename_information.in.overwrite = gen_bool(); + info->rename_information.in.root_fid = gen_root_fid(instance); + info->rename_information.in.new_name = gen_fname_open(instance); + break; + case RAW_SFILEINFO_POSITION_INFORMATION: + info->position_information.in.position = gen_offset(); + break; + case RAW_SFILEINFO_MODE_INFORMATION: + info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); + break; + case RAW_SFILEINFO_FULL_EA_INFORMATION: + info->full_ea_information.in.eas = gen_ea_list(); break; - case RAW_FILEINFO_ALT_NAME_INFO: - case RAW_FILEINFO_ALT_NAME_INFORMATION: - CHECK_WSTR_EQUAL(alt_name_info.out.fname); + case RAW_SFILEINFO_GENERIC: + case RAW_SFILEINFO_SEC_DESC: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_UNIX_BASIC: + case RAW_SFILEINFO_UNIX_INFO2: + case RAW_SFILEINFO_UNIX_LINK: + case RAW_SFILEINFO_UNIX_HLINK: + /* Untested */ break; + } +} - case RAW_FILEINFO_STREAM_INFO: - case RAW_FILEINFO_STREAM_INFORMATION: - CHECK_EQUAL(stream_info.out.num_streams); - for (i=0;igeneric.level = levels[i].level; +} + +/* + generate qpathinfo operations +*/ +static bool handler_smb_qpathinfo(int instance) +{ + union smb_fileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.path = gen_fname_open(instance); + + gen_fileinfo_smb(instance, &parm[0]); + + GEN_COPY_PARM; + GEN_CALL_SMB(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i])); + + return cmp_fileinfo(instance, parm, status); +} + +/* + generate qfileinfo operations +*/ +static bool handler_smb_qfileinfo(int instance) +{ + union smb_fileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.fnum = gen_fnum(instance); + + gen_fileinfo_smb(instance, &parm[0]); + + GEN_COPY_PARM; + GEN_SET_FNUM_SMB(generic.in.file.fnum); + GEN_CALL_SMB(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i])); + + return cmp_fileinfo(instance, parm, status); +} + + +/* + generate setpathinfo operations +*/ +static bool handler_smb_spathinfo(int instance) +{ + union smb_setfileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + gen_setfileinfo(instance, &parm[0]); + parm[0].generic.in.file.path = gen_fname_open(instance); + + GEN_COPY_PARM; + + /* a special case for the fid in a RENAME */ + if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION && + parm[0].rename_information.in.root_fid != 0) { + GEN_SET_FNUM_SMB(rename_information.in.root_fid); + } + + GEN_CALL_SMB(smb_raw_setpathinfo(tree, &parm[i])); + + return true; +} + + +/* + generate setfileinfo operations +*/ +static bool handler_smb_sfileinfo(int instance) +{ + union smb_setfileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.fnum = gen_fnum(instance); + + gen_setfileinfo(instance, &parm[0]); + + GEN_COPY_PARM; + GEN_SET_FNUM_SMB(generic.in.file.fnum); + GEN_CALL_SMB(smb_raw_setfileinfo(tree, &parm[i])); + + return true; +} + + +/* + this is called when a change notify reply comes in +*/ +static void async_notify_smb(struct smbcli_request *req) +{ + union smb_notify notify; + NTSTATUS status; + int i, j; + uint16_t tid; + struct smbcli_transport *transport = req->transport; + + tid = SVAL(req->in.hdr, HDR_TID); + + notify.nttrans.level = RAW_NOTIFY_NTTRANS; + status = smb_raw_changenotify_recv(req, current_op.mem_ctx, ¬ify); + if (NT_STATUS_IS_OK(status) && notify.nttrans.out.num_changes > 0) { + printf("notify tid=%d num_changes=%d action=%d name=%s\n", + tid, + notify.nttrans.out.num_changes, + notify.nttrans.out.changes[0].action, + notify.nttrans.out.changes[0].name.s); + } + + for (i=0;isession->transport && + tid == servers[i].smb_tree[j]->tid) { + notifies[i][j].notify_count++; + notifies[i][j].status = status; + notifies[i][j].notify = notify; + } } - break; + } +} - case RAW_FILEINFO_COMPRESSION_INFO: - case RAW_FILEINFO_COMPRESSION_INFORMATION: - CHECK_EQUAL(compression_info.out.compressed_size); - CHECK_EQUAL(compression_info.out.format); - CHECK_EQUAL(compression_info.out.unit_shift); - CHECK_EQUAL(compression_info.out.chunk_shift); - CHECK_EQUAL(compression_info.out.cluster_shift); - break; +/* + generate change notify operations +*/ +static bool handler_smb_notify(int instance) +{ + union smb_notify parm[NSERVERS]; + int n; - case RAW_FILEINFO_INTERNAL_INFORMATION: - CHECK_EQUAL(internal_information.out.file_id); - break; + ZERO_STRUCT(parm[0]); + parm[0].nttrans.level = RAW_NOTIFY_NTTRANS; + parm[0].nttrans.in.buffer_size = gen_io_count(); + parm[0].nttrans.in.completion_filter = gen_bits_mask(0xFF); + parm[0].nttrans.in.file.fnum = gen_fnum(instance); + parm[0].nttrans.in.recursive = gen_bool(); - case RAW_FILEINFO_ACCESS_INFORMATION: - CHECK_EQUAL(access_information.out.access_flags); - break; + GEN_COPY_PARM; + GEN_SET_FNUM_SMB(nttrans.in.file.fnum); - case RAW_FILEINFO_POSITION_INFORMATION: - CHECK_EQUAL(position_information.out.position); - break; + for (n=0;nasync.fn = async_notify_smb; + } - case RAW_FILEINFO_MODE_INFORMATION: - CHECK_EQUAL(mode_information.out.mode); - break; + return true; +} - case RAW_FILEINFO_ALIGNMENT_INFORMATION: - CHECK_EQUAL(alignment_information.out.alignment_requirement); - break; - case RAW_FILEINFO_NETWORK_OPEN_INFORMATION: - CHECK_NTTIMES_EQUAL(network_open_information.out.create_time); - CHECK_NTTIMES_EQUAL(network_open_information.out.access_time); - CHECK_NTTIMES_EQUAL(network_open_information.out.write_time); - CHECK_NTTIMES_EQUAL(network_open_information.out.change_time); - CHECK_EQUAL(network_open_information.out.alloc_size); - CHECK_EQUAL(network_open_information.out.size); - CHECK_EQUAL(network_open_information.out.attrib); - break; +/* + generate ntcreatex operations +*/ +static bool handler_smb2_create(int instance) +{ + struct smb2_create parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + ZERO_STRUCT(parm[0]); + parm[0].in.security_flags = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF); + parm[0].in.oplock_level = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF); + parm[0].in.impersonation_level = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF); + parm[0].in.create_flags = gen_reserved64(); + parm[0].in.reserved = gen_reserved64(); + parm[0].in.desired_access = gen_access_mask(); + parm[0].in.file_attributes = gen_attrib(); + parm[0].in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF); + parm[0].in.create_disposition = gen_open_disp(); + parm[0].in.create_options = gen_create_options(); + parm[0].in.fname = gen_fname_open(instance); + parm[0].in.eas = gen_ea_list(); + parm[0].in.alloc_size = gen_alloc_size(); + parm[0].in.durable_open = gen_bool(); + parm[0].in.query_maximal_access = gen_bool(); + parm[0].in.timewarp = gen_timewarp(); + parm[0].in.query_on_disk_id = gen_bool(); + parm[0].in.sec_desc = gen_sec_desc(); + + if (!options.use_oplocks) { + /* mask out oplocks */ + parm[0].in.oplock_level = 0; + } + + if (options.valid) { + parm[0].in.security_flags &= 3; + parm[0].in.oplock_level &= 9; + parm[0].in.impersonation_level &= 3; + } + + GEN_COPY_PARM; + GEN_CALL_SMB2(smb2_create(tree, current_op.mem_ctx, &parm[i])); + + CHECK_EQUAL(out.oplock_level); + CHECK_EQUAL(out.reserved); + CHECK_EQUAL(out.create_action); + CHECK_NTTIMES_EQUAL(out.create_time); + CHECK_NTTIMES_EQUAL(out.access_time); + CHECK_NTTIMES_EQUAL(out.write_time); + CHECK_NTTIMES_EQUAL(out.change_time); + CHECK_EQUAL(out.alloc_size); + CHECK_EQUAL(out.size); + CHECK_ATTRIB(out.file_attr); + CHECK_EQUAL(out.reserved2); + CHECK_EQUAL(out.maximal_access); + + /* ntcreatex creates a new file handle */ + ADD_HANDLE_SMB2(parm[0].in.fname, out.file.handle); + + return true; +} + +/* + generate close operations +*/ +static bool handler_smb2_close(int instance) +{ + struct smb2_close parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + ZERO_STRUCT(parm[0]); + parm[0].in.file.handle.data[0] = gen_fnum_close(instance); + parm[0].in.flags = gen_bits_mask2(0x1, 0xFFFF); + + GEN_COPY_PARM; + GEN_SET_FNUM_SMB2(in.file.handle); + GEN_CALL_SMB2(smb2_close(tree, &parm[i])); + + CHECK_EQUAL(out.flags); + CHECK_EQUAL(out._pad); + CHECK_NTTIMES_EQUAL(out.create_time); + CHECK_NTTIMES_EQUAL(out.access_time); + CHECK_NTTIMES_EQUAL(out.write_time); + CHECK_NTTIMES_EQUAL(out.change_time); + CHECK_EQUAL(out.alloc_size); + CHECK_EQUAL(out.size); + CHECK_ATTRIB(out.file_attr); + + REMOVE_HANDLE_SMB2(in.file.handle); + + return true; +} + +/* + generate read operations +*/ +static bool handler_smb2_read(int instance) +{ + struct smb2_read parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].in.file.handle.data[0] = gen_fnum(instance); + parm[0].in.reserved = gen_reserved8(); + parm[0].in.length = gen_io_count(); + parm[0].in.offset = gen_offset(); + parm[0].in.min_count = gen_io_count(); + parm[0].in.channel = gen_bits_mask2(0x0, 0xFFFFFFFF); + parm[0].in.remaining = gen_bits_mask2(0x0, 0xFFFFFFFF); + parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF); + parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF); + + GEN_COPY_PARM; + GEN_SET_FNUM_SMB2(in.file.handle); + GEN_CALL_SMB2(smb2_read(tree, current_op.mem_ctx, &parm[i])); + + CHECK_EQUAL(out.remaining); + CHECK_EQUAL(out.reserved); + CHECK_EQUAL(out.data.length); + + return true; +} - case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION: - CHECK_EQUAL(attribute_tag_information.out.attrib); - CHECK_EQUAL(attribute_tag_information.out.reparse_tag); - break; +/* + generate write operations +*/ +static bool handler_smb2_write(int instance) +{ + struct smb2_write parm[NSERVERS]; + NTSTATUS status[NSERVERS]; - /* Unhandled levels */ + parm[0].in.file.handle.data[0] = gen_fnum(instance); + parm[0].in.offset = gen_offset(); + parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF); + parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF); + parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL, + gen_io_count()); - case RAW_FILEINFO_SEC_DESC: - case RAW_FILEINFO_EA_LIST: - case RAW_FILEINFO_UNIX_BASIC: - case RAW_FILEINFO_UNIX_LINK: - case RAW_FILEINFO_SMB2_ALL_EAS: - case RAW_FILEINFO_SMB2_ALL_INFORMATION: - break; - } + GEN_COPY_PARM; + GEN_SET_FNUM_SMB2(in.file.handle); + GEN_CALL_SMB2(smb2_write(tree, &parm[i])); + + CHECK_EQUAL(out._pad); + CHECK_EQUAL(out.nwritten); + CHECK_EQUAL(out.unknown1); return true; } /* - generate qpathinfo operations + generate lockingx operations */ -static bool handler_qpathinfo(int instance) +static bool handler_smb2_lock(int instance) { - union smb_fileinfo parm[NSERVERS]; + struct smb2_lock parm[NSERVERS]; NTSTATUS status[NSERVERS]; + int n; - parm[0].generic.in.file.path = gen_fname_open(instance); - - gen_fileinfo(instance, &parm[0]); + parm[0].level = RAW_LOCK_LOCKX; + parm[0].in.file.handle.data[0] = gen_fnum(instance); + parm[0].in.lock_count = gen_lock_count(); + parm[0].in.reserved = gen_reserved32(); + + parm[0].in.locks = talloc_array(current_op.mem_ctx, + struct smb2_lock_element, + parm[0].in.lock_count); + for (n=0;nsession->transport)); + + return true; } + /* generate a fileinfo query structure */ -static void gen_setfileinfo(int instance, union smb_setfileinfo *info) +static void gen_fileinfo_smb2(int instance, union smb_fileinfo *info) { int i; - #undef LVL - #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v} + #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v} struct { - enum smb_setfileinfo_level level; + enum smb_fileinfo_level level; const char *name; } levels[] = { -#if 0 - /* disabled until win2003 can handle them ... */ - LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), - LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), -#endif - LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION), - LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), - LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION), - LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), - LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040) + LVL(BASIC_INFORMATION), + LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION), + LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION), + LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION), + LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION), + LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION), + LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC), }; do { i = gen_int_range(0, ARRAY_SIZE(levels)-1); } while (ignore_pattern(levels[i].name)); info->generic.level = levels[i].level; - - switch (info->generic.level) { - case RAW_SFILEINFO_SETATTR: - info->setattr.in.attrib = gen_attrib(); - info->setattr.in.write_time = gen_timet(); - break; - case RAW_SFILEINFO_SETATTRE: - info->setattre.in.create_time = gen_timet(); - info->setattre.in.access_time = gen_timet(); - info->setattre.in.write_time = gen_timet(); - break; - case RAW_SFILEINFO_STANDARD: - info->standard.in.create_time = gen_timet(); - info->standard.in.access_time = gen_timet(); - info->standard.in.write_time = gen_timet(); - break; - case RAW_SFILEINFO_EA_SET: { - static struct ea_struct ea; - info->ea_set.in.num_eas = 1; - info->ea_set.in.eas = &ea; - info->ea_set.in.eas[0] = gen_ea_struct(); - } - break; - case RAW_SFILEINFO_BASIC_INFO: - case RAW_SFILEINFO_BASIC_INFORMATION: - info->basic_info.in.create_time = gen_nttime(); - info->basic_info.in.access_time = gen_nttime(); - info->basic_info.in.write_time = gen_nttime(); - info->basic_info.in.change_time = gen_nttime(); - info->basic_info.in.attrib = gen_attrib(); - break; - case RAW_SFILEINFO_DISPOSITION_INFO: - case RAW_SFILEINFO_DISPOSITION_INFORMATION: - info->disposition_info.in.delete_on_close = gen_bool(); - break; - case RAW_SFILEINFO_ALLOCATION_INFO: - case RAW_SFILEINFO_ALLOCATION_INFORMATION: - info->allocation_info.in.alloc_size = gen_alloc_size(); - break; - case RAW_SFILEINFO_END_OF_FILE_INFO: - case RAW_SFILEINFO_END_OF_FILE_INFORMATION: - info->end_of_file_info.in.size = gen_offset(); - break; - case RAW_SFILEINFO_RENAME_INFORMATION: - info->rename_information.in.overwrite = gen_bool(); - info->rename_information.in.root_fid = gen_root_fid(instance); - info->rename_information.in.new_name = gen_fname_open(instance); - break; - case RAW_SFILEINFO_POSITION_INFORMATION: - info->position_information.in.position = gen_offset(); - break; - case RAW_SFILEINFO_MODE_INFORMATION: - info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); - break; - case RAW_SFILEINFO_GENERIC: - case RAW_SFILEINFO_SEC_DESC: - case RAW_SFILEINFO_UNIX_BASIC: - case RAW_SFILEINFO_UNIX_LINK: - case RAW_SFILEINFO_UNIX_HLINK: - case RAW_SFILEINFO_1023: - case RAW_SFILEINFO_1025: - case RAW_SFILEINFO_1029: - case RAW_SFILEINFO_1032: - case RAW_SFILEINFO_1039: - case RAW_SFILEINFO_1040: - /* Untested */ - break; - } } /* - generate setpathinfo operations + generate qfileinfo operations */ -static bool handler_spathinfo(int instance) +static bool handler_smb2_qfileinfo(int instance) { - union smb_setfileinfo parm[NSERVERS]; + union smb_fileinfo parm[NSERVERS]; NTSTATUS status[NSERVERS]; - parm[0].generic.in.file.path = gen_fname_open(instance); + parm[0].generic.in.file.handle.data[0] = gen_fnum(instance); - gen_setfileinfo(instance, &parm[0]); + gen_fileinfo_smb2(instance, &parm[0]); GEN_COPY_PARM; + GEN_SET_FNUM_SMB2(generic.in.file.handle); + GEN_CALL_SMB2(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i])); - /* a special case for the fid in a RENAME */ - if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION && - parm[0].rename_information.in.root_fid != 0) { - GEN_SET_FNUM(rename_information.in.root_fid); - } - - GEN_CALL(smb_raw_setpathinfo(tree, &parm[i])); - - return true; + return cmp_fileinfo(instance, parm, status); } /* generate setfileinfo operations */ -static bool handler_sfileinfo(int instance) +static bool handler_smb2_sfileinfo(int instance) { union smb_setfileinfo parm[NSERVERS]; NTSTATUS status[NSERVERS]; - parm[0].generic.in.file.fnum = gen_fnum(instance); - gen_setfileinfo(instance, &parm[0]); + parm[0].generic.in.file.fnum = gen_fnum(instance); GEN_COPY_PARM; - GEN_SET_FNUM(generic.in.file.fnum); - GEN_CALL(smb_raw_setfileinfo(tree, &parm[i])); - - return true; -} - - -/* - generate change notify operations -*/ -static bool handler_notify(int instance) -{ - union smb_notify parm[NSERVERS]; - int n; - - ZERO_STRUCT(parm[0]); - parm[0].nttrans.level = RAW_NOTIFY_NTTRANS; - parm[0].nttrans.in.buffer_size = gen_io_count(); - parm[0].nttrans.in.completion_filter = gen_bits_mask(0xFF); - parm[0].nttrans.in.file.fnum = gen_fnum(instance); - parm[0].nttrans.in.recursive = gen_bool(); - - GEN_COPY_PARM; - GEN_SET_FNUM(nttrans.in.file.fnum); - - for (n=0;ntree, &parm[n]); - req->async.fn = async_notify; - } + GEN_SET_FNUM_SMB2(generic.in.file.handle); + GEN_CALL_SMB2(smb2_setinfo_file(tree, &parm[i])); return true; } @@ -1857,15 +2788,30 @@ static bool handler_notify(int instance) static void wipe_files(void) { int i; + NTSTATUS status; + + if (options.skip_cleanup) { + return; + } + for (i=0;itree, "\\gentest"); + int n; + if (options.smb2) { + n = smb2_deltree(servers[i].smb2_tree[0], "gentest"); + } else { + n = smbcli_deltree(servers[i].smb_tree[0], "gentest"); + } if (n == -1) { printf("Failed to wipe tree on server %d\n", i); exit(1); } - if (NT_STATUS_IS_ERR(smbcli_mkdir(servers[i].cli[0]->tree, "\\gentest"))) { - printf("Failed to create \\gentest - %s\n", - smbcli_errstr(servers[i].cli[0]->tree)); + if (options.smb2) { + status = smb2_util_mkdir(servers[i].smb2_tree[0], "gentest"); + } else { + status = smbcli_mkdir(servers[i].smb_tree[0], "gentest"); + } + if (NT_STATUS_IS_ERR(status)) { + printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status)); exit(1); } if (n > 0) { @@ -1903,27 +2849,39 @@ static void dump_seeds(void) static struct { const char *name; bool (*handler)(int instance); + bool smb2; int count, success_count; } gen_ops[] = { - {"OPEN", handler_open}, - {"OPENX", handler_openx}, - {"NTCREATEX", handler_ntcreatex}, - {"CLOSE", handler_close}, - {"UNLINK", handler_unlink}, - {"MKDIR", handler_mkdir}, - {"RMDIR", handler_rmdir}, - {"RENAME", handler_rename}, - {"NTRENAME", handler_ntrename}, - {"READX", handler_readx}, - {"WRITEX", handler_writex}, - {"CHKPATH", handler_chkpath}, - {"LOCKINGX", handler_lockingx}, - {"QPATHINFO", handler_qpathinfo}, - {"QFILEINFO", handler_qfileinfo}, - {"SPATHINFO", handler_spathinfo}, - {"SFILEINFO", handler_sfileinfo}, - {"NOTIFY", handler_notify}, - {"SEEK", handler_seek}, + {"CREATE", handler_smb2_create, true}, + {"CLOSE", handler_smb2_close, true}, + {"READ", handler_smb2_read, true}, + {"WRITE", handler_smb2_write, true}, + {"LOCK", handler_smb2_lock, true}, + {"FLUSH", handler_smb2_flush, true}, + {"ECHO", handler_smb2_echo, true}, + {"QFILEINFO", handler_smb2_qfileinfo, true}, + {"SFILEINFO", handler_smb2_sfileinfo, true}, + + {"OPEN", handler_smb_open, false}, + {"OPENX", handler_smb_openx, false}, + {"NTCREATEX", handler_smb_ntcreatex, false}, + {"CLOSE", handler_smb_close, false}, + {"UNLINK", handler_smb_unlink, false}, + {"MKDIR", handler_smb_mkdir, false}, + {"RMDIR", handler_smb_rmdir, false}, + {"RENAME", handler_smb_rename, false}, + {"NTRENAME", handler_smb_ntrename, false}, + {"READX", handler_smb_readx, false}, + {"WRITEX", handler_smb_writex, false}, + {"CHKPATH", handler_smb_chkpath, false}, + {"SEEK", handler_smb_seek, false}, + {"LOCKINGX", handler_smb_lockingx, false}, + {"QPATHINFO", handler_smb_qpathinfo, false}, + {"QFILEINFO", handler_smb_qfileinfo, false}, + {"SPATHINFO", handler_smb_spathinfo, false}, + {"SFILEINFO", handler_smb_sfileinfo, false}, + {"NOTIFY", handler_smb_notify, false}, + {"SEEK", handler_smb_seek, false}, }; @@ -1931,11 +2889,11 @@ static struct { run the test with the current set of op_parms parameters return the number of operations that completed successfully */ -static int run_test(struct loadparm_context *lp_ctx) +static int run_test(struct tevent_context *ev, struct loadparm_context *lp_ctx) { int op, i; - if (!connect_servers(lp_ctx)) { + if (!connect_servers(ev, lp_ctx)) { printf("Failed to connect to servers\n"); exit(1); } @@ -1967,7 +2925,8 @@ static int run_test(struct loadparm_context *lp_ctx) /* generate a non-ignored operation */ do { which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1); - } while (ignore_pattern(gen_ops[which_op].name)); + } while (ignore_pattern(gen_ops[which_op].name) || + gen_ops[which_op].smb2 != options.smb2); DEBUG(3,("Generating op %s on instance %d\n", gen_ops[which_op].name, instance)); @@ -1976,12 +2935,11 @@ static int run_test(struct loadparm_context *lp_ctx) current_op.opnum = op; current_op.name = gen_ops[which_op].name; current_op.status = NT_STATUS_OK; + talloc_free(current_op.mem_ctx); current_op.mem_ctx = talloc_named(NULL, 0, "%s", current_op.name); ret = gen_ops[which_op].handler(instance); - talloc_free(current_op.mem_ctx); - gen_ops[which_op].count++; if (NT_STATUS_IS_OK(current_op.status)) { gen_ops[which_op].success_count++; @@ -2012,9 +2970,11 @@ static int run_test(struct loadparm_context *lp_ctx) perform a backtracking analysis of the minimal set of operations to generate an error */ -static void backtrack_analyze(struct loadparm_context *lp_ctx) +static void backtrack_analyze(struct tevent_context *ev, + struct loadparm_context *lp_ctx) { int chunk, ret; + const char *mismatch = current_op.mismatch; chunk = options.numops / 2; @@ -2033,7 +2993,7 @@ static void backtrack_analyze(struct loadparm_context *lp_ctx) } printf("Testing %d ops with %d-%d disabled\n", options.numops, base, max-1); - ret = run_test(lp_ctx); + ret = run_test(ev, lp_ctx); printf("Completed %d of %d ops\n", ret, options.numops); for (i=base;i 0); printf("Reduced to %d ops\n", options.numops); - ret = run_test(lp_ctx); + ret = run_test(ev, lp_ctx); if (ret != options.numops - 1) { printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops); } @@ -2074,7 +3038,8 @@ static void backtrack_analyze(struct loadparm_context *lp_ctx) /* start the main gentest process */ -static bool start_gentest(struct loadparm_context *lp_ctx) +static bool start_gentest(struct tevent_context *ev, + struct loadparm_context *lp_ctx) { int op; int ret; @@ -2088,7 +3053,7 @@ static bool start_gentest(struct loadparm_context *lp_ctx) /* generate the seeds - after this everything is deterministic */ if (options.use_preset_seeds) { int numops; - char **preset = file_lines_load(options.seeds_file, &numops, NULL); + char **preset = file_lines_load(options.seeds_file, &numops, 0, NULL); if (!preset) { printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno)); exit(1); @@ -2110,40 +3075,28 @@ static bool start_gentest(struct loadparm_context *lp_ctx) } } - ret = run_test(lp_ctx); + ret = run_test(ev, lp_ctx); if (ret != options.numops && options.analyze) { options.numops = ret+1; - backtrack_analyze(lp_ctx); + backtrack_analyze(ev, lp_ctx); } else if (options.analyze_always) { - backtrack_analyze(lp_ctx); + backtrack_analyze(ev, lp_ctx); } else if (options.analyze_continuous) { - while (run_test(lp_ctx) == options.numops) ; + while (run_test(ev, lp_ctx) == options.numops) ; } return ret == options.numops; } -static void usage(void) +static void usage(poptContext pc) { printf( "Usage:\n\ - gentest2 //server1/share1 //server2/share2 [options..]\n\ - options:\n\ - -U user%%pass (can be specified twice)\n\ - -s seed\n\ - -o numops\n\ - -a (show all ops)\n\ - -A backtrack to find minimal ops\n\ - -i FILE add a list of wildcard exclusions\n\ - -O enable oplocks\n\ - -S FILE set preset seeds file\n\ - -L use preset seeds\n\ - -F fast reconnect (just close files)\n\ - -C continuous analysis mode\n\ - -X analyse even when test OK\n\ + gentest //server1/share1 //server2/share2 [options..]\n\ "); + poptPrintUsage(pc, stdout, 0); } /** @@ -2176,105 +3129,115 @@ static bool split_unc_name(const char *unc, char **server, char **share) int opt; int i, username_count=0; bool ret; + char *ignore_file=NULL; + struct tevent_context *ev; struct loadparm_context *lp_ctx; + poptContext pc; + int argc_new; + char **argv_new; + enum {OPT_UNCLIST=1000}; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"smb2", 0, POPT_ARG_NONE, &options.smb2, 0, "use SMB2 protocol", NULL}, + {"seed", 0, POPT_ARG_INT, &options.seed, 0, "Seed to use for randomizer", NULL}, + {"num-ops", 0, POPT_ARG_INT, &options.numops, 0, "num ops", NULL}, + {"oplocks", 0, POPT_ARG_NONE, &options.use_oplocks,0, "use oplocks", NULL}, + {"showall", 0, POPT_ARG_NONE, &options.showall, 0, "display all operations", NULL}, + {"analyse", 0, POPT_ARG_NONE, &options.analyze, 0, "do backtrack analysis", NULL}, + {"analysealways", 0, POPT_ARG_NONE, &options.analyze_always, 0, "analysis always", NULL}, + {"analysecontinuous", 0, POPT_ARG_NONE, &options.analyze_continuous, 0, "analysis continuous", NULL}, + {"ignore", 0, POPT_ARG_STRING, &ignore_file, 0, "ignore from file", NULL}, + {"preset", 0, POPT_ARG_NONE, &options.use_preset_seeds, 0, "use preset seeds", NULL}, + {"fast", 0, POPT_ARG_NONE, &options.fast_reconnect, 0, "use fast reconnect", NULL}, + {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL}, + {"seedsfile", 0, POPT_ARG_STRING, &options.seeds_file, 0, "seed file", NULL}, + { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" }, + {"maskindexing", 0, POPT_ARG_NONE, &options.mask_indexing, 0, "mask out the indexed file attrib", NULL}, + {"noeas", 0, POPT_ARG_NONE, &options.no_eas, 0, "don't use extended attributes", NULL}, + {"noacls", 0, POPT_ARG_NONE, &options.no_acls, 0, "don't use ACLs", NULL}, + {"skip-cleanup", 0, POPT_ARG_NONE, &options.skip_cleanup, 0, "don't delete files at start", NULL}, + {"valid", 0, POPT_ARG_NONE, &options.valid, 0, "generate only valid fields", NULL}, + POPT_COMMON_SAMBA + POPT_COMMON_CONNECTION + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + { NULL } + }; - setlinebuf(stdout); - - setup_logging("gentest", DEBUG_STDOUT); - - if (argc < 3 || argv[1][0] == '-') { - usage(); - exit(1); - } - - setup_logging(argv[0], DEBUG_STDOUT); + memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle)); - for (i=0;i "); + lp_ctx = cmdline_lp_ctx; servers[0].credentials = cli_credentials_init(talloc_autofree_context()); servers[1].credentials = cli_credentials_init(talloc_autofree_context()); cli_credentials_guess(servers[0].credentials, lp_ctx); cli_credentials_guess(servers[1].credentials, lp_ctx); - options.seed = time(NULL); - options.numops = 1000; - options.max_open_handles = 20; - options.seeds_file = "gentest_seeds.dat"; - - while ((opt = getopt(argc, argv, "U:s:o:ad:i:AOhS:LFXC")) != EOF) { + while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { + case OPT_UNCLIST: + lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc)); + break; case 'U': if (username_count == 2) { - usage(); + usage(pc); exit(1); } - cli_credentials_parse_string(servers[username_count].credentials, - optarg, CRED_SPECIFIED); + cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED); username_count++; break; - case 'd': - DEBUGLEVEL = atoi(optarg); - setup_logging(NULL, DEBUG_STDOUT); - break; - case 's': - options.seed = atoi(optarg); - break; - case 'S': - options.seeds_file = optarg; - break; - case 'L': - options.use_preset_seeds = true; - break; - case 'F': - options.fast_reconnect = true; - break; - case 'o': - options.numops = atoi(optarg); - break; - case 'O': - options.use_oplocks = true; - break; - case 'a': - options.showall = true; - break; - case 'A': - options.analyze = true; - break; - case 'X': - options.analyze_always = true; - break; - case 'C': - options.analyze_continuous = true; - break; - case 'i': - options.ignore_patterns = file_lines_load(optarg, NULL, NULL); + } + } + + if (ignore_file) { + options.ignore_patterns = file_lines_load(ignore_file, NULL, 0, NULL); + } + + argv_new = discard_const_p(char *, poptGetArgs(pc)); + argc_new = argc; + for (i=0; i= 3)) { + usage(pc); + exit(1); + } + + setlinebuf(stdout); + + setup_logging("gentest", DEBUG_STDOUT); + + if (argc < 3 || argv[1][0] == '-') { + usage(pc); + exit(1); + } + + setup_logging(argv[0], DEBUG_STDOUT); + + for (i=0;i