[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha7-2188-gba42ccc

Stefan Metzmacher metze at samba.org
Tue Jun 9 15:04:09 GMT 2009


The branch, master has been updated
       via  ba42cccf008bfeb2bb4621fef7882bd3077dfe41 (commit)
       via  959503ed1ac76c4ebb8d7941a3a2462ae93869c4 (commit)
       via  f55091586dd2112bf94ff8d352b2ac43b6db0521 (commit)
       via  7633995fa08149fae9b1e281e1b5e2500b0a5572 (commit)
       via  7b27b5f6740e6d0d90f467a575ccbd2fdff7ea01 (commit)
       via  d153430e32ba8651feb9a626613c46a4a60c7bbf (commit)
       via  5b99fa5c4fb1a21caa6da747f8ee9db737990432 (commit)
       via  d777879aaa3d86cd31fe5d1e0bbd15b9ee02e5cb (commit)
       via  81275c84d31b9939bd2e8e6c56cf2c0498468a31 (commit)
      from  72fd5fa6bb78a054fad5e5ebe19a0c0387a7d45b (commit)

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


- Log -----------------------------------------------------------------
commit ba42cccf008bfeb2bb4621fef7882bd3077dfe41
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 8 16:26:57 2009 +0200

    s4:torture: add SMB2-COMPOUND test
    
    metze

commit 959503ed1ac76c4ebb8d7941a3a2462ae93869c4
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 16:48:25 2009 +0200

    s4:smb2srv: correctly fail remaining compounded requests after a failure
    
    metze

commit f55091586dd2112bf94ff8d352b2ac43b6db0521
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 16:35:25 2009 +0200

    s4:smb2srv: remove old TODO comment, we already check the seqnum
    
    metze

commit 7633995fa08149fae9b1e281e1b5e2500b0a5572
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 16:34:52 2009 +0200

    s4:smb2srv: fix handling of multiple compounded requests
    
    metze

commit 7b27b5f6740e6d0d90f467a575ccbd2fdff7ea01
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 16:33:46 2009 +0200

    s4:smb2srv: remove the chained file handle on close
    
    metze

commit d153430e32ba8651feb9a626613c46a4a60c7bbf
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 8 17:59:26 2009 +0200

    s4:libcli/smb2: add smb2_transport_credits_ask_num()
    
    metze

commit 5b99fa5c4fb1a21caa6da747f8ee9db737990432
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 15:04:53 2009 +0200

    s4:libcli/smb2: only add the 1 byte dynamic buffer padding for non compounded requests
    
    metze

commit d777879aaa3d86cd31fe5d1e0bbd15b9ee02e5cb
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 8 16:24:27 2009 +0200

    s4:libcli/smb2: add support sending compounded requests
    
    metze

commit 81275c84d31b9939bd2e8e6c56cf2c0498468a31
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 14:52:44 2009 +0200

    s4:libcli/smb2: prepare SMB2 signing code for compounded requests
    
    metze

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

Summary of changes:
 source4/libcli/smb2/request.c         |   46 +++++--
 source4/libcli/smb2/signing.c         |   10 +-
 source4/libcli/smb2/smb2.h            |   69 ++++++----
 source4/libcli/smb2/transport.c       |  163 ++++++++++++++++++++--
 source4/smb_server/smb2/fileio.c      |    4 +
 source4/smb_server/smb2/receive.c     |   37 ++++--
 source4/smb_server/smb2/smb2_server.h |    3 +
 source4/torture/smb2/compound.c       |  242 +++++++++++++++++++++++++++++++++
 source4/torture/smb2/config.mk        |    3 +-
 source4/torture/smb2/smb2.c           |    1 +
 10 files changed, 509 insertions(+), 69 deletions(-)
 create mode 100644 source4/torture/smb2/compound.c


Changeset truncated at 500 lines:

diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c
index 649a1db..f3684ed 100644
--- a/source4/libcli/smb2/request.c
+++ b/source4/libcli/smb2/request.c
@@ -63,6 +63,9 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
 {
 	struct smb2_request *req;
 	uint64_t seqnum;
+	uint32_t hdr_offset;
+	uint32_t flags = 0;
+	bool compound = false;
 
 	if (body_dynamic_present) {
 		if (body_dynamic_size == 0) {
@@ -92,16 +95,35 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
 	ZERO_STRUCT(req->cancel);
 	ZERO_STRUCT(req->in);
 
-	req->out.size      = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
+	if (transport->compound.missing > 0) {
+		compound = true;
+		transport->compound.missing -= 1;
+		req->out = transport->compound.buffer;
+		ZERO_STRUCT(transport->compound.buffer);
+		if (transport->compound.related) {
+			flags |= SMB2_HDR_FLAG_CHAINED;
+		}
+	} else {
+		ZERO_STRUCT(req->out);
+	}
+
+	if (req->out.size > 0) {
+		hdr_offset = req->out.size;
+	} else {
+		hdr_offset = NBT_HDR_SIZE;
+	}
 
+	req->out.size      = hdr_offset + SMB2_HDR_BODY + body_fixed_size;
 	req->out.allocated = req->out.size + body_dynamic_size;
-	req->out.buffer    = talloc_array(req, uint8_t, req->out.allocated);
+
+	req->out.buffer = talloc_realloc(req, req->out.buffer,
+					 uint8_t, req->out.allocated);
 	if (req->out.buffer == NULL) {
 		talloc_free(req);
 		return NULL;
 	}
 
-	req->out.hdr       = req->out.buffer + NBT_HDR_SIZE;
+	req->out.hdr       = req->out.buffer + hdr_offset;
 	req->out.body      = req->out.hdr + SMB2_HDR_BODY;
 	req->out.body_fixed= body_fixed_size;
 	req->out.body_size = body_fixed_size;
@@ -112,10 +134,10 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
 	SSVAL(req->out.hdr, SMB2_HDR_EPOCH,		0);
 	SIVAL(req->out.hdr, SMB2_HDR_STATUS,		0);
 	SSVAL(req->out.hdr, SMB2_HDR_OPCODE,		opcode);
-	SSVAL(req->out.hdr, SMB2_HDR_CREDIT,		0);
-	SIVAL(req->out.hdr, SMB2_HDR_FLAGS,		0);
+	SSVAL(req->out.hdr, SMB2_HDR_CREDIT,		transport->credits.ask_num);
+	SIVAL(req->out.hdr, SMB2_HDR_FLAGS,		flags);
 	SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND,	0);
-	SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID,		req->seqnum);
+	SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID,	req->seqnum);
 	SIVAL(req->out.hdr, SMB2_HDR_PID,		0);
 	SIVAL(req->out.hdr, SMB2_HDR_TID,		0);
 	SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID,		0);
