source4/librpc/rpc/dcerpc.c sq bla
authorStefan Metzmacher <metze@samba.org>
Fri, 20 Sep 2013 12:38:13 +0000 (14:38 +0200)
committerMatthieu Patou <mat@matws.net>
Fri, 3 Oct 2014 19:16:34 +0000 (12:16 -0700)
source4/librpc/rpc/dcerpc.c

index 6c249180c0219d2bcb64524b8d52215fd12afe88..b6ffdd091c2d418bc53f20dd7c7ca780f8f3a135 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;
@@ -378,7 +378,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,
@@ -391,6 +391,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);
@@ -406,15 +409,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);
 
+       if (raw_call_state->subreq == NULL) {
+               tevent_req_nterror(req, NT_STATUS_RPC_CALL_FAILED);
+               return tevent_req_post(req, ev);
+       }
 
-       struct rpc_request *subreq;
+       rpcreq = raw_call_state->subreq;
 
-       return req;
+       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 {
@@ -1592,7 +1651,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;
@@ -1697,8 +1756,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;
+       }
 
        DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
        talloc_set_destructor(req, dcerpc_req_dequeue);
@@ -1729,6 +1793,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) {
@@ -1742,6 +1807,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_info &&
            c->security_state.generic_state)
        {
@@ -1770,8 +1844,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;
@@ -1801,7 +1873,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;
@@ -1853,13 +1925,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) {
@@ -1873,11 +1952,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;
 }