#include "includes.h"
#include "winbindd/winbindd.h"
#include "winbindd/winbindd_proto.h"
-#include "librpc/gen_ndr/srv_wbint.h"
+#include "ntdomain.h"
+#include "librpc/rpc/dcesrv_core.h"
+#include "librpc/gen_ndr/ndr_winbind.h"
struct wbint_bh_state {
struct winbindd_domain *domain;
struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
struct wbint_bh_state);
- if (!hs->child) {
+ if ((hs->domain == NULL) && (hs->child == NULL)) {
return false;
}
DATA_BLOB out_data;
};
-static void wbint_bh_raw_call_done(struct tevent_req *subreq);
+static void wbint_bh_raw_call_child_done(struct tevent_req *subreq);
+static void wbint_bh_raw_call_domain_done(struct tevent_req *subreq);
static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
ok = wbint_bh_is_connected(h);
if (!ok) {
- tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
return tevent_req_post(req, ev);
}
if ((state->domain != NULL)
&& wcache_fetch_ndr(state, state->domain, state->opnum,
&state->in_data, &state->out_data)) {
+ DBG_DEBUG("Got opnum %"PRIu32" for domain %s from cache\n",
+ state->opnum, state->domain->name);
tevent_req_done(req);
return tevent_req_post(req, ev);
}
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, hs->child,
- &state->request);
+ if (hs->child != NULL) {
+ 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, wbint_bh_raw_call_child_done, req);
+ return req;
+ }
+
+ subreq = wb_domain_request_send(state, ev, hs->domain,
+ &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);
+ tevent_req_set_callback(subreq, wbint_bh_raw_call_domain_done, req);
return req;
}
-static void wbint_bh_raw_call_done(struct tevent_req *subreq)
+static void wbint_bh_raw_call_child_done(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq,
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);
+ tevent_req_oom(req);
+ return;
+ }
+
+ if (state->domain != NULL) {
+ wcache_store_ndr(state->domain, state->opnum,
+ &state->in_data, &state->out_data);
+ }
+
+ tevent_req_done(req);
+}
+
+static void wbint_bh_raw_call_domain_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_domain_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_oom(req);
return;
}
ok = wbint_bh_is_connected(h);
if (!ok) {
- tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
return tevent_req_post(req, ev);
}
/*
* TODO: do a real async disconnect ...
- *
- * For now the caller needs to free rpc_cli
*/
+ hs->domain = NULL;
hs->child = NULL;
tevent_req_done(req);
h = dcerpc_binding_handle_create(mem_ctx,
&wbint_bh_ops,
NULL,
- &ndr_table_wbint,
+ &ndr_table_winbind,
&hs,
struct wbint_bh_state,
__location__);
enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
- struct pipes_struct p;
- struct api_struct *fns;
- int num_fns;
- bool ret;
+ const struct dcesrv_endpoint_server *ep_server = NULL;
+ struct dcesrv_interface iface;
+ const struct ndr_syntax_id *abstract_syntax;
+ bool ok;
+ uint32_t opnum = state->request->data.ndrcmd;
+ struct pipes_struct *p;
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB in;
+ DATA_BLOB out;
+ NTSTATUS status;
- wbint_get_pipe_fns(&fns, &num_fns);
+ DBG_DEBUG("Running command %s (domain '%s')\n",
+ ndr_table_winbind.calls[opnum].name,
+ domain ? domain->name : "(null)");
- if (state->request->data.ndrcmd >= num_fns) {
+ ep_server = dcesrv_ep_server_byname(ndr_table_winbind.name);
+ if (ep_server == NULL) {
+ DBG_ERR("Failed to get DCE/RPC endpoint server '%s'\n",
+ ndr_table_winbind.name);
return WINBINDD_ERROR;
}
- DEBUG(10, ("winbindd_dual_ndrcmd: Running command %s (%s)\n",
- fns[state->request->data.ndrcmd].name,
- domain ? domain->name : "no domain"));
+ abstract_syntax = &ndr_table_winbind.syntax_id;
+ ok = ep_server->interface_by_uuid(&iface, &abstract_syntax->uuid,
+ abstract_syntax->if_version);
+ if (!ok) {
+ DBG_ERR("Failed to get DCE/RPC interface\n");
+ return WINBINDD_ERROR;
+ }
- ZERO_STRUCT(p);
- p.mem_ctx = talloc_stackframe();
- p.in_data.data = data_blob_const(state->request->extra_data.data,
- state->request->extra_len);
+ mem_ctx = talloc_stackframe();
+ if (mem_ctx == NULL) {
+ DBG_ERR("No memory");
+ return WINBINDD_ERROR;
+ }
- ret = fns[state->request->data.ndrcmd].fn(&p);
- if (!ret) {
- TALLOC_FREE(p.mem_ctx);
+ p = talloc_zero(mem_ctx, struct pipes_struct);
+ if (p == NULL) {
+ DBG_ERR("No memory\n");
+ return WINBINDD_ERROR;
+ }
+ p->mem_ctx = mem_ctx;
+
+ in = data_blob_const(state->request->extra_data.data,
+ state->request->extra_len);
+
+ status = iface.local(p, opnum, mem_ctx, &in, &out);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(mem_ctx);
return WINBINDD_ERROR;
}
state->response->extra_data.data =
- talloc_move(state->mem_ctx, &p.out_data.rdata.data);
- state->response->length += p.out_data.rdata.length;
- p.out_data.rdata.length = 0;
+ talloc_steal(state->mem_ctx, out.data);
+ state->response->length += out.length;
- TALLOC_FREE(p.mem_ctx);
+ TALLOC_FREE(mem_ctx);
if (state->response->extra_data.data == NULL) {
return WINBINDD_ERROR;
}
+
return WINBINDD_OK;
}