@@ -128,7 +150,7 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
 	 * if we have a dynamic part, make sure the first byte
 	 * which is always be part of the packet is initialized
 	 */
-	if (body_dynamic_size) {
+	if (body_dynamic_size && !compound) {
 		req->out.size += 1;
 		SCVAL(req->out.dynamic, 0, 0);
 	}
@@ -237,7 +259,9 @@ size_t smb2_padding_size(uint32_t offset, size_t n)
 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
 {
 	if (buf->dynamic == (buf->body + buf->body_fixed)) {
-		return 1;
+		if (buf->dynamic != (buf->buffer + buf->size)) {
+			return 1;
+		}
 	}
 	return 0;
 }
@@ -245,8 +269,9 @@ static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
 /*
   grow a SMB2 buffer by the specified amount
 */
-static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
+NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
 {
+	size_t hdr_ofs;
 	size_t dynamic_ofs;
 	uint8_t *buffer_ptr;
 	uint32_t newsize = buf->size + increase;
@@ -256,13 +281,14 @@ static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increas
 
 	if (newsize <= buf->allocated) return NT_STATUS_OK;
 
+	hdr_ofs = buf->hdr - buf->buffer;
 	dynamic_ofs = buf->dynamic - buf->buffer;
 
 	buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
 	NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
 
 	buf->buffer	= buffer_ptr;
-	buf->hdr	= buf->buffer + NBT_HDR_SIZE;
+	buf->hdr	= buf->buffer + hdr_ofs;
 	buf->body	= buf->hdr    + SMB2_HDR_BODY;
 	buf->dynamic	= buf->buffer + dynamic_ofs;
 	buf->allocated	= newsize;
diff --git a/source4/libcli/smb2/signing.c b/source4/libcli/smb2/signing.c
index 101fb00..6af7a6d 100644
--- a/source4/libcli/smb2/signing.c
+++ b/source4/libcli/smb2/signing.c
@@ -33,12 +33,15 @@ NTSTATUS smb2_sign_message(struct smb2_request_buffer *buf, DATA_BLOB session_ke
 	struct HMACSHA256Context m;
 	uint8_t res[32];
 	uint64_t session_id;
+	size_t hdr_offset;
 
 	if (buf->size < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
 		/* can't sign non-SMB2 messages */
 		return NT_STATUS_OK;
 	}
 
+	hdr_offset = buf->hdr - buf->buffer;
+
 	session_id = BVAL(buf->hdr, SMB2_HDR_SESSION_ID);
 	if (session_id == 0) {
 		/* we don't sign messages with a zero session_id. See
@@ -58,7 +61,7 @@ NTSTATUS smb2_sign_message(struct smb2_request_buffer *buf, DATA_BLOB session_ke
 
 	ZERO_STRUCT(m);
 	hmac_sha256_init(session_key.data, MIN(session_key.length, 16), &m);
-	hmac_sha256_update(buf->buffer+NBT_HDR_SIZE, buf->size-NBT_HDR_SIZE, &m);
+	hmac_sha256_update(buf->hdr, buf->size-hdr_offset, &m);
 	hmac_sha256_final(res, &m);
 	DEBUG(5,("signed SMB2 message of size %u\n", (unsigned)buf->size - NBT_HDR_SIZE));
 
@@ -76,12 +79,15 @@ NTSTATUS smb2_check_signature(struct smb2_request_buffer *buf, DATA_BLOB session
 	struct HMACSHA256Context m;
 	uint8_t res[SHA256_DIGEST_LENGTH];
 	uint8_t sig[16];
+	size_t hdr_offset;
 
 	if (buf->size < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
 		/* can't check non-SMB2 messages */
 		return NT_STATUS_OK;
 	}
 
+	hdr_offset = buf->hdr - buf->buffer;
+
 	session_id = BVAL(buf->hdr, SMB2_HDR_SESSION_ID);
 	if (session_id == 0) {
 		/* don't sign messages with a zero session_id. See
@@ -100,7 +106,7 @@ NTSTATUS smb2_check_signature(struct smb2_request_buffer *buf, DATA_BLOB session
 
 	ZERO_STRUCT(m);
 	hmac_sha256_init(session_key.data, MIN(session_key.length, 16), &m);
-	hmac_sha256_update(buf->hdr, buf->size-NBT_HDR_SIZE, &m);
+	hmac_sha256_update(buf->hdr, buf->size-hdr_offset, &m);
 	hmac_sha256_final(res, &m);
 
 	memcpy(buf->hdr+SMB2_HDR_SIGNATURE, sig, 16);
diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h
index f1c8321..eb23198 100644
--- a/source4/libcli/smb2/smb2.h
+++ b/source4/libcli/smb2/smb2.h
@@ -40,6 +40,35 @@ struct smb2_negotiate {
 	uint16_t dialect_revision;
 };
 
+struct smb2_request_buffer {
+	/* the raw SMB2 buffer, including the 4 byte length header */
+	uint8_t *buffer;
+
+	/* the size of the raw buffer, including 4 byte header */
+	size_t size;
+
+	/* how much has been allocated - on reply the buffer is over-allocated to
+	   prevent too many realloc() calls
+	*/
+	size_t allocated;
+
+	/* the start of the SMB2 header - this is always buffer+4 */
+	uint8_t *hdr;
+
+	/* the packet body */
+	uint8_t *body;
+	size_t body_fixed;
+	size_t body_size;
+
+	/* this point to the next dynamic byte that can be used
+	 * this will be moved when some dynamic data is pushed
+	 */
+	uint8_t *dynamic;
+
+	/* this is used to range check and align strings and buffers */
+	struct request_bufinfo bufinfo;
+};
+
 /* this is the context for the smb2 transport layer */
 struct smb2_transport {
 	/* socket level info */
@@ -50,6 +79,17 @@ struct smb2_transport {
 	/* next seqnum to allocate */
 	uint64_t seqnum;
 
+	/* the details for coumpounded requests */
+	struct {
+		uint32_t missing;
+		bool related;
+		struct smb2_request_buffer buffer;
+	} compound;
+
+	struct {
+		uint16_t ask_num;
+	} credits;
+
 	/* a list of requests that are pending for receive on this
 	   connection */
 	struct smb2_request *pending_recv;
@@ -110,35 +150,6 @@ struct smb2_session {
 };
 
 
-struct smb2_request_buffer {
-	/* the raw SMB2 buffer, including the 4 byte length header */
-	uint8_t *buffer;
-	
-	/* the size of the raw buffer, including 4 byte header */
-	size_t size;
-	
-	/* how much has been allocated - on reply the buffer is over-allocated to 
-	   prevent too many realloc() calls 
-	*/
-	size_t allocated;
-	
-	/* the start of the SMB2 header - this is always buffer+4 */
-	uint8_t *hdr;
-	
-	/* the packet body */
-	uint8_t *body;
-	size_t body_fixed;
-	size_t body_size;
-
-	/* this point to the next dynamic byte that can be used
-	 * this will be moved when some dynamic data is pushed
-	 */
-	uint8_t *dynamic;
-
-	/* this is used to range check and align strings and buffers */
-	struct request_bufinfo bufinfo;
-};
-
 
 /*
   a client request moves between the following 4 states.
diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c
index 6a87d12..6052237 100644
--- a/source4/libcli/smb2/transport.c
+++ b/source4/libcli/smb2/transport.c
@@ -84,6 +84,7 @@ struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock,
 
 	transport->socket = talloc_steal(transport, sock);
 	transport->options = *options;
+	transport->credits.ask_num = 1;
 
 	/* setup the stream -> packet parser */
 	transport->packet = packet_init(transport);
@@ -208,6 +209,28 @@ static NTSTATUS smb2_handle_oplock_break(struct smb2_transport *transport,
 	return NT_STATUS_OK;
 }
 
+struct smb2_transport_compount_response_state {
+	struct smb2_transport *transport;
+	DATA_BLOB blob;
+};
+
+static void smb2_transport_compound_response_handler(struct tevent_context *ctx,
+						     struct tevent_immediate *im,
+						     void *private_data)
+{
+	struct smb2_transport_compount_response_state *state =
+		talloc_get_type_abort(private_data,
+		struct smb2_transport_compount_response_state);
+	struct smb2_transport *transport = state->transport;
+	NTSTATUS status;
+
+	status = smb2_transport_finish_recv(transport, state->blob);
+	TALLOC_FREE(state);
+	if (!NT_STATUS_IS_OK(status)) {
+		smb2_transport_error(transport, status);
+	}
+}
+
 /*
   we have a full request in our receive buffer - match it to a pending request
   and process
@@ -226,6 +249,7 @@ static NTSTATUS smb2_transport_finish_recv(void *private_data, DATA_BLOB blob)
 	uint32_t i;
 	uint16_t opcode;
 	NTSTATUS status;
+	uint32_t next_ofs;
 
 	buffer = blob.data;
 	len = blob.length;
@@ -285,6 +309,18 @@ static NTSTATUS smb2_transport_finish_recv(void *private_data, DATA_BLOB blob)
 		return NT_STATUS_OK;
 	}
 
+	next_ofs = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND);
+	if (next_ofs > 0) {
+		if (smb2_oob(&req->in, req->in.hdr + next_ofs, SMB2_HDR_BODY + 2)) {
+			DEBUG(1,("SMB2 request invalid next offset 0x%x\n",
+				 next_ofs));
+			goto error;
+		}
+
+		req->in.size = NBT_HDR_SIZE + next_ofs;
+		req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
+	}
+
 	if (req->session && req->session->signing_active) {
 		status = smb2_check_signature(&req->in, 
 					      req->session->session_key);
@@ -313,6 +349,36 @@ static NTSTATUS smb2_transport_finish_recv(void *private_data, DATA_BLOB blob)
 	DEBUG(2, ("SMB2 RECV seqnum=0x%llx\n", (long long)req->seqnum));
 	dump_data(5, req->in.body, req->in.body_size);
 
+	if (next_ofs > 0) {
+		struct tevent_immediate *im;
+		struct smb2_transport_compount_response_state *state;
+
+		state = talloc(transport,
+			       struct smb2_transport_compount_response_state);
+		if (!state) {
+			goto error;
+		}
+		state->transport = transport;
+
+		state->blob = data_blob_talloc(state, NULL,
+					       blob.length - next_ofs);
+		if (!state->blob.data) {
+			goto error;
+		}
+		im = tevent_create_immediate(state);
+		if (!im) {
+			TALLOC_FREE(state);
+			goto error;
+		}
+		_smb2_setlen(state->blob.data, state->blob.length - NBT_HDR_SIZE);
+		memcpy(state->blob.data + NBT_HDR_SIZE,
+		       req->in.hdr + next_ofs,
+		       req->in.allocated - req->in.size);
+		tevent_schedule_immediate(im, transport->socket->event.ctx,
+					  smb2_transport_compound_response_handler,
+					  state);
+	}
+
 	/* if this request has an async handler then call that to
 	   notify that the reply has been received. This might destroy
 	   the request so it must happen last */
@@ -367,25 +433,67 @@ static int smb2_request_destructor(struct smb2_request *req)
 	return 0;
 }
 
+static NTSTATUS smb2_transport_raw_send(struct smb2_transport *transport,
+					struct smb2_request_buffer *buffer)
+{
+	DATA_BLOB blob;
+	NTSTATUS status;
+
+	/* check if the transport is dead */
+	if (transport->socket->sock == NULL) {
+		return NT_STATUS_NET_WRITE_FAULT;
+	}
+
+	_smb2_setlen(buffer->buffer, buffer->size - NBT_HDR_SIZE);
+	blob = data_blob_const(buffer->buffer, buffer->size);
+	status = packet_send(transport->packet, blob);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	return NT_STATUS_OK;
+}
 
 /*
   put a request into the send queue
 */
 void smb2_transport_send(struct smb2_request *req)
 {
-	DATA_BLOB blob;
 	NTSTATUS status;
 
-	_smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
-
 	DEBUG(2, ("SMB2 send seqnum=0x%llx\n", (long long)req->seqnum));
 	dump_data(5, req->out.body, req->out.body_size);
 
-	/* check if the transport is dead */
-	if (req->transport->socket->sock == NULL) {
-		req->state = SMB2_REQUEST_ERROR;
-		req->status = NT_STATUS_NET_WRITE_FAULT;
-		return;
+	if (req->transport->compound.missing > 0) {
+		off_t next_ofs;
+		size_t pad = 0;
+		uint8_t *end;
+
+		end = req->out.buffer + req->out.size;
+
+		/*
+		 * we need to set dynamic otherwise
+		 * smb2_grow_buffer segfaults
+		 */
+		if (req->out.dynamic == NULL) {
+			req->out.dynamic = end;
+		}
+
+		next_ofs = end - req->out.hdr;
+		if ((next_ofs % 8) > 0) {
+			pad = 8 - (next_ofs % 8);
+		}
+		next_ofs += pad;
+
+		status = smb2_grow_buffer(&req->out, pad);
+		if (!NT_STATUS_IS_OK(status)) {
+			req->state = SMB2_REQUEST_ERROR;
+			req->status = status;
+			return;
+		}
+		req->out.size += pad;
+
+		SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, next_ofs);
 	}
 
 	/* possibly sign the message */
@@ -397,14 +505,19 @@ void smb2_transport_send(struct smb2_request *req)
 			return;
 		}
 	}
-	
-	blob = data_blob_const(req->out.buffer, req->out.size);
-	status = packet_send(req->transport->packet, blob);
-	if (!NT_STATUS_IS_OK(status)) {
-		req->state = SMB2_REQUEST_ERROR;
-		req->status = status;
-		return;
+
+	if (req->transport->compound.missing > 0) {
+		req->transport->compound.buffer = req->out;
+	} else {
+		status = smb2_transport_raw_send(req->transport,
+						 &req->out);
+		if (!NT_STATUS_IS_OK(status)) {
+			req->state = SMB2_REQUEST_ERROR;
+			req->status = status;
+			return;
+		}
 	}
+	ZERO_STRUCT(req->out);
 
 	req->state = SMB2_REQUEST_RECV;
 	DLIST_ADD(req->transport->pending_recv, req);
@@ -419,6 +532,26 @@ void smb2_transport_send(struct smb2_request *req)
 	talloc_set_destructor(req, smb2_request_destructor);
 }
 
+NTSTATUS smb2_transport_compound_start(struct smb2_transport *transport,
+				       uint32_t num)
+{
+	ZERO_STRUCT(transport->compound);
+	transport->compound.missing = num;
+	return NT_STATUS_OK;
+}
+
+void smb2_transport_compound_set_related(struct smb2_transport *transport,
+					 bool related)
+{
+	transport->compound.related = related;
+}
+
+void smb2_transport_credits_ask_num(struct smb2_transport *transport,
+				    uint16_t ask_num)
+{
+	transport->credits.ask_num = ask_num;
+}
+
 static void idle_handler(struct tevent_context *ev, 
 			 struct tevent_timer *te, struct timeval t, void *private_data)
 {
diff --git a/source4/smb_server/smb2/fileio.c b/source4/smb_server/smb2/fileio.c
index bb894b2..12bfd51 100644
--- a/source4/smb_server/smb2/fileio.c


-- 
Samba Shared Repository


More information about the samba-cvs mailing list