diff options
Diffstat (limited to 'source4/librpc/rpc')
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 289 |
1 files changed, 140 insertions, 149 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 0728b97768..c7f337de99 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -517,91 +517,6 @@ static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt } /* - hold the state of pending full requests -*/ -struct full_request_state { - struct dcerpc_connection *c; - DATA_BLOB *reply_blob; - NTSTATUS status; -}; - -/* - receive a reply to a full request - */ -static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob, - NTSTATUS status) -{ - struct full_request_state *state = talloc_get_type(c->full_request_private, - struct full_request_state); - if (state == NULL) { - /* it timed out earlier */ - return; - } - - if (!NT_STATUS_IS_OK(status)) { - state->status = status; - return; - } - state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length); - state->reply_blob = NULL; -} - -/* - handle timeouts of full dcerpc requests -*/ -static void dcerpc_full_timeout_handler(struct event_context *ev, struct timed_event *te, - struct timeval t, void *private) -{ - struct full_request_state *state = talloc_get_type(private, - struct full_request_state); - state->status = NT_STATUS_IO_TIMEOUT; - state->c->full_request_private = NULL; -} - -/* - perform a single pdu synchronous request - used for the bind code - this cannot be mixed with normal async requests -*/ -static NTSTATUS full_request(struct dcerpc_connection *c, - TALLOC_CTX *mem_ctx, - DATA_BLOB *request_blob, - DATA_BLOB *reply_blob) -{ - struct full_request_state *state = talloc(mem_ctx, struct full_request_state); - NTSTATUS status; - - if (state == NULL) { - return NT_STATUS_NO_MEMORY; - } - - state->reply_blob = reply_blob; - state->status = NT_STATUS_OK; - state->c = c; - - c->transport.recv_data = full_request_recv; - c->full_request_private = state; - - status = c->transport.send_request(c, request_blob, True); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - event_add_timed(c->event_ctx, state, - timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), - dcerpc_full_timeout_handler, state); - - while (NT_STATUS_IS_OK(state->status) && state->reply_blob) { - if (event_loop_once(c->event_ctx) != 0) { - return NT_STATUS_CONNECTION_DISCONNECTED; - } - } - - c->full_request_private = NULL; - - return state->status; -} - -/* map a bind nak reason to a NTSTATUS */ static NTSTATUS dcerpc_map_reason(uint16_t reason) @@ -613,7 +528,7 @@ static NTSTATUS dcerpc_map_reason(uint16_t reason) return NT_STATUS_UNSUCCESSFUL; } -struct dcerpc_bind_state { +struct dcerpc_request_state { struct dcerpc_pipe *pipe; struct ncacn_packet pkt; DATA_BLOB blob; @@ -627,7 +542,7 @@ static void bind_request_recv(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status) { struct composite_context *c; - struct dcerpc_bind_state *state; + struct dcerpc_request_state *state; if (conn->full_request_private == NULL) { /* it timed out earlier */ @@ -635,7 +550,7 @@ static void bind_request_recv(struct dcerpc_connection *conn, DATA_BLOB *blob, } c = talloc_get_type(conn->full_request_private, struct composite_context); - state = talloc_get_type(c->private_data, struct dcerpc_bind_state); + state = talloc_get_type(c->private_data, struct dcerpc_request_state); if (!NT_STATUS_IS_OK(status)) { composite_error(c, status); @@ -677,7 +592,7 @@ static void bind_request_recv(struct dcerpc_connection *conn, DATA_BLOB *blob, } /* - handle timeouts of full dcerpc requests + handle timeouts of dcerpc bind and alter context requests */ static void bind_timeout_handler(struct event_context *ev, struct timed_event *te, @@ -685,8 +600,9 @@ static void bind_timeout_handler(struct event_context *ev, { struct composite_context *ctx = talloc_get_type(private, struct composite_context); - struct dcerpc_bind_state *state = - talloc_get_type(ctx->private_data, struct dcerpc_bind_state); + struct dcerpc_request_state *state = + talloc_get_type(ctx->private_data, + struct dcerpc_request_state); SMB_ASSERT(state->pipe->conn->full_request_private != NULL); state->pipe->conn->full_request_private = NULL; @@ -699,12 +615,12 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p, const struct dcerpc_syntax_id *transfer_syntax) { struct composite_context *c; - struct dcerpc_bind_state *state; + struct dcerpc_request_state *state; c = talloc_zero(mem_ctx, struct composite_context); if (c == NULL) return NULL; - state = talloc(c, struct dcerpc_bind_state); + state = talloc(c, struct dcerpc_request_state); if (state == NULL) { c->status = NT_STATUS_NO_MEMORY; goto failed; @@ -1569,82 +1485,157 @@ uint32_t dcerpc_auth_level(struct dcerpc_connection *c) return auth_level; } +/* + Receive an alter reply from the transport +*/ +static void alter_request_recv(struct dcerpc_connection *conn, DATA_BLOB *blob, + NTSTATUS status) +{ + struct composite_context *c; + struct dcerpc_request_state *state; + + if (conn->full_request_private == NULL) { + /* it timed out earlier */ + return; + } + + c = talloc_get_type(conn->full_request_private, + struct composite_context); + state = talloc_get_type(c->private_data, struct dcerpc_request_state); + + if (!NT_STATUS_IS_OK(status)) { + composite_error(c, status); + return; + } + + /* unmarshall the NDR */ + c->status = ncacn_pull(state->pipe->conn, blob, state, &state->pkt); + if (!composite_is_ok(c)) return; + + if (state->pkt.ptype == DCERPC_PKT_ALTER_RESP && + state->pkt.u.alter_resp.num_results == 1 && + state->pkt.u.alter_resp.ctx_list[0].result != 0) { + DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", + state->pkt.u.alter_resp.ctx_list[0].reason)); + composite_error(c, dcerpc_map_reason(state->pkt.u.alter_resp.ctx_list[0].reason)); + return; + } + + if (state->pkt.ptype != DCERPC_PKT_ALTER_RESP || + state->pkt.u.alter_resp.num_results == 0 || + state->pkt.u.alter_resp.ctx_list[0].result != 0) { + composite_error(c, NT_STATUS_UNSUCCESSFUL); + return; + } + + /* the alter_resp might contain a reply set of credentials */ + if (state->pipe->conn->security_state.auth_info && + state->pkt.u.alter_resp.auth_info.length) { + c->status = ndr_pull_struct_blob( + &state->pkt.u.alter_resp.auth_info, state, + state->pipe->conn->security_state.auth_info, + (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); + if (!composite_is_ok(c)) return; + } + + composite_done(c); +} /* send a dcerpc alter_context request */ -NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, - TALLOC_CTX *mem_ctx, - const struct dcerpc_syntax_id *syntax, - const struct dcerpc_syntax_id *transfer_syntax) +struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + const struct dcerpc_syntax_id *syntax, + const struct dcerpc_syntax_id *transfer_syntax) { - struct ncacn_packet pkt; - NTSTATUS status; - DATA_BLOB blob; + struct composite_context *c; + struct dcerpc_request_state *state; + + c = talloc_zero(mem_ctx, struct composite_context); + if (c == NULL) return NULL; + + state = talloc(c, struct dcerpc_request_state); + if (state == NULL) { + c->status = NT_STATUS_NO_MEMORY; + goto failed; + } + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = state; + c->event_ctx = p->conn->event_ctx; + + state->pipe = p; p->syntax = *syntax; p->transfer_syntax = *transfer_syntax; - init_ncacn_hdr(p->conn, &pkt); + init_ncacn_hdr(p->conn, &state->pkt); - pkt.ptype = DCERPC_PKT_ALTER; - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; - pkt.call_id = p->conn->call_id; - pkt.auth_length = 0; + state->pkt.ptype = DCERPC_PKT_ALTER; + state->pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + state->pkt.call_id = p->conn->call_id; + state->pkt.auth_length = 0; - pkt.u.alter.max_xmit_frag = 5840; - pkt.u.alter.max_recv_frag = 5840; - pkt.u.alter.assoc_group_id = 0; - pkt.u.alter.num_contexts = 1; - pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1); - if (!pkt.u.alter.ctx_list) { - return NT_STATUS_NO_MEMORY; + state->pkt.u.alter.max_xmit_frag = 5840; + state->pkt.u.alter.max_recv_frag = 5840; + state->pkt.u.alter.assoc_group_id = 0; + state->pkt.u.alter.num_contexts = 1; + state->pkt.u.alter.ctx_list = talloc_array(mem_ctx, + struct dcerpc_ctx_list, 1); + if (state->pkt.u.alter.ctx_list == NULL) { + c->status = NT_STATUS_NO_MEMORY; + goto failed; } - 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; - pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax; - pkt.u.alter.auth_info = data_blob(NULL, 0); + state->pkt.u.alter.ctx_list[0].context_id = p->context_id; + state->pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1; + state->pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax; + state->pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax; + state->pkt.u.alter.auth_info = data_blob(NULL, 0); /* construct the NDR form of the packet */ - status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info); - if (!NT_STATUS_IS_OK(status)) { - return status; + c->status = ncacn_push_auth(&state->blob, mem_ctx, &state->pkt, + p->conn->security_state.auth_info); + if (!NT_STATUS_IS_OK(c->status)) { + goto failed; } - /* send it on its way */ - status = full_request(p->conn, mem_ctx, &blob, &blob); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + p->conn->transport.recv_data = alter_request_recv; + p->conn->full_request_private = c; - /* unmarshall the NDR */ - status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt); - if (!NT_STATUS_IS_OK(status)) { - return status; + c->status = p->conn->transport.send_request(p->conn, &state->blob, + True); + if (!NT_STATUS_IS_OK(c->status)) { + goto failed; } - 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)); - return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason); - } + event_add_timed(c->event_ctx, c, + timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), + bind_timeout_handler, c); - if (pkt.ptype != DCERPC_PKT_ALTER_RESP || - pkt.u.alter_resp.num_results == 0 || - pkt.u.alter_resp.ctx_list[0].result != 0) { - return NT_STATUS_UNSUCCESSFUL; - } + return c; - /* the alter_resp might contain a reply set of credentials */ - if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) { - status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info, - mem_ctx, - p->conn->security_state.auth_info, - (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); - } + failed: + composite_trigger_error(c); + return c; +} - return status; +NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx) +{ + NTSTATUS result = composite_wait(ctx); + talloc_free(ctx); + return result; +} + +/* + send a dcerpc alter_context request +*/ +NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + const struct dcerpc_syntax_id *syntax, + const struct dcerpc_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); } |