source4/librpc/rpc/dcerpc.c bla...
authorStefan Metzmacher <metze@samba.org>
Wed, 18 Sep 2013 00:00:42 +0000 (02:00 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 11:14:55 +0000 (13:14 +0200)
source4/librpc/rpc/dcerpc.c

index 013531a5a722fde5b8433fec25b27ccea10fb2ae..03bcbea8004faf758422723362785f6a5a166d9d 100644 (file)
@@ -63,12 +63,15 @@ struct rpc_request {
        const struct GUID *object;
        uint16_t opnum;
        DATA_BLOB request_data;
+       bool request_data_allocated;
+       struct tevent_req *stub_subreq;
        bool ignore_timeout;
        bool wait_for_sync;
        bool verify_bitmask1;
        bool verify_pcontext;
        bool first_pdu_done;
        bool incomplete_request_data;
+       bool last_pdu_done;
 
        struct {
                void (*callback)(struct rpc_request *);
@@ -234,9 +237,11 @@ static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
 struct dcerpc_bh_raw_call_state {
        struct tevent_context *ev;
        struct dcerpc_binding_handle *h;
+       uint32_t in_flags;
        DATA_BLOB in_data;
        DATA_BLOB out_data;
        uint32_t out_flags;
+       struct rpc_request *subreq;
 };
 
 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
@@ -255,7 +260,6 @@ static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req;
        struct dcerpc_bh_raw_call_state *state;
        bool ok;
-       struct rpc_request *subreq;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct dcerpc_bh_raw_call_state);
@@ -264,6 +268,7 @@ static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
        }
        state->ev = ev;
        state->h = h;
+       state->in_flags = in_flags;
        state->in_data.data = discard_const_p(uint8_t, in_data);
        state->in_data.length = in_length;
 
@@ -273,16 +278,20 @@ static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       subreq = dcerpc_request_send(state,
-                                    hs->p,
-                                    object,
-                                    opnum,
-                                    &state->in_data);
-       if (tevent_req_nomem(subreq, req)) {
+       state->subreq = dcerpc_request_send(state,
+                                           hs->p,
+                                           object,
+                                           opnum,
+                                           &state->in_data);
+       if (tevent_req_nomem(state->subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       subreq->async.callback = dcerpc_bh_raw_call_done;
-       subreq->async.private_data = req;
+       state->subreq->async.callback = dcerpc_bh_raw_call_done;
+       state->subreq->async.private_data = req;
+
+       if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+               state->subreq->incomplete_request_data = true;
+       }
 
        return req;
 }
@@ -303,6 +312,13 @@ static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
                state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
+       if (subreq->state == RPC_REQUEST_PENDING) {
+               state->out_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
+       } else {
+               state->subreq = NULL;
+               state->out_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
+       }
+
        fault_code = subreq->fault_code;
 
        status = dcerpc_request_recv(subreq, state, &state->out_data);
@@ -327,6 +343,11 @@ static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
                return;
        }
 
+       if (state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+               tevent_req_notify_callback(req);
+               return;
+       }
+
        tevent_req_done(req);
 }
 
@@ -349,10 +370,52 @@ static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
        *out_data = talloc_move(mem_ctx, &state->out_data.data);
        *out_length = state->out_data.length;
        *out_flags = state->out_flags;
-       tevent_req_received(req);
+       if (!(state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
+               tevent_req_received(req);
+       }
        return NT_STATUS_OK;
 }
 
+struct dcerpc_bh_raw_call_in_state {
+
+};
+
+static struct tevent_req *dcerpc_bh_raw_call_in_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct tevent_req *raw_call_req,
+                                       uint32_t in_flags,
+                                       const uint8_t *in_data,
+                                       size_t in_length)
+{
+       struct dcerpc_bh_raw_call_state *raw_call_state = NULL;
+       struct tevent_req *req;
+       struct dcerpc_bh_raw_call_in_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct dcerpc_bh_raw_call_in_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (!tevent_req_is_in_progress(raw_call_req)) {
+               tevent_req_nterror(req, NT_STATUS_RPC_CALL_FAILED);
+               return tevent_req_post(req, ev);
+       }
+
+       raw_call_state = tevent_req_data(raw_call_req,
+                                        struct dcerpc_bh_raw_call_state);
+
+       
+       struct rpc_request *subreq;
+       
+       return req;
+}
+
+static NTSTATUS dcerpc_bh_raw_call_in__recv(struct tevent_req *req)
+{
+
+}
+
 struct dcerpc_bh_disconnect_state {
        uint8_t _dummy;
 };
