[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Mon Aug 6 13:55:02 MDT 2012


The branch, master has been updated
       via  721096b s3:smb2_server: make use of smbd_smb2_inbuf_parse_compound() in smbd_smb2_request_read*()
       via  fbd663c s3:smb2_server: make use of smbd_smb2_inbuf_parse_compound() in smbd_smb2_request_create()
       via  9e9d784 s3:smb2_server: remove const from smbd_smb2_first_negprot()
       via  c1b3454 s3:smb2_server: add smbd_smb2_inbuf_parse_compound()
      from  b20fb15 s4:libcli/smb2/write correct error checking

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


- Log -----------------------------------------------------------------
commit 721096b1ad58e97a20896fa74fa8e06013bb8a15
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Aug 5 20:52:55 2012 +0200

    s3:smb2_server: make use of smbd_smb2_inbuf_parse_compound() in smbd_smb2_request_read*()
    
    This changes the way we read SMB2 traffic from the socket,
    now as create just one large buffer for the whole NBT payload
    and then split it into iovec elements in smbd_smb2_inbuf_parse_compound()
    
    metze
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Mon Aug  6 21:54:35 CEST 2012 on sn-devel-104

commit fbd663c1437c104e9bc7f8f51fdef3747a111935
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Aug 5 20:48:51 2012 +0200

    s3:smb2_server: make use of smbd_smb2_inbuf_parse_compound() in smbd_smb2_request_create()
    
    metze

commit 9e9d784def6f0465075e0f0ce6243daaab277d90
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Aug 5 20:46:35 2012 +0200

    s3:smb2_server: remove const from smbd_smb2_first_negprot()
    
    metze

commit c1b345425997bc56a9dffd910b674e6820638337
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Aug 5 19:39:39 2012 +0200

    s3:smb2_server: add smbd_smb2_inbuf_parse_compound()
    
    metze

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

Summary of changes:
 source3/smbd/globals.h     |    8 +-
 source3/smbd/smb2_server.c |  482 ++++++++++++++++++--------------------------
 2 files changed, 200 insertions(+), 290 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index cf9d01b..967fe85 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -219,7 +219,7 @@ bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size);
 void reply_smb2002(struct smb_request *req, uint16_t choice);
 void reply_smb20ff(struct smb_request *req, uint16_t choice);
 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
-			     const uint8_t *inbuf, size_t size);
+			     uint8_t *inbuf, size_t size);
 
 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
 				    NTSTATUS status,
