The branch, v4-0-test has been updated via c52fe1fe1c77636d87355d3c4baa66e052fe9008 (commit) via ea6d9cf602302adafe0f9d5f5f90a9b26d1ead6f (commit) from 17c41a6c3e71102e3516e6926f7e7d1ab5c97563 (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test - Log ----------------------------------------------------------------- commit c52fe1fe1c77636d87355d3c4baa66e052fe9008 Author: Andrew Tridgell <[EMAIL PROTECTED]> Date: Wed May 21 22:51:21 2008 +1000 fixed SMB2 flush call, and added flush to gentest_smb2 commit ea6d9cf602302adafe0f9d5f5f90a9b26d1ead6f Author: Andrew Tridgell <[EMAIL PROTECTED]> Date: Wed May 21 22:12:20 2008 +1000 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 ----------------------------------------------------------------------- Summary of changes: source/libcli/raw/interfaces.h | 34 +++++--- source/libcli/smb2/flush.c | 6 +- source/libcli/smb2/lock.c | 24 ++++-- source/ntvfs/ntvfs_generic.c | 62 +++++++++----- source/smb_server/smb2/fileio.c | 37 ++++++--- source/smb_server/smb2/smb2_server.h | 2 +- source/torture/gentest_smb2.c | 103 ++++++++++++++--------- source/torture/smb2/lock.c | 148 ++++++++++++++++++---------------- 8 files changed, 246 insertions(+), 170 deletions(-) Changeset truncated at 500 lines: diff --git a/source/libcli/raw/interfaces.h b/source/libcli/raw/interfaces.h index 871bab0..3370021 100644 --- a/source/libcli/raw/interfaces.h +++ b/source/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; @@ -2154,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/source/libcli/smb2/flush.c b/source/libcli/smb2/flush.c index 116068e..577d1ba 100644 --- a/source/libcli/smb2/flush.c +++ b/source/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/source/libcli/smb2/lock.c b/source/libcli/smb2/lock.c index d71a337..62c6e5d 100644 --- a/source/libcli/smb2/lock.c +++ b/source/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;i<io->in.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/source/ntvfs/ntvfs_generic.c b/source/ntvfs/ntvfs_generic.c index 3653ad8..a706e62 100644 --- a/source/ntvfs/ntvfs_generic.c +++ b/source/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;i<lck->smb2.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;i<lck->smb2.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/source/smb_server/smb2/fileio.c b/source/smb_server/smb2/fileio.c index b6b35d3..5ab217b 100644 --- a/source/smb_server/smb2/fileio.c +++ b/source/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); @@ -247,7 +246,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 +254,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;i<io->smb2.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/source/smb_server/smb2/smb2_server.h b/source/smb_server/smb2/smb2_server.h index 2f347d3..fc40a92 100644 --- a/source/smb_server/smb2/smb2_server.h +++ b/source/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/source/torture/gentest_smb2.c b/source/torture/gentest_smb2.c index 9c4be90..fc6dbcb 100644 --- a/source/torture/gentest_smb2.c +++ b/source/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); @@ -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); } /* @@ -570,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); } @@ -590,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); } @@ -999,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); } @@ -1135,46 +1139,63 @@ 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;n<nlocks;n++) { - parm[0].lockx.in.locks[n].pid = gen_pid(); - parm[0].lockx.in.locks[n].offset = gen_offset(); - parm[0].lockx.in.locks[n].count = gen_io_count(); - } + 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_bits_mask2(0, 0xFFFFFFFF); + + parm[0].in.locks = talloc_array(current_op.mem_ctx, + struct smb2_lock_element, + parm[0].in.lock_count); + for (n=0;n<parm[0].in.lock_count;n++) { + parm[0].in.locks[n].offset = gen_offset(); + parm[0].in.locks[n].length = gen_io_count(); + /* don't yet cope with async replies */ + parm[0].in.locks[n].flags = gen_lock_flags() | + SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; + parm[0].in.locks[n].reserved = gen_bits_mask2(0x0, 0xFFFFFFFF); } GEN_COPY_PARM; - GEN_SET_FNUM(lockx.in.file.fnum); - GEN_CALL(smb_raw_lock(tree, &parm[i])); + GEN_SET_FNUM(in.file.handle); + GEN_CALL(smb2_lock(tree, &parm[i])); + + 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 + /* generate a fileinfo query structure */ @@ -1579,10 +1600,12 @@ static struct { bool (*handler)(int instance); -- Samba Shared Repository