The branch, master has been updated
       via  91e75ea8f6fef61219fcba992304563af7a04948 (commit)
       via  afa71fbad9cbd8b1a6b68b9ba01936ad70ff25e5 (commit)
      from  264b28ec0962c355ee90f9ac67fcf07cd84c5c7b (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 91e75ea8f6fef61219fcba992304563af7a04948
Author: Zach Loafman <[email protected]>
Date:   Mon Mar 30 15:59:06 2009 -0700

    s4:torture/smb2: Add torture tests for lease breaks, durable opens.

commit afa71fbad9cbd8b1a6b68b9ba01936ad70ff25e5
Author: Zach Loafman <[email protected]>
Date:   Mon Mar 30 15:57:57 2009 -0700

    s4:smb2: Add lease break support for SMB2.1
    
    Add the structures and marshalling for the lease break variants of the
    oplock break / oplock break ack messages.

-----------------------------------------------------------------------

Summary of changes:
 source4/libcli/raw/interfaces.h     |   23 ++-
 source4/libcli/smb2/config.mk       |    3 +-
 source4/libcli/smb2/create.c        |    4 +-
 source4/libcli/smb2/lease_break.c   |   81 ++++
 source4/libcli/smb2/smb2.h          |   13 +
 source4/libcli/smb2/transport.c     |   55 +++-
 source4/torture/smb2/durable_open.c |  420 ++++++++++++++++++---
 source4/torture/smb2/lease.c        |  704 +++++++++++++++++++++++++++++++----
 8 files changed, 1155 insertions(+), 148 deletions(-)
 create mode 100644 source4/libcli/smb2/lease_break.c


Changeset truncated at 500 lines:

diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h
index bd93fa1..3c0d186 100644
--- a/source4/libcli/raw/interfaces.h
+++ b/source4/libcli/raw/interfaces.h
@@ -56,13 +56,26 @@ struct smb2_handle {
 /*
   SMB2 lease structure (per MS-SMB2 2.2.13)
 */
+struct smb2_lease_key {
+       uint64_t data[2];
+};
+
 struct smb2_lease {
-       uint64_t lease_key[2];
+       struct smb2_lease_key lease_key;
        uint32_t lease_state;
        uint32_t lease_flags; /* should be 0 */
        uint64_t lease_duration; /* should be 0 */
 };
 
+struct smb2_lease_break {
+       struct smb2_lease current_lease;
+       uint32_t break_flags;
+       uint32_t new_lease_state;
+       uint32_t break_reason; /* should be 0 */
+       uint32_t access_mask_hint; /* should be 0 */
+       uint32_t share_mask_hint; /* should be 0 */
+};
+
 struct ntvfs_handle;
 
 /*
@@ -2006,6 +2019,14 @@ union smb_lock {
                        /* struct smb2_handle handle; */
                } in, out;
        } smb2_break;
+
+       /* SMB2 Lease Break Ack (same opcode as smb2_break) */
+       struct smb2_lease_break_ack {
+               struct {
+                       uint32_t reserved;
+                       struct smb2_lease lease;
+               } in, out;
+       } smb2_lease_break_ack;
 };
 
 
