#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;