From 4d39976dddf2adf6a0d659050c3a21a6e0ff8ab2 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 21 May 2008 22:12:20 +1000 Subject: fixed SMB2 locking - SMB2 locking is different in several ways from SMB locking. To fix it properly we will need a new generic mapping structure for locking, but for now do a best effort mapping - added locking to gentest_smb2 (This used to be commit ea6d9cf602302adafe0f9d5f5f90a9b26d1ead6f) --- source4/libcli/raw/interfaces.h | 28 ++++--- source4/libcli/smb2/lock.c | 24 ++++-- source4/ntvfs/ntvfs_generic.c | 62 +++++++++----- source4/smb_server/smb2/fileio.c | 30 +++++-- source4/smb_server/smb2/smb2_server.h | 2 +- source4/torture/gentest_smb2.c | 57 +++++++------ source4/torture/smb2/lock.c | 148 ++++++++++++++++++---------------- 7 files changed, 199 insertions(+), 152 deletions(-) diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h index 871bab01db..149b91916a 100644 --- a/source4/libcli/raw/interfaces.h +++ b/source4/libcli/raw/interfaces.h @@ -1866,13 +1866,12 @@ enum smb_lock_level { RAW_LOCK_SMB2_BREAK }; -/* the generic interface is defined to be equal to the lockingX interface */ -#define RAW_LOCK_GENERIC RAW_LOCK_LOCKX +#define RAW_LOCK_GENERIC RAW_LOCK_LOCKX /* union for lock() backend call */ union smb_lock { - /* SMBlockingX (and generic) interface */ + /* SMBlockingX and generic interface */ struct { enum smb_lock_level level; struct { @@ -1887,7 +1886,7 @@ union smb_lock { uint64_t count; } *locks; /* unlocks are first in the arrray */ } in; - } lockx, generic; + } generic, lockx; /* SMBlock and SMBunlock interface */ struct { @@ -1907,23 +1906,26 @@ union smb_lock { /* static body buffer 48 (0x30) bytes */ /* uint16_t buffer_code; 0x30 */ - uint16_t unknown1; /* must be 0x0001 */ - uint32_t unknown2; + uint16_t lock_count; + uint32_t reserved; /* struct smb2_handle handle; */ - uint64_t offset; - uint64_t count; - uint32_t unknown5; + struct smb2_lock_element { + uint64_t offset; + uint64_t length; +/* these flags are the same as the SMB2 lock flags */ #define SMB2_LOCK_FLAG_NONE 0x00000000 #define SMB2_LOCK_FLAG_SHARED 0x00000001 -#define SMB2_LOCK_FLAG_EXCLUSIV 0x00000002 +#define SMB2_LOCK_FLAG_EXCLUSIVE 0x00000002 #define SMB2_LOCK_FLAG_UNLOCK 0x00000004 -#define SMB2_LOCK_FLAG_NO_PENDING 0x00000010 - uint32_t flags; +#define SMB2_LOCK_FLAG_FAIL_IMMEDIATELY 0x00000010 + uint32_t flags; + uint32_t reserved; + } *locks; } in; struct { /* static body buffer 4 (0x04) bytes */ /* uint16_t buffer_code; 0x04 */ - uint16_t unknown1; + uint16_t reserved; } out; } smb2; diff --git a/source4/libcli/smb2/lock.c b/source4/libcli/smb2/lock.c index d71a337d56..62c6e5dba7 100644 --- a/source4/libcli/smb2/lock.c +++ b/source4/libcli/smb2/lock.c @@ -29,17 +29,25 @@ struct smb2_request *smb2_lock_send(struct smb2_tree *tree, struct smb2_lock *io) { struct smb2_request *req; + int i; - req = smb2_request_init_tree(tree, SMB2_OP_LOCK, 0x30, false, 0); + req = smb2_request_init_tree(tree, SMB2_OP_LOCK, + 24 + io->in.lock_count*24, false, 0); if (req == NULL) return NULL; - SSVAL(req->out.body, 0x02, io->in.unknown1); - SIVAL(req->out.body, 0x04, io->in.unknown2); + /* this is quite bizarre - the spec says we must lie about the length! */ + SSVAL(req->out.body, 0, 0x30); + + SSVAL(req->out.body, 0x02, io->in.lock_count); + SIVAL(req->out.body, 0x04, io->in.reserved); smb2_push_handle(req->out.body+0x08, &io->in.file.handle); - SBVAL(req->out.body, 0x18, io->in.offset); - SBVAL(req->out.body, 0x20, io->in.count); - SIVAL(req->out.body, 0x24, io->in.unknown5); - SIVAL(req->out.body, 0x28, io->in.flags); + + for (i=0;iin.lock_count;i++) { + SBVAL(req->out.body, 0x18 + i*24, io->in.locks[i].offset); + SBVAL(req->out.body, 0x20 + i*24, io->in.locks[i].length); + SIVAL(req->out.body, 0x28 + i*24, io->in.locks[i].flags); + SIVAL(req->out.body, 0x2C + i*24, io->in.locks[i].reserved); + } smb2_transport_send(req); @@ -59,7 +67,7 @@ NTSTATUS smb2_lock_recv(struct smb2_request *req, struct smb2_lock *io) SMB2_CHECK_PACKET_RECV(req, 0x04, false); - io->out.unknown1 = SVAL(req->in.body, 0x02); + io->out.reserved = SVAL(req->in.body, 0x02); return smb2_request_destroy(req); } diff --git a/source4/ntvfs/ntvfs_generic.c b/source4/ntvfs/ntvfs_generic.c index 3653ad82c1..a706e621c9 100644 --- a/source4/ntvfs/ntvfs_generic.c +++ b/source4/ntvfs/ntvfs_generic.c @@ -1011,38 +1011,56 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs, locks->count = lck->unlock.in.count; break; - case RAW_LOCK_SMB2: - if (lck->smb2.in.unknown1 != 1) { + case RAW_LOCK_SMB2: { + /* this is only approximate! We need to change the + generic structure to fix this properly */ + int i; + if (lck->smb2.in.lock_count < 1) { return NT_STATUS_INVALID_PARAMETER; } lck2->generic.level = RAW_LOCK_GENERIC; lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs; - if (lck->smb2.in.flags & SMB2_LOCK_FLAG_EXCLUSIV) { - lck2->generic.in.mode = 0; - } else { - lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK; + lck2->generic.in.timeout = UINT32_MAX; + lck2->generic.in.mode = 0; + lck2->generic.in.lock_cnt = 0; + lck2->generic.in.ulock_cnt = 0; + lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, + lck->smb2.in.lock_count); + if (lck2->generic.in.locks == NULL) { + return NT_STATUS_NO_MEMORY; } - if (lck->smb2.in.flags & SMB2_LOCK_FLAG_NO_PENDING) { - lck2->generic.in.timeout = 0; - } else { - lck2->generic.in.timeout = UINT32_MAX; + for (i=0;ismb2.in.lock_count;i++) { + if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) { + int j = lck2->generic.in.ulock_cnt; + lck2->generic.in.ulock_cnt++; + lck2->generic.in.locks[j].pid = 0; + lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset; + lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length; + lck2->generic.in.locks[j].pid = 0; + } } - if (lck->smb2.in.flags & SMB2_LOCK_FLAG_UNLOCK) { - lck2->generic.in.ulock_cnt = 1; - lck2->generic.in.lock_cnt = 0; - } else { - lck2->generic.in.ulock_cnt = 0; - lck2->generic.in.lock_cnt = 1; + for (i=0;ismb2.in.lock_count;i++) { + if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) { + int j = lck2->generic.in.ulock_cnt + + lck2->generic.in.lock_cnt; + lck2->generic.in.lock_cnt++; + lck2->generic.in.locks[j].pid = 0; + lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset; + lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length; + lck2->generic.in.locks[j].pid = 0; + if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) { + lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK; + } + if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) { + lck2->generic.in.timeout = 0; + } + } } - lck2->generic.in.locks = locks; - locks->pid = 0; - locks->offset = lck->smb2.in.offset; - locks->count = lck->smb2.in.count; - /* initialize output value */ - lck->smb2.out.unknown1 = 0; + lck->smb2.out.reserved = 0; break; + } case RAW_LOCK_SMB2_BREAK: lck2->generic.level = RAW_LOCK_GENERIC; diff --git a/source4/smb_server/smb2/fileio.c b/source4/smb_server/smb2/fileio.c index b6b35d3d89..0feb259038 100644 --- a/source4/smb_server/smb2/fileio.c +++ b/source4/smb_server/smb2/fileio.c @@ -247,7 +247,7 @@ static void smb2srv_lock_send(struct ntvfs_request *ntvfs) SMB2SRV_CHECK_ASYNC_STATUS_ERR(io, union smb_lock); SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x04, false, 0)); - SSVAL(req->out.body, 0x02, io->smb2.out.unknown1); + SSVAL(req->out.body, 0x02, io->smb2.out.reserved); smb2srv_send_reply(req); } @@ -255,20 +255,34 @@ static void smb2srv_lock_send(struct ntvfs_request *ntvfs) void smb2srv_lock_recv(struct smb2srv_request *req) { union smb_lock *io; + int i; SMB2SRV_CHECK_BODY_SIZE(req, 0x30, false); SMB2SRV_TALLOC_IO_PTR(io, union smb_lock); SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_lock_send, NTVFS_ASYNC_STATE_MAY_ASYNC); io->smb2.level = RAW_LOCK_SMB2; - - io->smb2.in.unknown1 = SVAL(req->in.body, 0x02); - io->smb2.in.unknown2 = IVAL(req->in.body, 0x04); + io->smb2.in.lock_count = SVAL(req->in.body, 0x02); + io->smb2.in.reserved = IVAL(req->in.body, 0x04); io->smb2.in.file.ntvfs = smb2srv_pull_handle(req, req->in.body, 0x08); - io->smb2.in.offset = BVAL(req->in.body, 0x18); - io->smb2.in.count = BVAL(req->in.body, 0x20); - io->smb2.in.unknown5 = IVAL(req->in.body, 0x24); - io->smb2.in.flags = IVAL(req->in.body, 0x28); + if (req->in.body_size < 24 + 24*(uint64_t)io->smb2.in.lock_count) { + DEBUG(0,("%s: lock buffer too small\n", __location__)); + smb2srv_send_error(req, NT_STATUS_FOOBAR); + return; + } + io->smb2.in.locks = talloc_array(io, struct smb2_lock_element, + io->smb2.in.lock_count); + if (io->smb2.in.locks == NULL) { + smb2srv_send_error(req, NT_STATUS_NO_MEMORY); + return; + } + + for (i=0;ismb2.in.lock_count;i++) { + io->smb2.in.locks[i].offset = BVAL(req->in.body, 24 + i*24); + io->smb2.in.locks[i].length = BVAL(req->in.body, 32 + i*24); + io->smb2.in.locks[i].flags = IVAL(req->in.body, 40 + i*24); + io->smb2.in.locks[i].reserved = IVAL(req->in.body, 44 + i*24); + } SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs); SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, io)); diff --git a/source4/smb_server/smb2/smb2_server.h b/source4/smb_server/smb2/smb2_server.h index 2f347d3876..fc40a92efc 100644 --- a/source4/smb_server/smb2/smb2_server.h +++ b/source4/smb_server/smb2/smb2_server.h @@ -70,7 +70,7 @@ struct smbsrv_request; #include "smb_server/smb2/smb2_proto.h" -/* useful way of catching wct errors with file and line number */ +/* useful way of catching field size errors with file and line number */ #define SMB2SRV_CHECK_BODY_SIZE(req, size, dynamic) do { \ size_t is_size = req->in.body_size; \ uint16_t field_size = SVAL(req->in.body, 0); \ diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c index 9c4be90b3c..68e9e2c20b 100644 --- a/source4/torture/gentest_smb2.c +++ b/source4/torture/gentest_smb2.c @@ -530,13 +530,16 @@ static uint16_t gen_rename_flags(void) /* - return a lockingx lock mode + return a set of lock flags */ -static uint16_t gen_lock_mode(void) +static uint16_t gen_lock_flags(void) { if (gen_chance(5)) return gen_bits_mask(0xFFFF); if (gen_chance(20)) return gen_bits_mask(0x1F); - return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES); + if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK; + return gen_bits_mask(SMB2_LOCK_FLAG_SHARED | + SMB2_LOCK_FLAG_EXCLUSIVE | + SMB2_LOCK_FLAG_FAIL_IMMEDIATELY); } /* @@ -1135,46 +1138,41 @@ static bool handler_write(int instance) return true; } -#if 0 /* generate lockingx operations */ static bool handler_lock(int instance) { - union smb_lock parm[NSERVERS]; + struct smb2_lock parm[NSERVERS]; NTSTATUS status[NSERVERS]; - int n, nlocks; + int n; - parm[0].lockx.level = RAW_LOCK_LOCKX; - parm[0].lockx.in.file.fnum = gen_fnum(instance); - parm[0].lockx.in.mode = gen_lock_mode(); - parm[0].lockx.in.timeout = gen_timeout(); - do { - /* make sure we don't accidentially generate an oplock - break ack - otherwise the server can just block forever */ - parm[0].lockx.in.ulock_cnt = gen_lock_count(); - parm[0].lockx.in.lock_cnt = gen_lock_count(); - nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt; - } while (nlocks == 0); - - if (nlocks > 0) { - parm[0].lockx.in.locks = talloc_array(current_op.mem_ctx, - struct smb_lock_entry, - nlocks); - for (n=0;nlock_flags; + el[0].offset = 0; + el[0].length = ARRAY_SIZE(buf)/2; + el[0].reserved = 0x00000000; + el[0].flags = s->lock_flags; status = smb2_lock(tree, &lck); CHECK_STATUS(status, NT_STATUS_OK); - CHECK_VALUE(lck.out.unknown1, 0); + CHECK_VALUE(lck.out.reserved, 0); - lck.in.unknown1 = 0x0001; - lck.in.unknown2 = 0x00000000; + lck.in.lock_count = 0x0001; + lck.in.reserved = 0x00000000; lck.in.file.handle = h1; - lck.in.offset = ARRAY_SIZE(buf)/2; - lck.in.count = ARRAY_SIZE(buf)/2; - lck.in.unknown5 = 0x00000000; - lck.in.flags = s->lock_flags; + el[0].offset = ARRAY_SIZE(buf)/2; + el[0].length = ARRAY_SIZE(buf)/2; + el[0].reserved = 0x00000000; + el[0].flags = s->lock_flags; status = smb2_lock(tree, &lck); CHECK_STATUS(status, NT_STATUS_OK); - CHECK_VALUE(lck.out.unknown1, 0); + CHECK_VALUE(lck.out.reserved, 0); ZERO_STRUCT(cr); cr.in.oplock_level = 0; @@ -286,16 +292,16 @@ static bool test_lock_read_write(struct torture_context *torture, status = smb2_read(tree, tree, &rd); CHECK_STATUS(status, s->read_h2_status); - lck.in.unknown1 = 0x0001; - lck.in.unknown2 = 0x00000000; + lck.in.lock_count = 0x0001; + lck.in.reserved = 0x00000000; lck.in.file.handle = h1; - lck.in.offset = ARRAY_SIZE(buf)/2; - lck.in.count = ARRAY_SIZE(buf)/2; - lck.in.unknown5 = 0x00000000; - lck.in.flags = SMB2_LOCK_FLAG_UNLOCK; + el[0].offset = ARRAY_SIZE(buf)/2; + el[0].length = ARRAY_SIZE(buf)/2; + el[0].reserved = 0x00000000; + el[0].flags = SMB2_LOCK_FLAG_UNLOCK; status = smb2_lock(tree, &lck); CHECK_STATUS(status, NT_STATUS_OK); - CHECK_VALUE(lck.out.unknown1, 0); + CHECK_VALUE(lck.out.reserved, 0); ZERO_STRUCT(wr); wr.in.file.handle = h2; @@ -349,7 +355,7 @@ static bool test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_t { struct test_lock_read_write_state s = { .fname = "lock_rw_exclusiv.dat", - .lock_flags = SMB2_LOCK_FLAG_EXCLUSIV, + .lock_flags = SMB2_LOCK_FLAG_EXCLUSIVE, .write_h1_status = NT_STATUS_OK, .read_h1_status = NT_STATUS_OK, .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT, -- cgit From aed93a238e13247945073921d91408c91ae210c3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 21 May 2008 22:51:21 +1000 Subject: fixed SMB2 flush call, and added flush to gentest_smb2 (This used to be commit c52fe1fe1c77636d87355d3c4baa66e052fe9008) --- source4/libcli/raw/interfaces.h | 6 +++++- source4/libcli/smb2/flush.c | 6 ++++-- source4/smb_server/smb2/fileio.c | 7 +++--- source4/torture/gentest_smb2.c | 46 ++++++++++++++++++++++++++++++---------- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h index 149b91916a..3370021d48 100644 --- a/source4/libcli/raw/interfaces.h +++ b/source4/libcli/raw/interfaces.h @@ -2156,8 +2156,12 @@ union smb_flush { enum smb_flush_level level; struct { union smb_handle file; - uint32_t unknown; + uint16_t reserved1; + uint32_t reserved2; } in; + struct { + uint16_t reserved; + } out; } smb2; }; diff --git a/source4/libcli/smb2/flush.c b/source4/libcli/smb2/flush.c index 116068ed6e..577d1ba1ba 100644 --- a/source4/libcli/smb2/flush.c +++ b/source4/libcli/smb2/flush.c @@ -33,8 +33,8 @@ struct smb2_request *smb2_flush_send(struct smb2_tree *tree, struct smb2_flush * req = smb2_request_init_tree(tree, SMB2_OP_FLUSH, 0x18, false, 0); if (req == NULL) return NULL; - SSVAL(req->out.body, 0x02, 0); /* pad? */ - SIVAL(req->out.body, 0x04, io->in.unknown); + SSVAL(req->out.body, 0x02, io->in.reserved1); + SIVAL(req->out.body, 0x04, io->in.reserved2); smb2_push_handle(req->out.body+0x08, &io->in.file.handle); smb2_transport_send(req); @@ -55,6 +55,8 @@ NTSTATUS smb2_flush_recv(struct smb2_request *req, struct smb2_flush *io) SMB2_CHECK_PACKET_RECV(req, 0x04, false); + io->out.reserved = SVAL(req->in.body, 0x02); + return smb2_request_destroy(req); } diff --git a/source4/smb_server/smb2/fileio.c b/source4/smb_server/smb2/fileio.c index 0feb259038..5ab217bbfd 100644 --- a/source4/smb_server/smb2/fileio.c +++ b/source4/smb_server/smb2/fileio.c @@ -135,7 +135,7 @@ static void smb2srv_flush_send(struct ntvfs_request *ntvfs) SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_flush); SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x04, false, 0)); - SSVAL(req->out.body, 0x02, 0); + SSVAL(req->out.body, 0x02, io->smb2.out.reserved); smb2srv_send_reply(req); } @@ -143,15 +143,14 @@ static void smb2srv_flush_send(struct ntvfs_request *ntvfs) void smb2srv_flush_recv(struct smb2srv_request *req) { union smb_flush *io; - uint16_t _pad; SMB2SRV_CHECK_BODY_SIZE(req, 0x18, false); SMB2SRV_TALLOC_IO_PTR(io, union smb_flush); SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_flush_send, NTVFS_ASYNC_STATE_MAY_ASYNC); io->smb2.level = RAW_FLUSH_SMB2; - _pad = SVAL(req->in.body, 0x02); - io->smb2.in.unknown = IVAL(req->in.body, 0x04); + io->smb2.in.reserved1 = SVAL(req->in.body, 0x02); + io->smb2.in.reserved2 = IVAL(req->in.body, 0x04); io->smb2.in.file.ntvfs = smb2srv_pull_handle(req, req->in.body, 0x08); SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs); diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c index 68e9e2c20b..fc6dbcbb9a 100644 --- a/source4/torture/gentest_smb2.c +++ b/source4/torture/gentest_smb2.c @@ -349,8 +349,8 @@ static uint16_t gen_fnum(int instance) */ static uint16_t gen_fnum_close(int instance) { - if (num_open_handles < 3) { - if (gen_chance(80)) return BAD_HANDLE; + if (num_open_handles < 5) { + if (gen_chance(90)) return BAD_HANDLE; } return gen_fnum(instance); @@ -573,8 +573,8 @@ static uint32_t gen_ntcreatex_flags(void) */ static uint32_t gen_access_mask(void) { - if (gen_chance(50)) return SEC_FLAG_MAXIMUM_ALLOWED; - if (gen_chance(20)) return SEC_FILE_ALL; + if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED; + if (gen_chance(70)) return SEC_FILE_ALL; return gen_bits_mask(0xFFFFFFFF); } @@ -593,6 +593,7 @@ static uint32_t gen_create_options(void) */ static uint32_t gen_open_disp(void) { + if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF; if (gen_chance(10)) return gen_bits_mask(0xFFFFFFFF); return gen_int_range(0, 5); } @@ -1002,20 +1003,20 @@ again: /* generate ntcreatex operations */ -static bool handler_ntcreatex(int instance) +static bool handler_create(int instance) { struct smb2_create parm[NSERVERS]; NTSTATUS status[NSERVERS]; ZERO_STRUCT(parm[0]); - parm[0].in.security_flags = gen_bits_levels(3, 70, 0x0, 70, 0x3, 100, 0xFF); - parm[0].in.oplock_level = gen_bits_levels(3, 70, 0x0, 70, 0x9, 100, 0xFF); - parm[0].in.impersonation_level = gen_bits_levels(3, 70, 0x0, 70, 0x3, 100, 0xFFFFFFFF); - parm[0].in.create_flags = gen_bits_levels(2, 80, 0x0, 100, 0xFFFFFFFF); + 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_bits_levels(2, 90, 0x0, 100, 0xFFFFFFFF); if (gen_chance(2)) { parm[0].in.create_flags |= gen_bits_mask(0xFFFFFFFF); } - parm[0].in.reserved = gen_bits_levels(2, 80, 0x0, 100, 0xFFFFFFFF); + parm[0].in.reserved = gen_bits_levels(2, 95, 0x0, 100, 0xFFFFFFFF); if (gen_chance(2)) { parm[0].in.reserved |= gen_bits_mask(0xFFFFFFFF); } @@ -1171,6 +1172,28 @@ static bool handler_lock(int instance) return true; } +/* + generate flush operations +*/ +static bool handler_flush(int instance) +{ + struct smb2_flush parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + ZERO_STRUCT(parm[0]); + parm[0].in.file.handle.data[0] = gen_fnum(instance); + parm[0].in.reserved1 = gen_bits_mask2(0x0, 0xFFFF); + parm[0].in.reserved2 = gen_bits_mask2(0x0, 0xFFFFFFFF); + + GEN_COPY_PARM; + GEN_SET_FNUM(in.file.handle); + GEN_CALL(smb2_flush(tree, &parm[i])); + + CHECK_EQUAL(out.reserved); + + return true; +} + #if 0 /* @@ -1577,11 +1600,12 @@ static struct { bool (*handler)(int instance); int count, success_count; } gen_ops[] = { - {"NTCREATEX", handler_ntcreatex}, + {"CREATE", handler_create}, {"CLOSE", handler_close}, {"READ", handler_read}, {"WRITE", handler_write}, {"LOCK", handler_lock}, + {"FLUSH", handler_flush}, }; -- cgit