diff --git a/source4/libcli/smb2/config.mk b/source4/libcli/smb2/config.mk
index 322bca1..ddd45c9 100644
--- a/source4/libcli/smb2/config.mk
+++ b/source4/libcli/smb2/config.mk
@@ -5,6 +5,7 @@ LIBCLI_SMB2_OBJ_FILES = $(addprefix $(libclisrcdir)/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 break.o util.o signing.o)
+       lock.o notify.o cancel.o keepalive.o break.o util.o signing.o \
+       lease_break.o)
 
 $(eval $(call 
proto_header_template,$(libclisrcdir)/smb2/smb2_proto.h,$(LIBCLI_SMB2_OBJ_FILES:.o=.c)))
diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c
index 344be60..363210b 100644
--- a/source4/libcli/smb2/create.c
+++ b/source4/libcli/smb2/create.c
@@ -315,7 +315,7 @@ struct smb2_request *smb2_create_send(struct smb2_tree 
*tree, struct smb2_create
        if (io->in.lease_request) {
                uint8_t data[32];
 
-               memcpy(&data[0], io->in.lease_request->lease_key, 16);
+               memcpy(&data[0], &io->in.lease_request->lease_key, 16);
                SIVAL(data, 16, io->in.lease_request->lease_state);
                SIVAL(data, 20, io->in.lease_request->lease_flags);
                SBVAL(data, 24, io->in.lease_request->lease_duration);
@@ -427,7 +427,7 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, 
TALLOC_CTX *mem_ctx, struct
                        }
 
                        data = io->out.blobs.blobs[i].data.data;
-                       memcpy(io->out.lease_response.lease_key, data, 16);
+                       memcpy(&io->out.lease_response.lease_key, data, 16);
                        io->out.lease_response.lease_state = IVAL(data, 16);
                        io->out.lease_response.lease_flags = IVAL(data, 20);
                        io->out.lease_response.lease_duration = BVAL(data, 24);
diff --git a/source4/libcli/smb2/lease_break.c 
b/source4/libcli/smb2/lease_break.c
new file mode 100644
index 0000000..c238f1d
--- /dev/null
+++ b/source4/libcli/smb2/lease_break.c
@@ -0,0 +1,81 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   SMB2 client oplock break handling
+
+   Copyright (C) Zachary Loafman 2009
+
+   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 "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+
+/*
+  Send a Lease Break Acknowledgement
+*/
+struct smb2_request *smb2_lease_break_ack_send(struct smb2_tree *tree,
+                                               struct smb2_lease_break_ack *io)
+{
+       struct smb2_request *req;
+
+       req = smb2_request_init_tree(tree, SMB2_OP_BREAK, 0x24, false, 0);
+       if (req == NULL) return NULL;
+
+       SIVAL(req->out.body, 0x02, io->in.reserved);
+       SIVAL(req->out.body, 0x04, io->in.lease.lease_flags);
+       memcpy(req->out.body+0x8, &io->in.lease.lease_key,
+           sizeof(struct smb2_lease_key));
+       SIVAL(req->out.body, 0x18, io->in.lease.lease_state);
+       SBVAL(req->out.body, 0x1C, io->in.lease.lease_duration);
+
+       smb2_transport_send(req);
+
+       return req;
+}
+
+
+/*
+  Receive a Lease Break Response
+*/
+NTSTATUS smb2_lease_break_ack_recv(struct smb2_request *req,
+                                   struct smb2_lease_break_ack *io)
+{
+       if (!smb2_request_receive(req) ||
+           !smb2_request_is_ok(req)) {
+               return smb2_request_destroy(req);
+       }
+
+       SMB2_CHECK_PACKET_RECV(req, 0x24, false);
+
+       io->out.reserved                = IVAL(req->in.body, 0x02);
+       io->out.lease.lease_flags       = IVAL(req->in.body, 0x04);
+       memcpy(&io->out.lease.lease_key, req->in.body+0x8,
+           sizeof(struct smb2_lease_key));
+       io->out.lease.lease_state       = IVAL(req->in.body, 0x18);
+       io->out.lease.lease_duration    = IVAL(req->in.body, 0x1C);
+
+       return smb2_request_destroy(req);
+}
+
+/*
+  sync flush request
+*/
+NTSTATUS smb2_lease_break_ack(struct smb2_tree *tree,
+                              struct smb2_lease_break_ack *io)
+{
+       struct smb2_request *req = smb2_lease_break_ack_send(tree, io);
+       return smb2_lease_break_ack_recv(req, io);
+}
diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h
index fd961ce..3044623 100644
--- a/source4/libcli/smb2/smb2.h
+++ b/source4/libcli/smb2/smb2.h
@@ -26,6 +26,7 @@
 #include "libcli/raw/libcliraw.h"
 
 struct smb2_handle;
+struct smb2_lease_break;
 
 /*
   information returned from the negotiate process
@@ -73,6 +74,15 @@ struct smb2_transport {
                void *private_data;
        } oplock;
 
+       struct {
+               /* a lease break request handler */
+               bool (*handler)(struct smb2_transport *transport,
+                               const struct smb2_lease_break *lease_break,
+                               void *private_data);
+               /* private data passed to the oplock handler */
+               void *private_data;
+       } lease;
+
        struct smbcli_options options;
 
        bool signing_required;
