From: Stefan Metzmacher Date: Fri, 17 Jan 2014 18:10:09 +0000 (+0100) Subject: STEP01: global fragment checking librpc/rpc/dcerpc_connection. X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=ff8514f245462962b4c9c727ba03b6b8602dab5e;hp=59200557219a873524f0b781b3a44997daab3650;p=metze%2Fsamba%2Fwip.git STEP01: global fragment checking librpc/rpc/dcerpc_connection. TODO verify header, reassemle? 4MB? --- diff --git a/librpc/rpc/dcerpc_connection.c b/librpc/rpc/dcerpc_connection.c index c72ac47c7eba..93f0c68fe43a 100644 --- a/librpc/rpc/dcerpc_connection.c +++ b/librpc/rpc/dcerpc_connection.c @@ -696,6 +696,7 @@ static void dcerpc_connection_loop(struct tevent_req *subreq) DATA_BLOB pdu; struct dcerpc_call *call; bool valid_type = false; + bool allow_fragments = false; conn->loop.subreq = NULL; @@ -714,6 +715,7 @@ static void dcerpc_connection_loop(struct tevent_req *subreq) case DCERPC_PKT_REQUEST: /* Ordinary request. */ valid_type = true; + allow_fragments = true; break; case DCERPC_PKT_PING: @@ -723,6 +725,7 @@ static void dcerpc_connection_loop(struct tevent_req *subreq) case DCERPC_PKT_RESPONSE: /* Ordinary reply. */ valid_type = true; + allow_fragments = true; break; case DCERPC_PKT_FAULT: @@ -811,14 +814,40 @@ static void dcerpc_connection_loop(struct tevent_req *subreq) return; } + if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) { + if (!allow_fragments) { + TALLOC_FREE(subreq); + // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR; + return; + } + } + if (conn->calls.active != NULL) { + if (pkt->call_id != conn->calls.active->call_id) { TALLOC_FREE(subreq); // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR; return; } + + if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) { + TALLOC_FREE(subreq); + // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR; + return; + } + call = conn->calls.active; + + if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) { + conn->calls.active = NULL; + } } else { + if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) { + TALLOC_FREE(subreq); + // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR; + return; + } + call = conn->calls.list; } @@ -844,6 +873,14 @@ static void dcerpc_connection_loop(struct tevent_req *subreq) return; } + if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) { + conn->calls.active = call; + + // TODO + // + // reassemble and return + } + error = call->incoming.handler(call->incoming.private_data, pkt, pdu); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(error)) { @@ -2338,12 +2375,6 @@ static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data, if (!state->got_first) { state->got_first = true; - if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) { - return NT_STATUS_RPC_PROTOCOL_ERROR; - } - - state->conn->calls.active = state->call; - if (pkt->drep[0] & DCERPC_DREP_LE) { state->response.bigendian = false; } else { @@ -2357,10 +2388,6 @@ static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data, if (state->verify_pcontext) { state->call->pres->verified_pcontext = true; } - } else { - if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) { - return NT_STATUS_RPC_PROTOCOL_ERROR; - } } if (state->response.bigendian) {