The branch, v4-0-test has been updated
via 914f0ac83bc396be0ca34c43e2ea01ecc1c3b826 (commit)
via b781bb733c9a563457f87c94abe8c91b426c07ee (commit)
via 2306394dcc22ff2be8581256a5cf91eef4993078 (commit)
via 58189b87eade62b717c2c17c679e482786bf2098 (commit)
via 7f545dbbf0186fe552e4c49a3f618862cb4771e7 (commit)
via 5ffea702c3a1c92a797afab1a3cadf2f2a18729f (commit)
via 60c4a4fc1afe88716ac63d3ea430e07fea7b9991 (commit)
from c7f34f41c3f9f0c3f75a618dfaf566706014a6b4 (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test
- Log -----------------------------------------------------------------
commit 914f0ac83bc396be0ca34c43e2ea01ecc1c3b826
Author: Stefan Metzmacher <[EMAIL PROTECTED]>
Date: Sat Apr 19 00:13:42 2008 +0200
torture/smb2: add a simple SMB2-OPLOCK-BATCH1 test
metze
commit b781bb733c9a563457f87c94abe8c91b426c07ee
Author: Stefan Metzmacher <[EMAIL PROTECTED]>
Date: Fri Apr 18 22:32:25 2008 +0200
ntvfs_generic: map RAW_LOCK_SMB2_BREAK to RAW_LOCK_GENERIC
metze
commit 2306394dcc22ff2be8581256a5cf91eef4993078
Author: Stefan Metzmacher <[EMAIL PROTECTED]>
Date: Fri Apr 18 22:30:12 2008 +0200
smb_server/smb2: handle incoming oplock releases
metze
commit 58189b87eade62b717c2c17c679e482786bf2098
Author: Stefan Metzmacher <[EMAIL PROTECTED]>
Date: Fri Apr 18 22:27:24 2008 +0200
libcli/smb2: make it possible to handle incoming oplock requests
metze
commit 7f545dbbf0186fe552e4c49a3f618862cb4771e7
Author: Stefan Metzmacher <[EMAIL PROTECTED]>
Date: Fri Apr 18 22:24:21 2008 +0200
libcli/smb2: add smb2_break() calls
metze
commit 5ffea702c3a1c92a797afab1a3cadf2f2a18729f
Author: Stefan Metzmacher <[EMAIL PROTECTED]>
Date: Fri Apr 18 22:19:08 2008 +0200
libcli: define structure for SMB2 Break
metze
commit 60c4a4fc1afe88716ac63d3ea430e07fea7b9991
Author: Stefan Metzmacher <[EMAIL PROTECTED]>
Date: Sat Apr 19 00:14:52 2008 +0200
ntvfs_generic: fix mapping the granted oplocks for SMB2
metze
-----------------------------------------------------------------------
Summary of changes:
source/libcli/raw/interfaces.h | 17 +++-
source/libcli/smb2/{flush.c => break.c} | 42 ++++---
source/libcli/smb2/config.mk | 2 +-
source/libcli/smb2/smb2.h | 11 ++
source/libcli/smb2/transport.c | 43 ++++++++
source/ntvfs/ntvfs_generic.c | 23 ++++-
source/smb_server/smb2/fileio.c | 31 +++++-
source/torture/smb2/config.mk | 3 +-
source/torture/smb2/oplocks.c | 178 +++++++++++++++++++++++++++++++
source/torture/smb2/smb2.c | 1 +
10 files changed, 326 insertions(+), 25 deletions(-)
copy source/libcli/smb2/{flush.c => break.c} (54%)
create mode 100644 source/torture/smb2/oplocks.c
Changeset truncated at 500 lines:
diff --git a/source/libcli/raw/interfaces.h b/source/libcli/raw/interfaces.h
index cf5a3aa..bad3743 100644
--- a/source/libcli/raw/interfaces.h
+++ b/source/libcli/raw/interfaces.h
@@ -1862,7 +1862,8 @@ enum smb_lock_level {
RAW_LOCK_LOCK,
RAW_LOCK_UNLOCK,
RAW_LOCK_LOCKX,
- RAW_LOCK_SMB2
+ RAW_LOCK_SMB2,
+ RAW_LOCK_SMB2_BREAK
};
/* the generic interface is defined to be equal to the lockingX interface */
@@ -1925,6 +1926,20 @@ union smb_lock {
uint16_t unknown1;
} out;
} smb2;
+
+ /* SMB2 Break */
+ struct smb2_break {
+ enum smb_lock_level level;
+ struct {
+ union smb_handle file;
+
+ /* static body buffer 24 (0x18) bytes */
+ uint8_t oplock_level;
+ uint8_t reserved;
+ uint32_t reserved2;
+ /* struct smb2_handle handle; */
+ } in, out;
+ } smb2_break;
};
diff --git a/source/libcli/smb2/flush.c b/source/libcli/smb2/break.c
similarity index 54%
copy from source/libcli/smb2/flush.c
copy to source/libcli/smb2/break.c
index 116068e..fe0cceb 100644
--- a/source/libcli/smb2/flush.c
+++ b/source/libcli/smb2/break.c
@@ -1,20 +1,20 @@
-/*
+/*
Unix SMB/CIFS implementation.
- SMB2 client flush handling
+ SMB2 client oplock break handling
+
+ Copyright (C) Stefan Metzmacher 2008
- Copyright (C) Andrew Tridgell 2005
-
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
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -24,17 +24,18 @@
#include "libcli/smb2/smb2_calls.h"
/*
- send a flush request
+ send a break request
*/
-struct smb2_request *smb2_flush_send(struct smb2_tree *tree, struct smb2_flush
*io)
+struct smb2_request *smb2_break_send(struct smb2_tree *tree, struct smb2_break
*io)
{
struct smb2_request *req;
- req = smb2_request_init_tree(tree, SMB2_OP_FLUSH, 0x18, false, 0);
+ req = smb2_request_init_tree(tree, SMB2_OP_BREAK, 0x18, false, 0);
if (req == NULL) return NULL;
- SSVAL(req->out.body, 0x02, 0); /* pad? */
- SIVAL(req->out.body, 0x04, io->in.unknown);
+ SCVAL(req->out.body, 0x02, io->in.oplock_level);
+ SCVAL(req->out.body, 0x03, io->in.reserved);
+ SIVAL(req->out.body, 0x04, io->in.reserved2);
smb2_push_handle(req->out.body+0x08, &io->in.file.handle);
smb2_transport_send(req);
@@ -44,16 +45,21 @@ struct smb2_request *smb2_flush_send(struct smb2_tree
*tree, struct smb2_flush *
/*
- recv a flush reply
+ recv a break reply
*/
-NTSTATUS smb2_flush_recv(struct smb2_request *req, struct smb2_flush *io)
+NTSTATUS smb2_break_recv(struct smb2_request *req, struct smb2_break *io)
{
- if (!smb2_request_receive(req) ||
+ if (!smb2_request_receive(req) ||
!smb2_request_is_ok(req)) {
return smb2_request_destroy(req);
}
- SMB2_CHECK_PACKET_RECV(req, 0x04, false);
+ SMB2_CHECK_PACKET_RECV(req, 0x18, false);
+
+ io->out.oplock_level = CVAL(req->in.body, 0x02);
+ io->out.reserved = CVAL(req->in.body, 0x03);
+ io->out.reserved2 = IVAL(req->in.body, 0x04);
+ smb2_pull_handle(req->in.body+0x08, &io->out.file.handle);
return smb2_request_destroy(req);
}
@@ -61,8 +67,8 @@ NTSTATUS smb2_flush_recv(struct smb2_request *req, struct
smb2_flush *io)
/*
sync flush request
*/
-NTSTATUS smb2_flush(struct smb2_tree *tree, struct smb2_flush *io)
+NTSTATUS smb2_break(struct smb2_tree *tree, struct smb2_break *io)
{
- struct smb2_request *req = smb2_flush_send(tree, io);
- return smb2_flush_recv(req, io);
+ struct smb2_request *req = smb2_break_send(tree, io);
+ return smb2_break_recv(req, io);
}
diff --git a/source/libcli/smb2/config.mk b/source/libcli/smb2/config.mk
index e95997d..18f6245 100644
--- a/source/libcli/smb2/config.mk
+++ b/source/libcli/smb2/config.mk
@@ -6,5 +6,5 @@ LIBCLI_SMB2_OBJ_FILES = $(addprefix libcli/smb2/, \
transport.o request.o negprot.o session.o tcon.o \
create.o close.o connect.o getinfo.o write.o read.o \
setinfo.o find.o ioctl.o logoff.o tdis.o flush.o \
- lock.o notify.o cancel.o keepalive.o)
+ lock.o notify.o cancel.o keepalive.o break.o)
diff --git a/source/libcli/smb2/smb2.h b/source/libcli/smb2/smb2.h
index 726df64..ae66a6e 100644
--- a/source/libcli/smb2/smb2.h
+++ b/source/libcli/smb2/smb2.h
@@ -21,6 +21,8 @@
#include "libcli/raw/request.h"
+struct smb2_handle;
+
struct smb2_options {
uint32_t timeout;
};
@@ -58,6 +60,15 @@ struct smb2_transport {
void *private;
uint_t period;
} idle;
+
+ struct {
+ /* a oplock break request handler */
+ bool (*handler)(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level, void *private_data);
+ /* private data passed to the oplock handler */
+ void *private_data;
+ } oplock;
};
diff --git a/source/libcli/smb2/transport.c b/source/libcli/smb2/transport.c
index af19fcb..8eb60a0 100644
--- a/source/libcli/smb2/transport.c
+++ b/source/libcli/smb2/transport.c
@@ -140,6 +140,44 @@ void smb2_transport_dead(struct smb2_transport *transport,
NTSTATUS status)
}
}
+static bool smb2_handle_oplock_break(struct smb2_transport *transport,
+ const DATA_BLOB *blob)
+{
+ uint8_t *hdr;
+ uint16_t opcode;
+ uint64_t seqnum;
+
+ hdr = blob->data+NBT_HDR_SIZE;
+
+ if (blob->length < (SMB2_MIN_SIZE+0x18)) {
+ DEBUG(1,("Discarding smb2 oplock reply of size %u\n",
+ blob->length));
+ return false;
+ }
+
+ opcode = SVAL(hdr, SMB2_HDR_OPCODE);
+ seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
+
+ if ((opcode != SMB2_OP_BREAK) ||
+ (seqnum != UINT64_MAX)) {
+ return false;
+ }
+
+ if (transport->oplock.handler) {
+ uint8_t *body = hdr+SMB2_HDR_BODY;
+ struct smb2_handle h;
+ uint8_t level;
+
+ level = CVAL(body, 0x02);
+ smb2_pull_handle(body+0x08, &h);
+
+ transport->oplock.handler(transport, &h, level,
+ transport->oplock.private_data);
+ }
+
+ return true;
+}
+
/*
we have a full request in our receive buffer - match it to a pending request
and process
@@ -167,6 +205,11 @@ static NTSTATUS smb2_transport_finish_recv(void *private,
DATA_BLOB blob)
goto error;
}
+ if (smb2_handle_oplock_break(transport, &blob)) {
+ talloc_free(buffer);
+ return NT_STATUS_OK;
+ }
+
flags = IVAL(hdr, SMB2_HDR_FLAGS);
seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
diff --git a/source/ntvfs/ntvfs_generic.c b/source/ntvfs/ntvfs_generic.c
index 5d4bbf3..3653ad8 100644
--- a/source/ntvfs/ntvfs_generic.c
+++ b/source/ntvfs/ntvfs_generic.c
@@ -209,13 +209,13 @@ static NTSTATUS ntvfs_map_open_finish(struct
ntvfs_module_context *ntvfs,
case RAW_OPEN_SMB2:
io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
switch (io2->generic.out.oplock_level) {
- case OPLOCK_BATCH:
+ case BATCH_OPLOCK_RETURN:
io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
break;
- case OPLOCK_EXCLUSIVE:
+ case EXCLUSIVE_OPLOCK_RETURN:
io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
break;
- case OPLOCK_LEVEL_II:
+ case LEVEL_II_OPLOCK_RETURN:
io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
break;
default:
@@ -1043,6 +1043,23 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context
*ntvfs,
/* initialize output value */
lck->smb2.out.unknown1 = 0;
break;
+
+ case RAW_LOCK_SMB2_BREAK:
+ lck2->generic.level = RAW_LOCK_GENERIC;
+ lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
+ lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
+
((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
+ lck2->generic.in.timeout = 0;
+ lck2->generic.in.ulock_cnt = 0;
+ lck2->generic.in.lock_cnt = 0;
+ lck2->generic.in.locks = NULL;
+
+ /* initialize output value */
+ lck->smb2_break.out.oplock_level=
lck->smb2_break.in.oplock_level;
+ lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
+ lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
+ lck->smb2_break.out.file = lck->smb2_break.in.file;
+ break;
}
/*
diff --git a/source/smb_server/smb2/fileio.c b/source/smb_server/smb2/fileio.c
index af1a413..b6b35d3 100644
--- a/source/smb_server/smb2/fileio.c
+++ b/source/smb_server/smb2/fileio.c
@@ -410,7 +410,36 @@ void smb2srv_notify_recv(struct smb2srv_request *req)
SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_notify(req->ntvfs, io));
}
+static void smb2srv_break_send(struct ntvfs_request *ntvfs)
+{
+ struct smb2srv_request *req;
+ union smb_lock *io;
+
+ SMB2SRV_CHECK_ASYNC_STATUS_ERR(io, union smb_lock);
+ SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x18, false, 0));
+
+ SCVAL(req->out.body, 0x02, io->smb2_break.out.oplock_level);
+ SCVAL(req->out.body, 0x03, io->smb2_break.out.reserved);
+ SIVAL(req->out.body, 0x04, io->smb2_break.out.reserved2);
+ smb2srv_push_handle(req->out.body, 0x08,io->smb2_break.out.file.ntvfs);
+
+ smb2srv_send_reply(req);
+}
+
void smb2srv_break_recv(struct smb2srv_request *req)
{
- smb2srv_send_error(req, NT_STATUS_NOT_IMPLEMENTED);
+ union smb_lock *io;
+
+ SMB2SRV_CHECK_BODY_SIZE(req, 0x18, false);
+ SMB2SRV_TALLOC_IO_PTR(io, union smb_lock);
+ SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_break_send,
NTVFS_ASYNC_STATE_MAY_ASYNC);
+
+ io->smb2_break.level = RAW_LOCK_SMB2_BREAK;
+ io->smb2_break.in.oplock_level = CVAL(req->in.body, 0x02);
+ io->smb2_break.in.reserved = CVAL(req->in.body, 0x03);
+ io->smb2_break.in.reserved2 = IVAL(req->in.body, 0x04);
+ io->smb2_break.in.file.ntvfs = smb2srv_pull_handle(req,
req->in.body, 0x08);
+
+ SMB2SRV_CHECK_FILE_HANDLE(io->smb2_break.in.file.ntvfs);
+ SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, io));
}
diff --git a/source/torture/smb2/config.mk b/source/torture/smb2/config.mk
index 12d5edb..f3318bb 100644
--- a/source/torture/smb2/config.mk
+++ b/source/torture/smb2/config.mk
@@ -21,5 +21,6 @@ TORTURE_SMB2_OBJ_FILES = $(addprefix torture/smb2/, \
lock.o \
notify.o \
smb2.o \
- persistent_handles.o)
+ persistent_handles.o \
+ oplocks.o)
diff --git a/source/torture/smb2/oplocks.c b/source/torture/smb2/oplocks.c
new file mode 100644
index 0000000..b0a1b31
--- /dev/null
+++ b/source/torture/smb2/oplocks.c
@@ -0,0 +1,178 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 oplocks
+
+ Copyright (C) Stefan Metzmacher 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/security.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "param/param.h"
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s
got 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect
status %s - should be %s", \
+ nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+static struct {
+ struct smb2_handle handle;
+ uint8_t level;
+ struct smb2_break br;
+ int count;
+ int failures;
+} break_info;
+
+static void torture_oplock_break_callback(struct smb2_request *req)
+{
+ NTSTATUS status;
+ struct smb2_break br;
+
+ ZERO_STRUCT(br);
+ status = smb2_break_recv(req, &break_info.br);
+ if (!NT_STATUS_IS_OK(status)) {
+ break_info.failures++;
+ }
+
+ return;
+}
+
+/* a oplock break request handler */
+static bool torture_oplock_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level, void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ const char *name;
+ struct smb2_request *req;
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ switch (level) {
+ case SMB2_OPLOCK_LEVEL_II:
+ name = "level II";
+ break;
+ case SMB2_OPLOCK_LEVEL_NONE:
+ name = "none";
+ break;
+ default:
+ name = "unknown";
+ break_info.failures++;
+ }
+ printf("Acking to %s [0x%02X] in oplock handler\n",
+ name, level);
+
+ ZERO_STRUCT(break_info.br);
+ break_info.br.in.file.handle = *handle;
+ break_info.br.in.oplock_level = level;
+ break_info.br.in.reserved = 0;
+ break_info.br.in.reserved2 = 0;
+
+ req = smb2_break_send(tree, &break_info.br);
+ req->async.fn = torture_oplock_break_callback;
+ req->async.private = NULL;
+
+ return true;
+}
+
+bool torture_smb2_oplock_batch1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle h1, h2;
+ struct smb2_create io;
+ NTSTATUS status;
+ const char *fname = "oplock.dat";
+ bool ret = true;
+
+ tree->session->transport->oplock.handler =
torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(break_info);
+
+ ZERO_STRUCT(io);
+ io.in.security_flags = 0x00;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.in.create_flags = 0x00000000;
+ io.in.reserved = 0x00000000;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+ /*CHECK_VAL(io.out.reserved, 0);*/
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_VAL(io.out.alloc_size, 0);
+ CHECK_VAL(io.out.size, 0);
+ CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.reserved2, 0);
+ CHECK_VAL(break_info.count, 0);
+
+ h1 = io.out.file.handle;
+
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+ /*CHECK_VAL(io.out.reserved, 0);*/
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
--
Samba Shared Repository