@@ -271,6 +281,9 @@ struct smb2_request {
 #define SMB2_LEASE_HANDLE                                0x02
 #define SMB2_LEASE_WRITE                                 0x04
 
+/* SMB2 lease break flags */
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED        0x01
+
 /* SMB2 impersonation levels */
 #define SMB2_IMPERSONATION_ANONYMOUS                     0x00
 #define SMB2_IMPERSONATION_IDENTIFICATION                0x01
diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c
index e112544..6a87d12 100644
--- a/source4/libcli/smb2/transport.c
+++ b/source4/libcli/smb2/transport.c
@@ -144,24 +144,39 @@ static NTSTATUS smb2_handle_oplock_break(struct 
smb2_transport *transport,
                                         const DATA_BLOB *blob)
 {
        uint8_t *hdr;
-       uint16_t opcode;
+       uint8_t *body;
+       uint16_t len, bloblen;
+       bool lease;
 
        hdr = blob->data+NBT_HDR_SIZE;
+       body = hdr+SMB2_HDR_BODY;
+       bloblen = blob->length - SMB2_HDR_BODY;
 
-       if (blob->length < (SMB2_MIN_SIZE+0x18)) {
+       if (bloblen < 2) {
                DEBUG(1,("Discarding smb2 oplock reply of size %u\n",
-                        (unsigned)blob->length));
+                       (unsigned)blob->length));
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       opcode  = SVAL(hdr, SMB2_HDR_OPCODE);
+       len = CVAL(body, 0x00);
+       if (len > bloblen) {
+               DEBUG(1,("Discarding smb2 oplock reply,"
+                       "packet claims %u byte body, only %u bytes seen\n",
+                       len, bloblen));
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
 
-       if (opcode != SMB2_OP_BREAK) {
+       if (len == 24) {
+               lease = false;
+       } else if (len == 44) {
+               lease = true;
+       } else {
+               DEBUG(1,("Discarding smb2 oplock reply of invalid size %u\n",
+                       (unsigned)blob->length));
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       if (transport->oplock.handler) {
-               uint8_t *body = hdr+SMB2_HDR_BODY;
+       if (!lease && transport->oplock.handler) {
                struct smb2_handle h;
                uint8_t level;
 
@@ -170,8 +185,24 @@ static NTSTATUS smb2_handle_oplock_break(struct 
smb2_transport *transport,
 
                transport->oplock.handler(transport, &h, level,
                                          transport->oplock.private_data);
+       } else if (lease && transport->lease.handler) {
+               struct smb2_lease_break lb;
+
+               ZERO_STRUCT(lb);
+               lb.break_flags =                SVAL(body, 0x4);
+               memcpy(&lb.current_lease.lease_key, body+0x8,
+                   sizeof(struct smb2_lease_key));
+               lb.current_lease.lease_state =  SVAL(body, 0x18);
+               lb.new_lease_state =            SVAL(body, 0x1C);
+               lb.break_reason =               SVAL(body, 0x20);
+               lb.access_mask_hint =           SVAL(body, 0x24);
+               lb.share_mask_hint =            SVAL(body, 0x28);
+
+               transport->lease.handler(transport, &lb,
+                   transport->lease.private_data);
        } else {
-               DEBUG(5,("Got SMB2 oplock break with no handler\n"));
+               DEBUG(5,("Got SMB2 %s break with no handler\n",
+                       lease ? "lease" : "oplock"));
        }
 
        return NT_STATUS_OK;
@@ -193,6 +224,7 @@ static NTSTATUS smb2_transport_finish_recv(void 
*private_data, DATA_BLOB blob)
        uint16_t buffer_code;
        uint32_t dynamic_size;
        uint32_t i;
+       uint16_t opcode;
        NTSTATUS status;
 
        buffer = blob.data;
@@ -207,9 +239,16 @@ static NTSTATUS smb2_transport_finish_recv(void 
*private_data, DATA_BLOB blob)
 
        flags   = IVAL(hdr, SMB2_HDR_FLAGS);
        seqnum  = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
+       opcode  = SVAL(hdr, SMB2_HDR_OPCODE);
 
        /* see MS-SMB2 3.2.5.19 */
        if (seqnum == UINT64_MAX) {
+               if (opcode != SMB2_OP_BREAK) {
+                       DEBUG(1,("Discarding packet with invalid seqnum, "
+                               "opcode %u\n", opcode));
+                       return NT_STATUS_INVALID_NETWORK_RESPONSE;
+               }
+
                return smb2_handle_oplock_break(transport, &blob);
        }
 
diff --git a/source4/torture/smb2/durable_open.c 
b/source4/torture/smb2/durable_open.c
index 9cc25e3..1b86f2c 100644
--- a/source4/torture/smb2/durable_open.c
+++ b/source4/torture/smb2/durable_open.c
@@ -41,6 +41,15 @@
                goto done; \
        }} while (0)
 
+#define CHECK_CREATED(__io, __created, __attribute)                    \
+       do {                                                            \
+               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, (__attribute));        \
+               CHECK_VAL((__io)->out.reserved2, 0);                    \
+       } while(0)
+
 /*
    basic testing of SMB2 durable opens
    regarding the position information on the handle
@@ -54,7 +63,6 @@ bool test_durable_open_file_position(struct torture_context 
*tctx,
        struct smb2_create io1, io2;
        NTSTATUS status;
        const char *fname = "durable_open_position.dat";
-       DATA_BLOB b;
        union smb_fileinfo qfinfo;
        union smb_setfileinfo sfinfo;
        bool ret = true;
@@ -78,31 +86,17 @@ bool test_durable_open_file_position(struct torture_context 
*tctx,
                                          NTCREATEX_OPTIONS_ASYNC_ALERT |
                                          NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
                                          0x00200000;
+       io1.in.durable_open             = true;
        io1.in.fname                    = fname;
 
-       b = data_blob_talloc(mem_ctx, NULL, 16);
-       SBVAL(b.data, 0, 0);
-       SBVAL(b.data, 8, 0);
-
-       status = smb2_create_blob_add(tree1, &io1.in.blobs,
-                                     SMB2_CREATE_TAG_DHNQ,
-                                     b);
-       CHECK_STATUS(status, NT_STATUS_OK);
-
        status = smb2_create(tree1, mem_ctx, &io1);
        CHECK_STATUS(status, NT_STATUS_OK);
+       h1 = io1.out.file.handle;
+       CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
        CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
-       /*CHECK_VAL(io1.out.reserved, 0);*/
-       CHECK_VAL(io1.out.create_action, NTCREATEX_ACTION_CREATED);
-       CHECK_VAL(io1.out.alloc_size, 0);
-       CHECK_VAL(io1.out.size, 0);
-       CHECK_VAL(io1.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
-       CHECK_VAL(io1.out.reserved2, 0);
 
        /* TODO: check extra blob content */
 
-       h1 = io1.out.file.handle;
-
        ZERO_STRUCT(qfinfo);
        qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
        qfinfo.generic.in.file.handle = h1;
@@ -141,15 +135,7 @@ bool test_durable_open_file_position(struct 
torture_context *tctx,
 
        ZERO_STRUCT(io2);
        io2.in.fname = fname;
-
-       b = data_blob_talloc(tctx, NULL, 16);
-       SBVAL(b.data, 0, h1.data[0]);
-       SBVAL(b.data, 8, h1.data[1]);
-
-       status = smb2_create_blob_add(tree2, &io2.in.blobs,
-                                     SMB2_CREATE_TAG_DHNC,
-                                     b);
-       CHECK_STATUS(status, NT_STATUS_OK);
+       io2.in.durable_handle = &h1;
 
        status = smb2_create(tree2, mem_ctx, &io2);
        CHECK_STATUS(status, NT_STATUS_OK);
@@ -191,12 +177,14 @@ bool test_durable_open_oplock(struct torture_context 
*tctx,
 {
        TALLOC_CTX *mem_ctx = talloc_new(tctx);
        struct smb2_create io1, io2;
-       struct smb2_handle h1;
+       struct smb2_handle h1, h2;
        NTSTATUS status;
-       const char *fname = "durable_open_oplock.dat";
-       DATA_BLOB b;
+       char fname[256];
        bool ret = true;
 
+       /* Choose a random name in case the state is left a little funky. */
+       snprintf(fname, 256, "durable_open_lease_%s.dat", 
generate_random_str(tctx, 8));
+
        /* Clean slate */
        smb2_util_unlink(tree1, fname);
 
@@ -218,29 +206,16 @@ bool test_durable_open_oplock(struct torture_context 
*tctx,
                                          NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
                                          0x00200000;
        io1.in.fname                    = fname;
+       io1.in.durable_open             = true;
 
        io2 = io1;
        io2.in.create_disposition       = NTCREATEX_DISP_OPEN;
 
-       b = data_blob_talloc(mem_ctx, NULL, 16);
-       SBVAL(b.data, 0, 0);
-       SBVAL(b.data, 8, 0);
-
-       status = smb2_create_blob_add(tree1, &io1.in.blobs,
-                                     SMB2_CREATE_TAG_DHNQ,
-                                     b);
-       CHECK_STATUS(status, NT_STATUS_OK);
-
        status = smb2_create(tree1, mem_ctx, &io1);
        CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
-       CHECK_VAL(io1.out.create_action, NTCREATEX_ACTION_CREATED);
-       CHECK_VAL(io1.out.alloc_size, 0);
-       CHECK_VAL(io1.out.size, 0);
-       CHECK_VAL(io1.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
-       CHECK_VAL(io1.out.reserved2, 0);
-
        h1 = io1.out.file.handle;
+       CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
 
        /* Disconnect after getting the batch */
        talloc_free(tree1);
@@ -253,12 +228,9 @@ bool test_durable_open_oplock(struct torture_context *tctx,
         */
        status = smb2_create(tree2, mem_ctx, &io2);
        CHECK_STATUS(status, NT_STATUS_OK);
+       h2 = io2.out.file.handle;
+       CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
        CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
-       CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED);
-       CHECK_VAL(io2.out.alloc_size, 0);
-       CHECK_VAL(io2.out.size, 0);
-       CHECK_VAL(io2.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
-       CHECK_VAL(io2.out.reserved2, 0);
 
        /* What if tree1 tries to come back and reclaim? */
        if (!torture_smb2_connection(tctx, &tree1)) {
@@ -267,24 +239,349 @@ bool test_durable_open_oplock(struct torture_context 
*tctx,
                goto done;
        }
 
-       ZERO_STRUCT(io2);
-       io2.in.fname = fname;
+       ZERO_STRUCT(io1);
+       io1.in.fname = fname;
+       io1.in.durable_handle = &h1;
+
+       status = smb2_create(tree1, mem_ctx, &io1);
+       CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ done:
+       smb2_util_close(tree2, h2);
+       smb2_util_unlink(tree2, fname);
+
+       return ret;
+}
+
+/*
+  Open, disconnect, lease break, reconnect.
+*/
+bool test_durable_open_lease(struct torture_context *tctx,
+                            struct smb2_tree *tree1,
+                            struct smb2_tree *tree2)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(tctx);
+       struct smb2_create io1, io2;
+       struct smb2_lease ls1, ls2;
+       struct smb2_handle h1, h2;
+       NTSTATUS status;
+       char fname[256];
+       bool ret = true;
+       uint64_t lease1, lease2;
+
+       /*
+        * Choose a random name and random lease in case the state is left a
+        * little funky.
+        */
+       lease1 = random();
+       lease2 = random();
+       snprintf(fname, 256, "durable_open_lease_%s.dat", 
generate_random_str(tctx, 8));
+
+       /* Clean slate */


-- 
Samba Shared Repository

Reply via email to