$OpenBSD: patch-source3_rpc_client_cli_pipe_c,v 1.2 2014/04/10 00:50:58 brad Exp $

DCE-RPC fragment length field is incorrectly checked.
CVE-2013-4408

--- source3/rpc_client/cli_pipe.c.orig	Wed May  8 04:16:26 2013
+++ source3/rpc_client/cli_pipe.c	Wed Apr  9 17:25:42 2014
@@ -235,6 +235,7 @@ struct get_complete_frag_state {
 	struct event_context *ev;
 	struct rpc_pipe_client *cli;
 	uint16_t frag_len;
+	uint32_t call_id;
 	DATA_BLOB *pdu;
 };
 
@@ -244,6 +245,7 @@ static void get_complete_frag_got_rest(struct tevent_r
 static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
 						 struct event_context *ev,
 						 struct rpc_pipe_client *cli,
+						 uint32_t call_id,
 						 DATA_BLOB *pdu)
 {
 	struct tevent_req *req, *subreq;
@@ -259,6 +261,7 @@ static struct tevent_req *get_complete_frag_send(TALLO
 	state->ev = ev;
 	state->cli = cli;
 	state->frag_len = RPC_HEADER_LEN;
+	state->call_id = call_id;
 	state->pdu = pdu;
 
 	received = pdu->length;
@@ -282,6 +285,11 @@ static struct tevent_req *get_complete_frag_send(TALLO
 
 	state->frag_len = dcerpc_get_frag_length(pdu);
 
+	if (state->call_id != dcerpc_get_call_id(pdu)) {
+		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+		return tevent_req_post(req, ev);
+	}
+
 	/*
 	 * Ensure we have frag_len bytes of data.
 	 */
@@ -330,6 +338,11 @@ static void get_complete_frag_got_header(struct tevent
 
 	state->frag_len = dcerpc_get_frag_length(state->pdu);
 
+	if (state->call_id != dcerpc_get_call_id(state->pdu)) {
+		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+		return;
+	}
+
 	if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) {
 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
 		return;
@@ -690,6 +703,7 @@ struct rpc_api_pipe_state {
 	struct event_context *ev;
 	struct rpc_pipe_client *cli;
 	uint8_t expected_pkt_type;
+	uint32_t call_id;
 
 	DATA_BLOB incoming_frag;
 	struct ncacn_packet *pkt;
@@ -708,7 +722,8 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX
 					    struct event_context *ev,
 					    struct rpc_pipe_client *cli,
 					    DATA_BLOB *data, /* Outgoing PDU */
-					    uint8_t expected_pkt_type)
+					    uint8_t expected_pkt_type,
+					    uint32_t call_id)
 {
 	struct tevent_req *req, *subreq;
 	struct rpc_api_pipe_state *state;
@@ -722,6 +737,7 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX
 	state->ev = ev;
 	state->cli = cli;
 	state->expected_pkt_type = expected_pkt_type;
+	state->call_id = call_id;
 	state->incoming_frag = data_blob_null;
 	state->reply_pdu = data_blob_null;
 	state->reply_pdu_offset = 0;
@@ -821,6 +837,7 @@ static void rpc_api_pipe_trans_done(struct tevent_req 
 
 	/* Ensure we have enough data for a pdu. */
 	subreq = get_complete_frag_send(state, state->ev, state->cli,
+					state->call_id,
 					&state->incoming_frag);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
@@ -940,6 +957,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *su
 	}
 
 	subreq = get_complete_frag_send(state, state->ev, state->cli,
+					state->call_id,
 					&state->incoming_frag);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
@@ -1292,7 +1310,8 @@ struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *m
 	if (is_last_frag) {
 		subreq = rpc_api_pipe_send(state, ev, state->cli,
 					   &state->rpc_out,
-					   DCERPC_PKT_RESPONSE);
+					   DCERPC_PKT_RESPONSE,
+					   state->call_id);
 		if (subreq == NULL) {
 			goto fail;
 		}
@@ -1428,7 +1447,8 @@ static void rpc_api_pipe_req_write_done(struct tevent_
 	if (is_last_frag) {
 		subreq = rpc_api_pipe_send(state, state->ev, state->cli,
 					   &state->rpc_out,
-					   DCERPC_PKT_RESPONSE);
+					   DCERPC_PKT_RESPONSE,
+					   state->call_id);
 		if (tevent_req_nomem(subreq, req)) {
 			return;
 		}
@@ -1667,7 +1687,7 @@ struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_
 	}
 
 	subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
-				   DCERPC_PKT_BIND_ACK);
+				   DCERPC_PKT_BIND_ACK, state->rpc_call_id);
 	if (subreq == NULL) {
 		goto fail;
 	}
@@ -1865,7 +1885,8 @@ static NTSTATUS rpc_bind_next_send(struct tevent_req *
 	}
 
 	subreq = rpc_api_pipe_send(state, state->ev, state->cli,
-				   &state->rpc_out, DCERPC_PKT_ALTER_RESP);
+				   &state->rpc_out, DCERPC_PKT_ALTER_RESP,
+				   state->rpc_call_id);
 	if (subreq == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -1897,7 +1918,8 @@ static NTSTATUS rpc_bind_finish_send(struct tevent_req
 	}
 
 	subreq = rpc_api_pipe_send(state, state->ev, state->cli,
-				   &state->rpc_out, DCERPC_PKT_AUTH3);
+				   &state->rpc_out, DCERPC_PKT_AUTH3,
+				   state->rpc_call_id);
 	if (subreq == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
