STEP01: global fragment checking librpc/rpc/dcerpc_connection.
authorStefan Metzmacher <metze@samba.org>
Fri, 17 Jan 2014 18:10:09 +0000 (19:10 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 10:45:39 +0000 (12:45 +0200)
TODO verify header, reassemle? 4MB?

librpc/rpc/dcerpc_connection.c

index c72ac47c7eba84c55e0335cf2393b86ddf609dc8..93f0c68fe43a8eee0cefb3391300f7c7bfe5addb 100644 (file)
@@ -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) {