[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha7-808-g91e75ea

Tim Prouty tprouty at samba.org
Wed Apr 1 16:20:23 GMT 2009


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 <zachary.loafman at isilon.com>
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 <zachary.loafman at isilon.com>
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


More information about the samba-cvs mailing list