From 6b81d71f3e0ae89bf1352ea469446a902613de01 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Mar 2012 14:52:40 +0100 Subject: s4:librpc/rpc: convert dcerpc_bind_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 | 232 ++++++++++++++++++++++----------------- source4/librpc/rpc/dcerpc_auth.c | 48 ++++++-- 2 files changed, 169 insertions(+), 111 deletions(-) diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 3243644721..c1f27cc263 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -1071,65 +1071,6 @@ static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NT dcerpc_request_recv_data(conn, blob, &pkt); } -/* - Receive a bind reply from the transport -*/ -static void dcerpc_bind_recv_handler(struct rpc_request *req, - DATA_BLOB *raw_packet, struct ncacn_packet *pkt) -{ - struct composite_context *c; - struct dcecli_connection *conn; - - c = talloc_get_type(req->async.private_data, struct composite_context); - - if (pkt->ptype == DCERPC_PKT_BIND_NAK) { - DEBUG(2,("dcerpc: bind_nak reason %d\n", - pkt->u.bind_nak.reject_reason)); - composite_error(c, dcerpc_map_reason(pkt->u.bind_nak. - reject_reason)); - return; - } - - if ((pkt->ptype != DCERPC_PKT_BIND_ACK) || - (pkt->u.bind_ack.num_results == 0) || - (pkt->u.bind_ack.ctx_list[0].result != 0)) { - req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR; - composite_error(c, NT_STATUS_NET_WRITE_FAULT); - return; - } - - conn = req->p->conn; - - conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag; - conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag; - - if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) && - (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) { - conn->flags |= DCERPC_CONCURRENT_MULTIPLEX; - } - - if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) && - (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) { - conn->flags |= DCERPC_HEADER_SIGNING; - } - - /* the bind_ack might contain a reply set of credentials */ - if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) { - NTSTATUS status; - uint32_t auth_length; - status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info, - conn->security_state.auth_info, &auth_length, true); - if (!NT_STATUS_IS_OK(status)) { - composite_error(c, status); - return; - } - } - - req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id; - - composite_done(c); -} - /* handle timeouts of individual dcerpc requests */ @@ -1151,23 +1092,35 @@ static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_time dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT); } -/* - send a async dcerpc bind request -*/ -struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p, - TALLOC_CTX *mem_ctx, - const struct ndr_syntax_id *syntax, - const struct ndr_syntax_id *transfer_syntax) +struct dcerpc_bind_state { + struct dcerpc_pipe *p; +}; + +static void dcerpc_bind_fail_handler(struct rpc_request *subreq); +static void dcerpc_bind_recv_handler(struct rpc_request *subreq, + DATA_BLOB *raw_packet, + struct ncacn_packet *pkt); + +struct tevent_req *dcerpc_bind_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_bind_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_bind_state); + if (req == NULL) { + return NULL; + } - c->private_data = p; + state->p = p; p->syntax = *syntax; p->transfer_syntax = *transfer_syntax; @@ -1192,7 +1145,9 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p, pkt.u.bind.assoc_group_id = p->binding->assoc_group_id; pkt.u.bind.num_contexts = 1; pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1); - if (composite_nomem(pkt.u.bind.ctx_list, c)) return c; + if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) { + return tevent_req_post(req, ev); + } pkt.u.bind.ctx_list[0].context_id = p->context_id; pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1; pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax; @@ -1200,9 +1155,11 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p, pkt.u.bind.auth_info = data_blob(NULL, 0); /* construct the NDR form of the packet */ - c->status = ncacn_push_auth(&blob, c, &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; @@ -1210,37 +1167,114 @@ struct composite_context *dcerpc_bind_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_bind_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_bind_fail_handler; + subreq->p = p; + subreq->recv_handler = dcerpc_bind_recv_handler; + DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *); + talloc_set_destructor(subreq, dcerpc_req_dequeue); + + status = p->conn->transport.send_request(p->conn, &blob, true); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } - c->status = p->conn->transport.send_request(p->conn, &blob, - true); - if (!composite_is_ok(c)) return c; + tevent_add_timer(ev, subreq, + timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), + dcerpc_timeout_handler, subreq); - tevent_add_timer(c->event_ctx, req, - timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), - dcerpc_timeout_handler, req); + return req; +} - return c; +static void dcerpc_bind_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); } -/* - recv side of async dcerpc bind request -*/ -NTSTATUS dcerpc_bind_recv(struct composite_context *ctx) +static void dcerpc_bind_recv_handler(struct rpc_request *subreq, + DATA_BLOB *raw_packet, + struct ncacn_packet *pkt) { - NTSTATUS result = composite_wait(ctx); - talloc_free(ctx); - return result; + struct tevent_req *req = + talloc_get_type_abort(subreq->async.private_data, + struct tevent_req); + struct dcerpc_bind_state *state = + tevent_req_data(req, + struct dcerpc_bind_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_BIND_NAK) { + status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason); + + DEBUG(2,("dcerpc: bind_nak reason %d - %s\n", + pkt->u.bind_nak.reject_reason, nt_errstr(status))); + + tevent_req_nterror(req, status); + return; + } + + if ((pkt->ptype != DCERPC_PKT_BIND_ACK) || + (pkt->u.bind_ack.num_results == 0) || + (pkt->u.bind_ack.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; + } + + conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag; + conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag; + + if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) && + (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) { + conn->flags |= DCERPC_CONCURRENT_MULTIPLEX; + } + + if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) && + (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) { + conn->flags |= DCERPC_HEADER_SIGNING; + } + + /* the bind_ack might contain a reply set of credentials */ + if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) { + uint32_t auth_length; + + status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info, + conn->security_state.auth_info, &auth_length, true); + if (tevent_req_nterror(req, status)) { + return; + } + } + + state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id; + + tevent_req_done(req); +} + +NTSTATUS dcerpc_bind_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); } /* diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index b3f4f2fdb0..7af85aaab1 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -22,6 +22,7 @@ */ #include "includes.h" +#include #include "libcli/composite/composite.h" #include "auth/gensec/gensec.h" #include "librpc/rpc/dcerpc.h" @@ -52,6 +53,8 @@ static NTSTATUS dcerpc_init_syntaxes(const struct ndr_interface_table *table, /* Send request to do a non-authenticated dcerpc bind */ +static void dcerpc_bind_auth_none_done(struct tevent_req *subreq); + struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx, struct dcerpc_pipe *p, const struct ndr_interface_table *table) @@ -60,6 +63,7 @@ struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx, struct ndr_syntax_id transfer_syntax; struct composite_context *c; + struct tevent_req *subreq; c = composite_create(mem_ctx, p->conn->event_ctx); if (c == NULL) return NULL; @@ -73,19 +77,35 @@ struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx, return c; } - /* c was only allocated as a container for a possible error */ - talloc_free(c); + subreq = dcerpc_bind_send(mem_ctx, p->conn->event_ctx, p, + &syntax, &transfer_syntax); + if (composite_nomem(subreq, c)) return c; + tevent_req_set_callback(subreq, dcerpc_bind_auth_none_done, c); - return dcerpc_bind_send(p, mem_ctx, &syntax, &transfer_syntax); + return c; } +static void dcerpc_bind_auth_none_done(struct tevent_req *subreq) +{ + struct composite_context *ctx = + tevent_req_callback_data(subreq, + struct composite_context); + + ctx->status = dcerpc_bind_recv(subreq); + TALLOC_FREE(subreq); + if (!composite_is_ok(ctx)) return; + + composite_done(ctx); +} /* Receive result of a non-authenticated dcerpc bind */ NTSTATUS dcerpc_bind_auth_none_recv(struct composite_context *ctx) { - return dcerpc_bind_recv(ctx); + NTSTATUS result = composite_wait(ctx); + TALLOC_FREE(ctx); + return result; } @@ -191,14 +211,16 @@ static void bind_auth_recv_alter(struct composite_context *creq) } -static void bind_auth_recv_bindreply(struct composite_context *creq) +static void bind_auth_recv_bindreply(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); struct bind_auth_state *state = talloc_get_type(c->private_data, struct bind_auth_state); - c->status = dcerpc_bind_recv(creq); + c->status = dcerpc_bind_recv(subreq); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; if (!state->more_processing) { @@ -232,9 +254,10 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx, uint8_t auth_type, uint8_t auth_level, const char *service) { - struct composite_context *c, *creq; + struct composite_context *c; struct bind_auth_state *state; struct dcecli_security *sec; + struct tevent_req *subreq; struct ndr_syntax_id syntax, transfer_syntax; @@ -355,12 +378,13 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx, /* The first request always is a dcerpc_bind. The subsequent ones * depend on gensec results */ - creq = dcerpc_bind_send(p, state, &syntax, &transfer_syntax); + subreq = dcerpc_bind_send(state, p->conn->event_ctx, p, + &syntax, &transfer_syntax); data_blob_free(&state->credentials); sec->auth_info->credentials = data_blob(NULL, 0); - if (composite_nomem(creq, c)) return c; + if (composite_nomem(subreq, c)) return c; + tevent_req_set_callback(subreq, bind_auth_recv_bindreply, c); - composite_continue(c, creq, bind_auth_recv_bindreply, c); return c; } -- cgit