@@ -493,10 +493,8 @@ struct smbd_smb2_request {
 #define SMBD_SMB2_OUT_DYN_LEN(req)   (SMBD_SMB2_OUT_DYN_IOV(req)->iov_len)
 
 	struct {
-		/* the NBT header is not allocated */
-		uint8_t nbt_hdr[4];
 		/*
-		 * vector[0] NBT
+		 * vector[0] TRANSPORT HEADER
 		 * .
 		 * vector[1] SMB2
 		 * vector[2] fixed body
@@ -518,7 +516,7 @@ struct smbd_smb2_request {
 		/* the NBT header is not allocated */
 		uint8_t nbt_hdr[4];
 		/*
-		 * vector[0] NBT
+		 * vector[0] TRANSPORT HEADER
 		 * .
 		 * vector[1] SMB2
 		 * vector[2] fixed body
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 443a8f9..1c19cce 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -180,16 +180,121 @@ static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
 	return req;
 }
 
+static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
+					       NTTIME now,
+					       uint8_t *buf,
+					       size_t buflen,
+					       TALLOC_CTX *mem_ctx,
+					       struct iovec **piov,
+					       int *pnum_iov)
+{
+	struct iovec *iov;
+	int num_iov = 1;
+	size_t taken = 0;
+	uint8_t *first_hdr = buf;
+
+	/*
+	 * Note: index '0' is reserved for the transport protocol
+	 */
+	iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
+	if (iov == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	while (taken < buflen) {
+		size_t len = buflen - taken;
+		uint8_t *hdr = first_hdr + taken;
+		struct iovec *cur;
+		size_t full_size;
+		size_t next_command_ofs;
+		uint16_t body_size;
+		struct iovec *iov_tmp;
+
+		/*
+		 * We need the header plus the body length field
+		 */
+
+		if (len < SMB2_HDR_BODY + 2) {
+			DEBUG(10, ("%d bytes left, expected at least %d\n",
+				   (int)len, SMB2_HDR_BODY));
+			goto inval;
+		}
+		if (IVAL(hdr, 0) != SMB2_MAGIC) {
+			DEBUG(10, ("Got non-SMB2 PDU: %x\n",
+				   IVAL(hdr, 0)));
+			goto inval;
+		}
+		if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
+			DEBUG(10, ("Got HDR len %d, expected %d\n",
+				   SVAL(hdr, 4), SMB2_HDR_BODY));
+			goto inval;
+		}
+
+		full_size = len;
+		next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
+		body_size = SVAL(hdr, SMB2_HDR_BODY);
+
+		if (next_command_ofs != 0) {
+			if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
+				goto inval;
+			}
+			if (next_command_ofs > full_size) {
+				goto inval;
+			}
+			full_size = next_command_ofs;
+		}
+		if (body_size < 2) {
+			goto inval;
+		}
+		body_size &= 0xfffe;
+
+		if (body_size > (full_size - SMB2_HDR_BODY)) {
+			/*
+			 * let the caller handle the error
+			 */
+			body_size = full_size - SMB2_HDR_BODY;
+		}
+
+		iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+					 num_iov + 3);
+		if (iov_tmp == NULL) {
+			TALLOC_FREE(iov);
+			return NT_STATUS_NO_MEMORY;
+		}
+		iov = iov_tmp;
+		cur = &iov[num_iov];
+		num_iov += 3;
+
+		cur[0].iov_base = hdr;
+		cur[0].iov_len  = SMB2_HDR_BODY;
+		cur[1].iov_base = hdr + SMB2_HDR_BODY;
+		cur[1].iov_len  = body_size;
+		cur[2].iov_base = hdr + SMB2_HDR_BODY + body_size;
+		cur[2].iov_len  = full_size - (SMB2_HDR_BODY + body_size);
+
+		taken += full_size;
+	}
+
+	*piov = iov;
+	*pnum_iov = num_iov;
+	return NT_STATUS_OK;
+
+inval:
+	TALLOC_FREE(iov);
+	return NT_STATUS_INVALID_PARAMETER;
+}
+
 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
