summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/winbindd/winbindd_dual_ndr.c262
1 files changed, 262 insertions, 0 deletions
diff --git a/source3/winbindd/winbindd_dual_ndr.c b/source3/winbindd/winbindd_dual_ndr.c
index 79709a6b7b..65387f9558 100644
--- a/source3/winbindd/winbindd_dual_ndr.c
+++ b/source3/winbindd/winbindd_dual_ndr.c
@@ -198,6 +198,261 @@ static NTSTATUS wb_ndr_dispatch(struct rpc_pipe_client *cli,
return status;
}
+struct wbint_bh_state {
+ struct rpc_pipe_client *rpc_cli;
+};
+
+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->rpc_cli) {
+ return false;
+ }
+
+ return true;
+}
+
+struct wbint_bh_raw_call_state {
+ struct winbindd_domain *domain;
+ uint32_t opnum;
+ DATA_BLOB in_data;
+ struct winbindd_request request;
+ struct winbindd_response *response;
+ DATA_BLOB out_data;
+};
+
+static void wbint_bh_raw_call_done(struct tevent_req *subreq);
+
+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 wbint_bh_state *hs =
+ dcerpc_binding_handle_data(h,
+ struct wbint_bh_state);
+ struct wb_ndr_transport_priv *transport =
+ talloc_get_type_abort(hs->rpc_cli->transport->priv,
+ struct wb_ndr_transport_priv);
+ 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 wbint_bh_raw_call_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->domain = transport->domain;
+ state->opnum = opnum;
+ state->in_data.data = discard_const_p(uint8_t, in_data);
+ state->in_data.length = in_length;
+
+ ok = wbint_bh_is_connected(h);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+ return tevent_req_post(req, ev);
+ }
+
+ 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 = 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,
+ &state->request);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
+
+ return req;
+}
+
+static void wbint_bh_raw_call_done(struct tevent_req *subreq)
+{
+ 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) {
+ NTSTATUS status = map_nt_error_from_unix(err);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->out_data = data_blob_talloc(state,
+ state->response->extra_data.data,
+ state->response->length - sizeof(struct winbindd_response));
+ if (state->response->extra_data.data && !state->out_data.data) {
+ tevent_req_nomem(NULL, req);
+ return;
+ }
+
+ if (state->domain != NULL) {
+ wcache_store_ndr(state->domain, state->opnum,
+ &state->in_data, &state->out_data);
+ }
+
+ tevent_req_done(req);
+}
+
+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 wbint_bh_raw_call_state *state =
+ tevent_req_data(req,
+ struct wbint_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 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)
+{
+ struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct wbint_bh_state);
+ struct tevent_req *req;
+ struct wbint_bh_disconnect_state *state;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct wbint_bh_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ok = wbint_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 rpc_cli
+ */
+ hs->rpc_cli = NULL;
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS wbint_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 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);
+ }
+ 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,
+ .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 */
+static struct dcerpc_binding_handle *wbint_binding_handle(struct rpc_pipe_client *rpc_cli)
+{
+ struct dcerpc_binding_handle *h;
+ struct wbint_bh_state *hs;
+
+ h = dcerpc_binding_handle_create(rpc_cli,
+ &wbint_bh_ops,
+ NULL,
+ NULL, /* TODO */
+ &hs,
+ struct wbint_bh_state,
+ __location__);
+ if (h == NULL) {
+ return NULL;
+ }
+ hs->rpc_cli = rpc_cli;
+
+ return h;
+}
+
struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx,
struct winbindd_domain *domain,
struct winbindd_child *child)
@@ -241,6 +496,13 @@ struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx,
transp->domain = domain;
transp->child = child;
result->transport->priv = transp;
+
+ result->binding_handle = wbint_binding_handle(result);
+ if (result->binding_handle == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
return result;
}