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 *);
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);
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);
}
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;
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;
}
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);
return;
}
+ if (state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+ tevent_req_notify_callback(req);
+ return;
+ }
+
tevent_req_done(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;
};
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) {
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;
}
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);
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,
{
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);
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;
}