pidl: Change *_get_pipe_fns() to return const struct api_struct *
[gd/samba-autobuild/.git] / source3 / winbindd / winbindd_dual_ndr.c
index f67a48dfeb97b97960d9c58d5826ea4be738d743..250d9d3da598d3e15b1cf37c4800d6ded4b2a618 100644 (file)
 #include "includes.h"
 #include "winbindd/winbindd.h"
 #include "winbindd/winbindd_proto.h"
-#include "librpc/gen_ndr/srv_wbint.h"
+#include "ntdomain.h"
+#include "librpc/gen_ndr/srv_winbind.h"
 
-struct wb_ndr_transport_priv {
+struct wbint_bh_state {
        struct winbindd_domain *domain;
        struct winbindd_child *child;
 };
 
-struct wb_ndr_dispatch_state {
-       struct wb_ndr_transport_priv *transport;
+static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h)
+{
+       struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
+                                    struct wbint_bh_state);
+
+       if (!hs->child) {
+               return false;
+       }
+
+       return true;
+}
+
+static uint32_t wbint_bh_set_timeout(struct dcerpc_binding_handle *h,
+                                    uint32_t timeout)
+{
+       /* TODO: implement timeouts */
+       return UINT32_MAX;
+}
+
+struct wbint_bh_raw_call_state {
+       struct winbindd_domain *domain;
        uint32_t opnum;
-       const struct ndr_interface_call *call;
-       void *r;
-       DATA_BLOB req_blob, resp_blob;
+       DATA_BLOB in_data;
        struct winbindd_request request;
        struct winbindd_response *response;
+       DATA_BLOB out_data;
 };
 
-static void wb_ndr_dispatch_done(struct tevent_req *subreq);
+static void wbint_bh_raw_call_done(struct tevent_req *subreq);
 
-static struct tevent_req *wb_ndr_dispatch_send(TALLOC_CTX *mem_ctx,
-                                              struct tevent_context *ev,
-                                              struct rpc_pipe_client *cli,
-                                              const struct ndr_interface_table *table,
-                                              uint32_t opnum,
-                                              void *r)
+static struct tevent_req *wbint_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 tevent_req *req, *subreq;
-       struct wb_ndr_dispatch_state *state;
-       struct wb_ndr_transport_priv *transport = talloc_get_type_abort(
-               cli->transport->priv, struct wb_ndr_transport_priv);
-       struct ndr_push *push;
-       enum ndr_err_code ndr_err;
+       struct wbint_bh_state *hs =
+               dcerpc_binding_handle_data(h,
+               struct wbint_bh_state);
+       struct tevent_req *req;
+       struct wbint_bh_raw_call_state *state;
+       bool ok;
+       struct tevent_req *subreq;
 
        req = tevent_req_create(mem_ctx, &state,
-                               struct wb_ndr_dispatch_state);
+                               struct wbint_bh_raw_call_state);
        if (req == NULL) {
                return NULL;
        }
-
-       state->r = r;
-       state->call = &table->calls[opnum];
-       state->transport = transport;
+       state->domain = hs->domain;
        state->opnum = opnum;
+       state->in_data.data = discard_const_p(uint8_t, in_data);
+       state->in_data.length = in_length;
 
-       push = ndr_push_init_ctx(state);
-       if (tevent_req_nomem(push, req)) {
-               return tevent_req_post(req, ev);
-       }
-
-       ndr_err = state->call->ndr_push(push, NDR_IN, r);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               tevent_req_nterror(req, ndr_map_error2ntstatus(ndr_err));
-               TALLOC_FREE(push);
+       ok = wbint_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
                return tevent_req_post(req, ev);
        }
 
