source4/librpc/rpc/dcerpc.c sq bla
authorStefan Metzmacher <metze@samba.org>
Fri, 20 Sep 2013 12:38:13 +0000 (14:38 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 11:14:55 +0000 (13:14 +0200)
source4/librpc/rpc/dcerpc.c

index 2e7f92a0ae286f6736bca718878d2caf5be05393..a0bbf6b78c086a8fa7a9c174a4da92b3d2049524 100644 (file)
@@ -63,7 +63,7 @@ struct rpc_request {
        const struct GUID *object;
        uint16_t opnum;
        DATA_BLOB request_data;
-       bool request_data_allocated;
+       bool request_data_can_append;
        struct tevent_req *stub_subreq;
        bool ignore_timeout;
        bool wait_for_sync;
@@ -379,7 +379,7 @@ static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
 }
 
 struct dcerpc_bh_raw_call_in_state {
-
+       uint8_t dummy;
 };
 
 static struct tevent_req *dcerpc_bh_raw_call_in_send(TALLOC_CTX *mem_ctx,
@@ -392,6 +392,9 @@ static struct tevent_req *dcerpc_bh_raw_call_in_send(TALLOC_CTX *mem_ctx,
        struct dcerpc_bh_raw_call_state *raw_call_state = NULL;
        struct tevent_req *req;
        struct dcerpc_bh_raw_call_in_state *state;
+       struct rpc_request *rpcreq = NULL;
+       DATA_BLOB *b = NULL;
+       bool ok;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct dcerpc_bh_raw_call_in_state);
@@ -407,15 +410,71 @@ static struct tevent_req *dcerpc_bh_raw_call_in_send(TALLOC_CTX *mem_ctx,
        raw_call_state = tevent_req_data(raw_call_req,
                                         struct dcerpc_bh_raw_call_state);
 
-       
-       struct rpc_request *subreq;
-       
-       return req;
+       if (raw_call_state->subreq == NULL) {
+               tevent_req_nterror(req, NT_STATUS_RPC_CALL_FAILED);
+               return tevent_req_post(req, ev);
+       }
+
+       rpcreq = raw_call_state->subreq;
+
+       if (rpcreq->state != RPC_REQUEST_QUEUED) {
+               tevent_req_nterror(req, NT_STATUS_RPC_INVALID_PIPE_OPERATION);
+               return tevent_req_post(req, ev);
+       }
+
+       if (!(in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
+               rpcreq->incomplete_request_data = false;
+       }
+
+       b = &rpcreq->request_data;
+
+       if (in_length == 0) {
+               if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+                       /*
+                        * with LIBNDR_FLAG_INCOMPLETE_BUFFER
+                        * we need to make sure we make any progress...
+                        */
+                       tevent_req_nterror(req, NT_STATUS_RPC_INVALID_PIPE_OPERATION);
+                       return tevent_req_post(req, ev);
+               }
+
+               /*
+                * nothing to add
+                */
+       } else if (rpcreq->request_data_can_append) {
+               ok = data_blob_append(rpcreq, b, in_data, in_length);
+               if (!ok) {
+                       tevent_req_nomem(NULL, req);
+                       return tevent_req_post(req, ev);
+               }
+       } else {
+               *b = data_blob_talloc(rpcreq, b->data, b->length);
+               if (tevent_req_nomem(b->data, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               rpcreq->request_data_can_append = true;
+               ok = data_blob_append(rpcreq, b, in_data, in_length);
+               if (!ok) {
+                       tevent_req_nomem(NULL, req);
+                       return tevent_req_post(req, ev);
+               }
+       }
+
+       dcerpc_schedule_io_trigger(rpcreq->p->conn);
+
+       if (b->length > (rpcreq->p->conn->srv_max_xmit_frag * 10)) {
+               rpcreq->stub_subreq = req;
+               //TODO
+               return req;
+       }
+
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
 }
 
-static NTSTATUS dcerpc_bh_raw_call_in__recv(struct tevent_req *req)
+static NTSTATUS dcerpc_bh_raw_call_in_recv(struct tevent_req *req)
 {
-
+       return tevent_req_simple_recv_ntstatus(req);
 }
 
 struct dcerpc_bh_disconnect_state {
@@ -1479,7 +1538,7 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
                goto req_done;
        }
 
-       if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+       if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) {
                if (req->first_pdu_done) {
                        req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
                        goto req_done;
@@ -1602,8 +1661,13 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
        }
 
        req->opnum = opnum;
-       req->request_data.length = stub_data->length;
-       req->request_data.data = stub_data->data;
+
+       if (stub_data->length > 0) {
+               req->request_data.length = stub_data->length;
+               req->request_data.data = stub_data->data;
+       } else {
+               req->request_data_can_append = true;
+       }
 
        status = dcerpc_request_prepare_vt(req);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1754,6 +1818,7 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
        size_t sig_size = 0;
        bool need_async = false;
        bool can_async = true;
+       bool current_pdus_done = false;
 
        req = c->request_queue;
        if (req == NULL) {
@@ -1767,6 +1832,15 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
                need_async = true;
        }
 
+       remaining = stub_data->length;
+
+       if ((remaining == 0) && req->incomplete_request_data) {
+               /*
+                * we're waiting for more data
+                */
+               return;
+       }
+
        if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
                can_async = gensec_have_feature(c->security_state.generic_state,
                                                GENSEC_FEATURE_ASYNC_REPLIES);
@@ -1779,8 +1853,6 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
 
        init_ncacn_hdr(p->conn, &pkt);
 
-       remaining = stub_data->length;
-
        /* we can write a full max_recv_frag size, minus the dcerpc
           request header size */
        chunk_size = p->conn->srv_max_recv_frag;
@@ -1814,7 +1886,7 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
        }
 
        /* we send a series of pdus without waiting for a reply */
-       while (remaining > 0 || !req->first_pdu_done) {
+       while (!current_pdus_done) {
                uint32_t chunk = MIN(chunk_size, remaining);
                bool last_frag = false;
                bool do_trans = false;
@@ -1866,13 +1938,20 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
                }
 
                remaining -= chunk;
+               if (remaining == 0) {
+                       current_pdus_done = true;
+               }
                req->last_pdu_done = last_frag;
        }
 
-       if (req->request_data_allocated) {
+       if (req->request_data_can_append) {
+               /*
+                * request_data_can_append means the blob
+                * is a talloc child of req
+                */
                data_blob_free(&req->request_data);
        }
-       req->request_data_allocated = false;
+       req->request_data_can_append = true;
        req->request_data = data_blob_null;
 
        if (req->last_pdu_done) {
@@ -1886,11 +1965,15 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
                req->last_pdu_done = false;
        }
 
-       if (req->stub_subreq == NULL) {
+       if (req->stub_subreq != NULL) {
+               struct tevent_req *stub_subreq = req->stub_subreq;
+
+               req->stub_subreq = NULL;
+
+               tevent_req_done(stub_subreq);
                return;
        }
 
-       tevent_req_done(req->stub_subreq);
        return;
 }