-					 const uint8_t *inbuf, size_t size,
+					 uint8_t *inbuf, size_t size,
 					 struct smbd_smb2_request **_req)
 {
 	struct smbd_smb2_request *req;
 	uint32_t protocol_version;
 	const uint8_t *inhdr = NULL;
-	off_t ofs = 0;
 	uint16_t cmd;
 	uint32_t next_command_ofs;
+	NTSTATUS status;
+	NTTIME now;
 
 	if (size < (4 + SMB2_HDR_BODY + 2)) {
 		DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
@@ -227,36 +332,20 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
 
 	talloc_steal(req, inbuf);
 
-	req->in.vector = talloc_array(req, struct iovec, 4);
-	if (req->in.vector == NULL) {
+	req->request_time = timeval_current();
+	now = timeval_to_nttime(&req->request_time);
+
+	status = smbd_smb2_inbuf_parse_compound(sconn->conn,
+						now,
+						inbuf + NBT_HDR_SIZE,
+						size - NBT_HDR_SIZE,
+						req, &req->in.vector,
+						&req->in.vector_count);
+	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(req);
-		return NT_STATUS_NO_MEMORY;
-	}
-	req->in.vector_count = 4;
-
-	memcpy(req->in.nbt_hdr, inbuf, 4);
-
-	ofs = 0;
-	req->in.vector[0].iov_base	= discard_const_p(void, req->in.nbt_hdr);
-	req->in.vector[0].iov_len	= 4;
-	ofs += req->in.vector[0].iov_len;
-
-	req->in.vector[1].iov_base	= discard_const_p(void, (inbuf + ofs));
-	req->in.vector[1].iov_len	= SMB2_HDR_BODY;
-	ofs += req->in.vector[1].iov_len;
-
-	req->in.vector[2].iov_base	= discard_const_p(void, (inbuf + ofs));
-	req->in.vector[2].iov_len	= SVAL(inbuf, ofs) & 0xFFFE;
-	ofs += req->in.vector[2].iov_len;
-
-	if (ofs > size) {
-		return NT_STATUS_INVALID_PARAMETER;
+		return status;
 	}
 
-	req->in.vector[3].iov_base	= discard_const_p(void, (inbuf + ofs));
-	req->in.vector[3].iov_len	= size - ofs;
-	ofs += req->in.vector[3].iov_len;
-
 	req->current_idx = 1;
 
 	*_req = req;
@@ -649,8 +738,6 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
 	int count;
 	int idx;
 
-	req->request_time = timeval_current();
-
 	count = req->in.vector_count;
 	vector = talloc_zero_array(req, struct iovec, count);
 	if (vector == NULL) {
@@ -2400,9 +2487,15 @@ static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
 }
 
 struct smbd_smb2_request_read_state {
-	size_t missing;
-	bool asked_for_header;
+	struct tevent_context *ev;
+	struct smbd_server_connection *sconn;
 	struct smbd_smb2_request *smb2_req;
+	struct {
+		uint8_t nbt[NBT_HDR_SIZE];
+		bool done;
+	} hdr;
+	size_t pktlen;
+	uint8_t *pktbuf;
 };
 
 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
@@ -2425,8 +2518,8 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
 	if (req == NULL) {
 		return NULL;
 	}
-	state->missing = 0;
-	state->asked_for_header = false;
+	state->ev = ev;
+	state->sconn = sconn;
 
 	state->smb2_req = smbd_smb2_request_allocate(state);
 	if (tevent_req_nomem(state->smb2_req, req)) {
@@ -2434,10 +2527,12 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
 	}
 	state->smb2_req->sconn = sconn;
 
-	subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
-					      sconn->smb2.recv_queue,
-					      smbd_smb2_request_next_vector,
-					      state);
+	subreq = tstream_readv_pdu_queue_send(state->smb2_req,
+					state->ev,
+					state->sconn->smb2.stream,
+					state->sconn->smb2.recv_queue,
+					smbd_smb2_request_next_vector,
+					state);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
@@ -2455,273 +2550,58 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
 	struct smbd_smb2_request_read_state *state =
 		talloc_get_type_abort(private_data,
 		struct smbd_smb2_request_read_state);
-	struct smbd_smb2_request *req = state->smb2_req;
 	struct iovec *vector;
-	int idx = req->in.vector_count;
-	size_t len = 0;
-	uint8_t *buf = NULL;
-
-	if (req->in.vector_count == 0) {
-		/*
-		 * first we need to get the NBT header
-		 */
-		req->in.vector = talloc_array(req, struct iovec,
-					      req->in.vector_count + 1);
-		if (req->in.vector == NULL) {
-			return -1;
-		}
-		req->in.vector_count += 1;
-
-		req->in.vector[idx].iov_base	= (void *)req->in.nbt_hdr;
-		req->in.vector[idx].iov_len	= 4;
-
-		vector = talloc_array(mem_ctx, struct iovec, 1);
-		if (vector == NULL) {
-			return -1;
-		}
-
-		vector[0] = req->in.vector[idx];
-
-		*_vector = vector;
-		*_count = 1;
-		return 0;
-	}
-
-	if (req->in.vector_count == 1) {
-		/*
-		 * Now we analyze the NBT header
-		 */
-		state->missing = smb2_len(req->in.vector[0].iov_base);
-
-		if (state->missing == 0) {
-			/* if there're no remaining bytes, we're done */
-			*_vector = NULL;
-			*_count = 0;
-			return 0;
-		}
-
-		req->in.vector = talloc_realloc(req, req->in.vector,
-						struct iovec,
-						req->in.vector_count + 1);
-		if (req->in.vector == NULL) {
-			return -1;
-		}
-		req->in.vector_count += 1;
-
-		if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
-			/*
-			 * it's a special NBT message,
-			 * so get all remaining bytes
-			 */
-			len = state->missing;
-		} else if (state->missing < (SMB2_HDR_BODY + 2)) {
-			/*
-			 * it's an invalid message, just read what we can get
-			 * and let the caller handle the error
-			 */
-			len = state->missing;
-		} else {
-			/*
-			 * We assume it's a SMB2 request,
-			 * and we first get the header and the
-			 * first 2 bytes (the struct size) of the body
-			 */
-			len = SMB2_HDR_BODY + 2;
-
-			state->asked_for_header = true;
-		}
-
-		state->missing -= len;
-
-		buf = talloc_array(req->in.vector, uint8_t, len);
-		if (buf == NULL) {
-			return -1;
-		}
-
-		req->in.vector[idx].iov_base	= (void *)buf;
-		req->in.vector[idx].iov_len	= len;
-
-		vector = talloc_array(mem_ctx, struct iovec, 1);
-		if (vector == NULL) {
-			return -1;
-		}
-
-		vector[0] = req->in.vector[idx];
-
-		*_vector = vector;
-		*_count = 1;
-		return 0;
-	}
 
