From 198c5ace6f9a7d1b1f99473168b0b5b1d191f355 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Mar 2012 15:37:49 +0100 Subject: s4:librpc/rpc: convert dcerpc_alter_context_send/recv to tevent_req Many thanks to Andrew Bartlett for the debugging, which lead to the following line: talloc_steal(state, raw_packet->data); metze --- source4/librpc/rpc/dcerpc.c | 249 +++++++++++++++++++++++---------------- source4/librpc/rpc/dcerpc_auth.c | 26 ++-- 2 files changed, 161 insertions(+), 114 deletions(-) (limited to 'source4/librpc') diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index c1f27cc263..9e7abecf9b 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -27,7 +27,6 @@ #include "librpc/rpc/dcerpc_proto.h" #include "librpc/gen_ndr/ndr_misc.h" #include "librpc/gen_ndr/ndr_dcerpc.h" -#include "libcli/composite/composite.h" #include "auth/gensec/gensec.h" #include "param/param.h" #include "lib/util/tevent_ntstatus.h" @@ -957,16 +956,6 @@ static NTSTATUS dcerpc_map_reason(uint16_t reason) return NT_STATUS_UNSUCCESSFUL; } -/* - a bind or alter context has failed -*/ -static void dcerpc_composite_fail(struct rpc_request *req) -{ - struct composite_context *c = talloc_get_type(req->async.private_data, - struct composite_context); - composite_error(c, req->status); -} - /* remove requests from the pending or queued queues */ @@ -1921,76 +1910,35 @@ uint32_t dcerpc_auth_level(struct dcecli_connection *c) return auth_level; } -/* - Receive an alter reply from the transport -*/ -static void dcerpc_alter_recv_handler(struct rpc_request *req, - DATA_BLOB *raw_packet, struct ncacn_packet *pkt) -{ - struct composite_context *c; - struct dcerpc_pipe *recv_pipe; - - c = talloc_get_type(req->async.private_data, struct composite_context); - recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe); - - if (pkt->ptype == DCERPC_PKT_ALTER_RESP && - pkt->u.alter_resp.num_results == 1 && - pkt->u.alter_resp.ctx_list[0].result != 0) { - DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", - pkt->u.alter_resp.ctx_list[0].reason)); - composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason)); - return; - } - - if (pkt->ptype == DCERPC_PKT_FAULT) { - DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status))); - recv_pipe->last_fault_code = pkt->u.fault.status; - composite_error(c, NT_STATUS_NET_WRITE_FAULT); - return; - } +struct dcerpc_alter_context_state { + struct dcerpc_pipe *p; +}; - if (pkt->ptype != DCERPC_PKT_ALTER_RESP || - pkt->u.alter_resp.num_results == 0 || - pkt->u.alter_resp.ctx_list[0].result != 0) { - recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR; - composite_error(c, NT_STATUS_NET_WRITE_FAULT); - return; - } +static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq); +static void dcerpc_alter_context_recv_handler(struct rpc_request *req, + DATA_BLOB *raw_packet, + struct ncacn_packet *pkt); - /* the alter_resp might contain a reply set of credentials */ - if (recv_pipe->conn->security_state.auth_info && - pkt->u.alter_resp.auth_info.length) { - struct dcecli_connection *conn = recv_pipe->conn; - NTSTATUS status; - uint32_t auth_length; - status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info, - conn->security_state.auth_info, &auth_length, true); - if (!NT_STATUS_IS_OK(status)) { - composite_error(c, status); - return; - } - } - - composite_done(c); -} - -/* - send a dcerpc alter_context request -*/ -struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, - TALLOC_CTX *mem_ctx, - const struct ndr_syntax_id *syntax, - const struct ndr_syntax_id *transfer_syntax) +struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct dcerpc_pipe *p, + const struct ndr_syntax_id *syntax, + const struct ndr_syntax_id *transfer_syntax) { - struct composite_context *c; + struct tevent_req *req; + struct dcerpc_alter_context_state *state; struct ncacn_packet pkt; DATA_BLOB blob; - struct rpc_request *req; + NTSTATUS status; + struct rpc_request *subreq; - c = composite_create(mem_ctx, p->conn->event_ctx); - if (c == NULL) return NULL; + req = tevent_req_create(mem_ctx, &state, + struct dcerpc_alter_context_state); + if (req == NULL) { + return NULL; + } - c->private_data = p; + state->p = p; p->syntax = *syntax; p->transfer_syntax = *transfer_syntax; @@ -2014,8 +1962,10 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, pkt.u.alter.max_recv_frag = 5840; pkt.u.alter.assoc_group_id = p->binding->assoc_group_id; pkt.u.alter.num_contexts = 1; - pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1); - if (composite_nomem(pkt.u.alter.ctx_list, c)) return c; + pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1); + if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) { + return tevent_req_post(req, ev); + } pkt.u.alter.ctx_list[0].context_id = p->context_id; pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1; pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax; @@ -2023,9 +1973,11 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, pkt.u.alter.auth_info = data_blob(NULL, 0); /* construct the NDR form of the packet */ - c->status = ncacn_push_auth(&blob, mem_ctx, &pkt, - p->conn->security_state.auth_info); - if (!composite_is_ok(c)) return c; + status = ncacn_push_auth(&blob, state, &pkt, + p->conn->security_state.auth_info); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } p->conn->transport.recv_data = dcerpc_recv_data; @@ -2033,33 +1985,109 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, * we allocate a dcerpc_request so we can be in the same * request queue as normal requests */ - req = talloc_zero(c, struct rpc_request); - if (composite_nomem(req, c)) return c; + subreq = talloc_zero(state, struct rpc_request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } - req->state = RPC_REQUEST_PENDING; - req->call_id = pkt.call_id; - req->async.private_data = c; - req->async.callback = dcerpc_composite_fail; - req->p = p; - req->recv_handler = dcerpc_alter_recv_handler; - DLIST_ADD_END(p->conn->pending, req, struct rpc_request *); - talloc_set_destructor(req, dcerpc_req_dequeue); + subreq->state = RPC_REQUEST_PENDING; + subreq->call_id = pkt.call_id; + subreq->async.private_data = req; + subreq->async.callback = dcerpc_alter_context_fail_handler; + subreq->p = p; + subreq->recv_handler = dcerpc_alter_context_recv_handler; + DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *); + talloc_set_destructor(subreq, dcerpc_req_dequeue); - c->status = p->conn->transport.send_request(p->conn, &blob, true); - if (!composite_is_ok(c)) return c; + status = p->conn->transport.send_request(p->conn, &blob, true); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } - tevent_add_timer(c->event_ctx, req, - timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), - dcerpc_timeout_handler, req); + tevent_add_timer(ev, subreq, + timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), + dcerpc_timeout_handler, subreq); - return c; + return req; +} + +static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq) +{ + struct tevent_req *req = + talloc_get_type_abort(subreq->async.private_data, + struct tevent_req); + NTSTATUS status = subreq->status; + + TALLOC_FREE(subreq); + + tevent_req_nterror(req, status); +} + +static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq, + DATA_BLOB *raw_packet, + struct ncacn_packet *pkt) +{ + struct tevent_req *req = + talloc_get_type_abort(subreq->async.private_data, + struct tevent_req); + struct dcerpc_alter_context_state *state = + tevent_req_data(req, + struct dcerpc_alter_context_state); + struct dcecli_connection *conn = state->p->conn; + NTSTATUS status; + + /* + * Note that pkt is allocated under raw_packet->data, + * while raw_packet->data is a child of subreq. + */ + talloc_steal(state, raw_packet->data); + TALLOC_FREE(subreq); + + if (pkt->ptype == DCERPC_PKT_ALTER_RESP && + pkt->u.alter_resp.num_results == 1 && + pkt->u.alter_resp.ctx_list[0].result != 0) { + status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason); + DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n", + pkt->u.alter_resp.ctx_list[0].reason, + nt_errstr(status))); + tevent_req_nterror(req, status); + return; + } + + if (pkt->ptype == DCERPC_PKT_FAULT) { + DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n", + dcerpc_errstr(state, pkt->u.fault.status))); + state->p->last_fault_code = pkt->u.fault.status; + tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT); + return; + } + + if (pkt->ptype != DCERPC_PKT_ALTER_RESP || + pkt->u.alter_resp.num_results == 0 || + pkt->u.alter_resp.ctx_list[0].result != 0) { + state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR; + tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT); + return; + } + + /* the alter_resp might contain a reply set of credentials */ + if (conn->security_state.auth_info && + pkt->u.alter_resp.auth_info.length) { + uint32_t auth_length; + + status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info, + conn->security_state.auth_info, &auth_length, true); + if (tevent_req_nterror(req, status)) { + return; + } + } + + tevent_req_done(req); } -NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx) +NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req) { - NTSTATUS result = composite_wait(ctx); - talloc_free(ctx); - return result; + return tevent_req_simple_recv_ntstatus(req); } /* @@ -2070,8 +2098,25 @@ _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, const struct ndr_syntax_id *syntax, const struct ndr_syntax_id *transfer_syntax) { - struct composite_context *creq; - creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax); - return dcerpc_alter_context_recv(creq); + struct tevent_req *subreq; + struct tevent_context *ev = p->conn->event_ctx; + bool ok; + + /* TODO: create a new event context here */ + + subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx, + p, syntax, transfer_syntax); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ok = tevent_req_poll(subreq, ev); + if (!ok) { + NTSTATUS status; + status = map_nt_error_from_unix_common(errno); + return status; + } + + return dcerpc_alter_context_recv(subreq); } diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index 7af85aaab1..f119b426d9 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -129,13 +129,13 @@ struct bind_auth_state { * first bind itself received? */ }; -static void bind_auth_recv_alter(struct composite_context *creq); +static void bind_auth_recv_alter(struct tevent_req *subreq); static void bind_auth_next_step(struct composite_context *c) { struct bind_auth_state *state; struct dcecli_security *sec; - struct composite_context *creq; + struct tevent_req *subreq; bool more_processing = false; state = talloc_get_type(c->private_data, struct bind_auth_state); @@ -188,23 +188,25 @@ static void bind_auth_next_step(struct composite_context *c) /* We are demanding a reply, so use a request that will get us one */ - creq = dcerpc_alter_context_send(state->pipe, state, - &state->pipe->syntax, - &state->pipe->transfer_syntax); + subreq = dcerpc_alter_context_send(state, state->pipe->conn->event_ctx, + state->pipe, + &state->pipe->syntax, + &state->pipe->transfer_syntax); data_blob_free(&state->credentials); sec->auth_info->credentials = data_blob(NULL, 0); - if (composite_nomem(creq, c)) return; - - composite_continue(c, creq, bind_auth_recv_alter, c); + if (composite_nomem(subreq, c)) return; + tevent_req_set_callback(subreq, bind_auth_recv_alter, c); } -static void bind_auth_recv_alter(struct composite_context *creq) +static void bind_auth_recv_alter(struct tevent_req *subreq) { - struct composite_context *c = talloc_get_type(creq->async.private_data, - struct composite_context); + struct composite_context *c = + tevent_req_callback_data(subreq, + struct composite_context); - c->status = dcerpc_alter_context_recv(creq); + c->status = dcerpc_alter_context_recv(subreq); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; bind_auth_next_step(c); -- cgit