-       state->req_blob = ndr_push_blob(push);
-
-       if ((transport->domain != NULL)
-           && wcache_fetch_ndr(state, transport->domain, opnum,
-                               &state->req_blob, &state->resp_blob)) {
+       if ((state->domain != NULL)
+           && wcache_fetch_ndr(state, state->domain, state->opnum,
+                               &state->in_data, &state->out_data)) {
                tevent_req_done(req);
                return tevent_req_post(req, ev);
        }
 
        state->request.cmd = WINBINDD_DUAL_NDRCMD;
-       state->request.data.ndrcmd = opnum;
-       state->request.extra_data.data = (char *)state->req_blob.data;
-       state->request.extra_len = state->req_blob.length;
+       state->request.data.ndrcmd = state->opnum;
+       state->request.extra_data.data = (char *)state->in_data.data;
+       state->request.extra_len = state->in_data.length;
 
-       subreq = wb_child_request_send(state, ev, transport->child,
+       subreq = wb_child_request_send(state, ev, hs->child,
                                       &state->request);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, wb_ndr_dispatch_done, req);
+       tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
+
        return req;
 }
 
-static void wb_ndr_dispatch_done(struct tevent_req *subreq)
+static void wbint_bh_raw_call_done(struct tevent_req *subreq)
 {
-       struct tevent_req *req = tevent_req_callback_data(
-               subreq, struct tevent_req);
-       struct wb_ndr_dispatch_state *state = tevent_req_data(
-               req, struct wb_ndr_dispatch_state);
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct wbint_bh_raw_call_state *state =
+               tevent_req_data(req,
+               struct wbint_bh_raw_call_state);
        int ret, err;
 
        ret = wb_child_request_recv(subreq, state, &state->response, &err);
        TALLOC_FREE(subreq);
        if (ret == -1) {
-               tevent_req_nterror(req, map_nt_error_from_unix(err));
+               NTSTATUS status = map_nt_error_from_unix(err);
+               tevent_req_nterror(req, status);
                return;
        }
 
-       state->resp_blob = data_blob_const(
+       state->out_data = data_blob_talloc(state,
                state->response->extra_data.data,
-               state->response->length - sizeof(struct winbindd_response));
+               state->response->length - sizeof(struct winbindd_response));
+       if (state->response->extra_data.data && !state->out_data.data) {
+               tevent_req_oom(req);
+               return;
+       }
 
-       if (state->transport->domain != NULL) {
-               wcache_store_ndr(state->transport->domain, state->opnum,
-                                &state->req_blob, &state->resp_blob);
+       if (state->domain != NULL) {
+               wcache_store_ndr(state->domain, state->opnum,
+                                &state->in_data, &state->out_data);
        }
 
        tevent_req_done(req);
 }
 
-static NTSTATUS wb_ndr_dispatch_recv(struct tevent_req *req,
-                                    TALLOC_CTX *mem_ctx)
+static NTSTATUS wbint_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 wb_ndr_dispatch_state *state = tevent_req_data(
-               req, struct wb_ndr_dispatch_state);
+       struct wbint_bh_raw_call_state *state =
+               tevent_req_data(req,
+               struct wbint_bh_raw_call_state);
        NTSTATUS status;
-       struct ndr_pull *pull;
-       enum ndr_err_code ndr_err;
 
        if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
                return status;
        }
 
-       pull = ndr_pull_init_blob(&state->resp_blob, mem_ctx);
-       if (pull == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /* have the ndr parser alloc memory for us */
-       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
-       ndr_err = state->call->ndr_pull(pull, NDR_OUT, state->r);
-       TALLOC_FREE(pull);
-
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               return ndr_map_error2ntstatus(ndr_err);
-       }
-
+       *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;
 }
 
-static NTSTATUS wb_ndr_dispatch(struct rpc_pipe_client *cli,
-                               TALLOC_CTX *mem_ctx,
-                               const struct ndr_interface_table *table,
-                               uint32_t opnum, void *r)
+struct wbint_bh_disconnect_state {
+       uint8_t _dummy;
+};
+
+static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct dcerpc_binding_handle *h)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
+       struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
+                                    struct wbint_bh_state);
        struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_OK;
+       struct wbint_bh_disconnect_state *state;
+       bool ok;
 
