summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/rpc_server/rpc_ncacn_np_internal.c272
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;
}