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

Reply via email to