@@ -1409,6 +1472,30 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
                return;
        }
 
+       if (req->state != RPC_REQUEST_PENDING) {
+               req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
+               goto req_done;
+       }
+
+       if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+               if (req->first_pdu_done) {
+                       req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
+                       goto req_done;
+               }
+               req->first_pdu_done = true;
+
+               if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
+                       req->flags |= DCERPC_PULL_BIGENDIAN;
+               } else {
+                       req->flags &= ~DCERPC_PULL_BIGENDIAN;
+               }
+       }
+
+       if (!req->first_pdu_done) {
+               req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
+               goto req_done;
+       }
+
        length = pkt->u.response.stub_and_verifier.length;
 
        if (req->payload.length + length > c->max_total_response_size) {
@@ -1435,7 +1522,19 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
 
        if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
                data_blob_free(raw_packet);
-               dcerpc_send_read(c);
+
+               req->status = dcerpc_send_read(c);
+               if (!NT_STATUS_IS_OK(req->status)) {
+                       goto req_done;
+               }
+
+               if (!req->incomplete_request_data) {
+                       return;
+               }
+
+               if (req->async.callback) {
+                       req->async.callback(req);
+               }
                return;
        }
 
@@ -1446,11 +1545,7 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
                req->p->verified_pcontext = true;
        }
 
-       if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
-               req->flags |= DCERPC_PULL_BIGENDIAN;
-       } else {
-               req->flags &= ~DCERPC_PULL_BIGENDIAN;
-       }
+       req->incomplete_request_data = false;
 
 req_done:
        data_blob_free(raw_packet);
@@ -1767,15 +1862,32 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
 
                remaining -= chunk;
 
-               if ((remaining == 0) && req->incomplete_request_data) {
-                       req->request_data = data_blob_null;
+       }
+
+       if (req->request_data_allocated) {
+               data_blob_free(&req->request_data);
+       }
+       req->request_data_allocated = false;
+       req->request_data = data_blob_null;
+
+       if (!req->incomplete_request_data) {
+               DLIST_REMOVE(c->request_queue, req);
+               DLIST_ADD(c->pending, req);
+               req->state = RPC_REQUEST_PENDING;
+               /*
+                * we reuse first_pdu_done for the receive side
+                */
+               req->first_pdu_done = false;
+       }
+
+               if (req->stub_subreq == NULL) {
                        return;
                }
+
+               tevent_req_done(req->stub_subreq);
+               return;
        }
 
-       DLIST_REMOVE(c->request_queue, req);
-       DLIST_ADD(c->pending, req);
-       req->state = RPC_REQUEST_PENDING;
 }
 
 static void dcerpc_io_trigger(struct tevent_context *ctx,
@@ -1828,13 +1940,8 @@ static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
 {
        NTSTATUS status;
 
-       while (req->state != RPC_REQUEST_DONE) {
-               struct tevent_context *ctx = req->p->conn->event_ctx;
-               if (tevent_loop_once(ctx) != 0) {
-                       return NT_STATUS_CONNECTION_DISCONNECTED;
-               }
-       }
        *stub_data = req->payload;
+       req->payload = data_blob_null;
        status = req->status;
        if (stub_data->data) {
                stub_data->data = talloc_steal(mem_ctx, stub_data->data);
@@ -1842,6 +1949,11 @@ static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
        if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
                req->p->last_fault_code = req->fault_code;
        }
+       if (req->state == RPC_REQUEST_PENDING) {
+               if (NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
        talloc_unlink(talloc_parent(req), req);
        return status;
 }