s3:rpc_server: add rpc_pipe_open_internal dcerpc_binding_handle backend
authorStefan Metzmacher <metze@samba.org>
Sat, 7 Aug 2010 12:37:21 +0000 (14:37 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 12 Aug 2010 12:31:22 +0000 (14:31 +0200)
metze

source3/rpc_server/rpc_ncacn_np_internal.c

index 9d15e0d3f9a6b4bf38e8fc4dfcfd9d8bbb743b89..58727600cf52b5a53add6fcfeaf7c8ee4a274901 100644 (file)
@@ -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;
 }