-	if (state->missing == 0) {
+	if (state->pktlen > 0) {
 		/* if there're no remaining bytes, we're done */
 		*_vector = NULL;
 		*_count = 0;
 		return 0;
 	}
 
-	if (state->asked_for_header) {
-		const uint8_t *hdr;
-		size_t full_size;
-		size_t next_command_ofs;
-		size_t body_size;
-		uint8_t *body;
-		size_t dyn_size;
-		uint8_t *dyn;
-		bool invalid = false;
-
-		state->asked_for_header = false;
-
+	if (!state->hdr.done) {
 		/*
-		 * We got the SMB2 header and the first 2 bytes
-		 * of the body. We fix the size to just the header
-		 * and manually copy the 2 first bytes to the body section
+		 * first we need to get the NBT header
 		 */
-		req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
-		hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
-
-		/* allocate vectors for body and dynamic areas */
-		req->in.vector = talloc_realloc(req, req->in.vector,
-						struct iovec,
-						req->in.vector_count + 2);
-		if (req->in.vector == NULL) {
-			return -1;
-		}
-		req->in.vector_count += 2;
-
-		full_size = state->missing + SMB2_HDR_BODY + 2;
-		next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
-		body_size = SVAL(hdr, SMB2_HDR_BODY);
-
-		if (next_command_ofs != 0) {
-			if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
-				/*
-				 * this is invalid, just return a zero
-				 * body and let the caller deal with the error
-				 */
-				invalid = true;
-			} else if (next_command_ofs > full_size) {
-				/*
-				 * this is invalid, just return a zero
-				 * body and let the caller deal with the error
-				 */
-				invalid = true;
-			} else {
-				full_size = next_command_ofs;
-			}
-		}
-
-		if (!invalid) {
-			if (body_size < 2) {
-				/*
-				 * this is invalid, just return a zero
-				 * body and let the caller deal with the error
-				 */
-				invalid = true;
-			}
-
-			/*
-			 * Mask out the lowest bit, the "dynamic" part
-			 * of body_size.
-			 */
-			body_size &= ~1;
-
-			if (body_size > (full_size - SMB2_HDR_BODY)) {
-				/*
-				 * this is invalid, just return a zero
-				 * body and let the caller deal with the error
-				 */
-				invalid = true;
-			}
-		}
-
-		if (invalid) {
-			/* the caller should check this */
-			body_size = 2;
-		}
-
-		dyn_size = full_size - (SMB2_HDR_BODY + body_size);
-
-		state->missing -= (body_size - 2) + dyn_size;
-
-		body = talloc_array(req->in.vector, uint8_t, body_size);
-		if (body == NULL) {
-			return -1;
-		}
-
-		dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
-		if (dyn == NULL) {
-			return -1;
-		}
-
-		req->in.vector[idx].iov_base	= (void *)body;
-		req->in.vector[idx].iov_len	= body_size;
-		req->in.vector[idx+1].iov_base	= (void *)dyn;
-		req->in.vector[idx+1].iov_len	= dyn_size;
-
-		vector = talloc_array(mem_ctx, struct iovec, 2);
+		vector = talloc_array(mem_ctx, struct iovec, 1);
 		if (vector == NULL) {
 			return -1;
 		}
 
-		/*
-		 * the first 2 bytes of the body were already fetched
-		 * together with the header
-		 */
-		memcpy(body, hdr + SMB2_HDR_BODY, 2);
-		vector[0].iov_base = body + 2;
-		vector[0].iov_len = body_size - 2;
-
-		vector[1] = req->in.vector[idx+1];
+		vector[0].iov_base = (void *)state->hdr.nbt;
+		vector[0].iov_len = NBT_HDR_SIZE;
 
 		*_vector = vector;
-		*_count = 2;
-		return 0;
-	}
-
-	/*


-- 
Samba Shared Repository


More information about the samba-cvs mailing list