-       ev = event_context_init(frame);
-       if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
-       }
-
-       req = wb_ndr_dispatch_send(frame, ev, cli, table, opnum, r);
+       req = tevent_req_create(mem_ctx, &state,
+                               struct wbint_bh_disconnect_state);
        if (req == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
+               return NULL;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
-               goto fail;
+       ok = wbint_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+               return tevent_req_post(req, ev);
        }
 
-       status = wb_ndr_dispatch_recv(req, mem_ctx);
- fail:
-       TALLOC_FREE(frame);
-       return status;
+       /*
+        * TODO: do a real async disconnect ...
+        *
+        * For now the caller needs to free rpc_cli
+        */
+       hs->child = NULL;
+
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
 }
 
-struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx,
-                                           struct winbindd_domain *domain,
-                                           struct winbindd_child *child)
+static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
 {
-       struct rpc_pipe_client *result;
-       struct wb_ndr_transport_priv *transp;
+       NTSTATUS status;
 
-       result = talloc(mem_ctx, struct rpc_pipe_client);
-       if (result == NULL) {
-               return NULL;
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
        }
-       result->abstract_syntax = ndr_table_wbint.syntax_id;
-       result->transfer_syntax = ndr_transfer_syntax;
-       result->dispatch = wb_ndr_dispatch;
-       result->dispatch_send = wb_ndr_dispatch_send;
-       result->dispatch_recv = wb_ndr_dispatch_recv;
-       result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
-       result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
-       result->desthost = NULL;
-       result->srv_name_slash = NULL;
 
-       /*
-        * Initialize a fake transport. Due to our own wb_ndr_dispatch
-        * function we don't use all the fragmentation engine in
-        * cli_pipe, which would use all the _read and _write
-        * functions in rpc_cli_transport. But we need a place to
-        * store the child struct in, and we're re-using
-        * result->transport->priv for that.
-        */
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
 
-       result->transport = talloc_zero(result, struct rpc_cli_transport);
-       if (result->transport == NULL) {
-               TALLOC_FREE(result);
-               return NULL;
+static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
+{
+       return true;
+}
+
+static void wbint_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);
        }
-       transp = talloc(result->transport, struct wb_ndr_transport_priv);
-       if (transp == NULL) {
-               TALLOC_FREE(result);
+       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 wbint_bh_ops = {
+       .name                   = "wbint",
+       .is_connected           = wbint_bh_is_connected,
+       .set_timeout            = wbint_bh_set_timeout,
+       .raw_call_send          = wbint_bh_raw_call_send,
+       .raw_call_recv          = wbint_bh_raw_call_recv,
+       .disconnect_send        = wbint_bh_disconnect_send,
+       .disconnect_recv        = wbint_bh_disconnect_recv,
+
+       .ref_alloc              = wbint_bh_ref_alloc,
+       .do_ndr_print           = wbint_bh_do_ndr_print,
+};
+
+/* initialise a wbint binding handle */
+struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
+                                               struct winbindd_domain *domain,
+                                               struct winbindd_child *child)
+{
+       struct dcerpc_binding_handle *h;
+       struct wbint_bh_state *hs;
+
+       h = dcerpc_binding_handle_create(mem_ctx,
+                                        &wbint_bh_ops,
+                                        NULL,
+                                        &ndr_table_winbind,
+                                        &hs,
+                                        struct wbint_bh_state,
+                                        __location__);
+       if (h == NULL) {
                return NULL;
        }
-       transp->domain = domain;
-       transp->child = child;
-       result->transport->priv = transp;
-       return result;
+       hs->domain = domain;
+       hs->child = child;
+
+       return h;
 }
 
 enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
                                          struct winbindd_cli_state *state)
 {
-       pipes_struct p;
-       struct api_struct *fns;
+       struct pipes_struct p;
+       const struct api_struct *fns;
        int num_fns;
        bool ret;
 
-       wbint_get_pipe_fns(&fns, &num_fns);
+       fns = winbind_get_pipe_fns(&num_fns);
 
        if (state->request->data.ndrcmd >= num_fns) {
                return WINBINDD_ERROR;