diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/rpc_server/rpc_ncacn_np_internal.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/source3/rpc_server/rpc_ncacn_np_internal.c b/source3/rpc_server/rpc_ncacn_np_internal.c index 9d15e0d3f9..58727600cf 100644 --- a/source3/rpc_server/rpc_ncacn_np_internal.c +++ b/source3/rpc_server/rpc_ncacn_np_internal.c @@ -315,6 +315,272 @@ static NTSTATUS rpc_pipe_internal_dispatch(struct rpc_pipe_client *cli, return NT_STATUS_OK; } +static NTSTATUS rpcint_dispatch(struct pipes_struct *p, + TALLOC_CTX *mem_ctx, + uint32_t opnum, + const DATA_BLOB *in_data, + DATA_BLOB *out_data) +{ + uint32_t num_cmds = rpc_srv_get_pipe_num_cmds(&p->syntax); + const struct api_struct *cmds = rpc_srv_get_pipe_cmds(&p->syntax); + uint32_t i; + bool ok; + + /* set opnum */ + p->opnum = opnum; + + for (i = 0; i < num_cmds; i++) { + if (cmds[i].opnum == opnum && cmds[i].fn != NULL) { + break; + } + } + + if (i == num_cmds) { + return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE; + } + + p->in_data.data = *in_data; + p->out_data.rdata = data_blob_null; + + ok = cmds[i].fn(p); + p->in_data.data = data_blob_null; + if (!ok) { + data_blob_free(&p->out_data.rdata); + talloc_free_children(p->mem_ctx); + return NT_STATUS_RPC_CALL_FAILED; + } + + if (p->fault_state) { + p->fault_state = false; + data_blob_free(&p->out_data.rdata); + talloc_free_children(p->mem_ctx); + return NT_STATUS_RPC_CALL_FAILED; + } + + if (p->bad_handle_fault_state) { + p->bad_handle_fault_state = false; + data_blob_free(&p->out_data.rdata); + talloc_free_children(p->mem_ctx); + return NT_STATUS_RPC_SS_CONTEXT_MISMATCH; + } + + if (p->rng_fault_state) { + p->rng_fault_state = false; + data_blob_free(&p->out_data.rdata); + talloc_free_children(p->mem_ctx); + return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE; + } + + *out_data = p->out_data.rdata; + talloc_steal(mem_ctx, out_data->data); + p->out_data.rdata = data_blob_null; + + talloc_free_children(p->mem_ctx); + return NT_STATUS_OK; +} + +struct rpcint_bh_state { + struct pipes_struct *p; +}; + +static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h) +{ + struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h, + struct rpcint_bh_state); + + if (!hs->p) { + return false; + } + + return true; +} + +struct rpcint_bh_raw_call_state { + DATA_BLOB in_data; + DATA_BLOB out_data; + uint32_t out_flags; +}; + +static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct dcerpc_binding_handle *h, + const struct GUID *object, + uint32_t opnum, + uint32_t in_flags, + const uint8_t *in_data, + size_t in_length) +{ + struct rpcint_bh_state *hs = + dcerpc_binding_handle_data(h, + struct rpcint_bh_state); + struct tevent_req *req; + struct rpcint_bh_raw_call_state *state; + bool ok; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct rpcint_bh_raw_call_state); + if (req == NULL) { + return NULL; + } + state->in_data.data = discard_const_p(uint8_t, in_data); + state->in_data.length = in_length; + + ok = rpcint_bh_is_connected(h); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION); + return tevent_req_post(req, ev); + } + + /* TODO: allow async */ + status = rpcint_dispatch(hs->p, state, opnum, + &state->in_data, + &state->out_data); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + uint8_t **out_data, + size_t *out_length, + uint32_t *out_flags) +{ + struct rpcint_bh_raw_call_state *state = + tevent_req_data(req, + struct rpcint_bh_raw_call_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *out_data = talloc_move(mem_ctx, &state->out_data.data); + *out_length = state->out_data.length; + *out_flags = 0; + tevent_req_received(req); + return NT_STATUS_OK; +} + +struct rpcint_bh_disconnect_state { + uint8_t _dummy; +}; + +static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct dcerpc_binding_handle *h) +{ + struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h, + struct rpcint_bh_state); + struct tevent_req *req; + struct rpcint_bh_disconnect_state *state; + bool ok; + + req = tevent_req_create(mem_ctx, &state, + struct rpcint_bh_disconnect_state); + if (req == NULL) { + return NULL; + } + + ok = rpcint_bh_is_connected(h); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION); + return tevent_req_post(req, ev); + } + + /* + * TODO: do a real async disconnect ... + * + * For now the caller needs to free pipes_struct + */ + hs->p = NULL; + + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + tevent_req_received(req); + return NT_STATUS_OK; +} + +static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h) +{ + return true; +} + +static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h, + int ndr_flags, + const void *_struct_ptr, + const struct ndr_interface_call *call) +{ + void *struct_ptr = discard_const(_struct_ptr); + + if (DEBUGLEVEL < 10) { + return; + } + + if (ndr_flags & NDR_IN) { + ndr_print_function_debug(call->ndr_print, + call->name, + ndr_flags, + struct_ptr); + } + if (ndr_flags & NDR_OUT) { + ndr_print_function_debug(call->ndr_print, + call->name, + ndr_flags, + struct_ptr); + } +} + +static const struct dcerpc_binding_handle_ops rpcint_bh_ops = { + .name = "rpcint", + .is_connected = rpcint_bh_is_connected, + .raw_call_send = rpcint_bh_raw_call_send, + .raw_call_recv = rpcint_bh_raw_call_recv, + .disconnect_send = rpcint_bh_disconnect_send, + .disconnect_recv = rpcint_bh_disconnect_recv, + + .ref_alloc = rpcint_bh_ref_alloc, + .do_ndr_print = rpcint_bh_do_ndr_print, +}; + +/* initialise a wbint binding handle */ +static struct dcerpc_binding_handle *rpcint_binding_handle(struct pipes_struct *p) +{ + struct dcerpc_binding_handle *h; + struct rpcint_bh_state *hs; + + h = dcerpc_binding_handle_create(p, + &rpcint_bh_ops, + NULL, + NULL, /* TODO */ + &hs, + struct rpcint_bh_state, + __location__); + if (h == NULL) { + return NULL; + } + hs->p = p; + + return h; +} + /** * @brief Create a new RPC client context which uses a local dispatch function. * @@ -371,6 +637,12 @@ NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx, result->max_xmit_frag = -1; result->max_recv_frag = -1; + result->binding_handle = rpcint_binding_handle(result->pipes_struct); + if (result->binding_handle == NULL) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + *presult = result; return NT_STATUS_OK; } |