summaryrefslogtreecommitdiffstats
path: root/source3/winbindd/winbindd_irpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/winbindd/winbindd_irpc.c')
-rw-r--r--source3/winbindd/winbindd_irpc.c891
1 files changed, 891 insertions, 0 deletions
diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c
new file mode 100644
index 0000000..232772d
--- /dev/null
+++ b/source3/winbindd/winbindd_irpc.c
@@ -0,0 +1,891 @@
+/*
+ Unix SMB/CIFS implementation.
+ async implementation of commands submitted over IRPC
+ Copyright (C) Volker Lendecke 2009
+ Copyright (C) Guenther Deschner 2009
+ Copyright (C) Andrew Bartlett 2014
+ Copyright (C) Andrew Tridgell 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+#include "librpc/gen_ndr/ndr_winbind_c.h"
+#include "source4/lib/messaging/irpc.h"
+#include "librpc/gen_ndr/ndr_winbind.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "libcli/security/dom_sid.h"
+#include "passdb/lookup_sid.h" /* only for LOOKUP_NAME_NO_NSS flag */
+#include "librpc/gen_ndr/ndr_irpc.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "lib/global_contexts.h"
+#include "lib/param/param.h"
+#include "messages.h"
+
+struct imessaging_context *winbind_imessaging_context(void)
+{
+ static struct imessaging_context *msg = NULL;
+ struct messaging_context *msg_ctx;
+ struct server_id myself;
+ struct loadparm_context *lp_ctx;
+
+ if (msg != NULL) {
+ return msg;
+ }
+
+ msg_ctx = global_messaging_context();
+ if (msg_ctx == NULL) {
+ smb_panic("global_messaging_context failed\n");
+ }
+ myself = messaging_server_id(msg_ctx);
+
+ lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
+ if (lp_ctx == NULL) {
+ smb_panic("Could not load smb.conf to init winbindd's imessaging context.\n");
+ }
+
+ /*
+ * Note we MUST use the NULL context here, not the autofree context,
+ * to avoid side effects in forked children exiting.
+ */
+ msg = imessaging_init(NULL, lp_ctx, myself, global_event_context());
+ talloc_unlink(NULL, lp_ctx);
+
+ if (msg == NULL) {
+ smb_panic("Could not init winbindd's messaging context.\n");
+ }
+ return msg;
+}
+
+struct wb_irpc_forward_state {
+ struct irpc_message *msg;
+ const char *opname;
+ struct dcesrv_call_state *dce_call;
+};
+
+/*
+ called when the forwarded rpc request is finished
+ */
+static void wb_irpc_forward_callback(struct tevent_req *subreq)
+{
+ struct wb_irpc_forward_state *st =
+ tevent_req_callback_data(subreq,
+ struct wb_irpc_forward_state);
+ const char *opname = st->opname;
+ NTSTATUS status;
+
+ status = dcerpc_binding_handle_call_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("RPC callback failed for %s - %s\n",
+ opname, nt_errstr(status)));
+ irpc_send_reply(st->msg, status);
+ return;
+ }
+
+ irpc_send_reply(st->msg, status);
+}
+
+
+
+/**
+ * Forward a RPC call using IRPC to another task
+ */
+
+static NTSTATUS wb_irpc_forward_rpc_call(struct irpc_message *msg, TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ void *r, uint32_t callid,
+ const char *opname,
+ struct winbindd_domain *domain,
+ uint32_t timeout)
+{
+ struct wb_irpc_forward_state *st;
+ struct dcerpc_binding_handle *binding_handle;
+ struct tevent_req *subreq;
+
+ st = talloc(mem_ctx, struct wb_irpc_forward_state);
+ if (st == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ st->msg = msg;
+ st->opname = opname;
+
+ binding_handle = dom_child_handle(domain);
+ if (binding_handle == NULL) {
+ DEBUG(0,("%s: Failed to forward request to winbind handler for %s\n",
+ opname, domain->name));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* reset timeout for the handle */
+ dcerpc_binding_handle_set_timeout(binding_handle, timeout);
+
+ /* forward the call */
+ subreq = dcerpc_binding_handle_call_send(st, ev,
+ binding_handle,
+ NULL, &ndr_table_winbind,
+ callid,
+ msg, r);
+ if (subreq == NULL) {
+ DEBUG(0,("%s: Failed to forward request to winbind handler for %s\n",
+ opname, domain->name));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* mark the request as replied async */
+ msg->defer_reply = true;
+
+ /* setup the callback */
+ tevent_req_set_callback(subreq, wb_irpc_forward_callback, st);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS wb_irpc_DsrUpdateReadOnlyServerDnsRecords(struct irpc_message *msg,
+ struct winbind_DsrUpdateReadOnlyServerDnsRecords *req)
+{
+ struct winbindd_domain *domain = find_our_domain();
+ if (domain == NULL) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ DEBUG(5, ("wb_irpc_DsrUpdateReadOnlyServerDnsRecords called\n"));
+
+ return wb_irpc_forward_rpc_call(msg, msg,
+ global_event_context(),
+ req, NDR_WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
+ "winbind_DsrUpdateReadOnlyServerDnsRecords",
+ domain, IRPC_CALL_TIMEOUT);
+}
+
+static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
+ struct winbind_SamLogon *req)
+{
+ struct winbindd_domain *domain;
+ struct netr_IdentityInfo *identity_info;
+ const char *target_domain_name = NULL;
+ const char *account_name = NULL;
+
+ /*
+ * Make sure we start with authoritative=true,
+ * it will only set to false if we don't know the
+ * domain.
+ */
+ req->out.authoritative = true;
+
+ switch (req->in.logon_level) {
+ case NetlogonInteractiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceTransitiveInformation:
+ if (req->in.logon.password == NULL) {
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+ identity_info = &req->in.logon.password->identity_info;
+ break;
+
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
+ if (req->in.logon.network == NULL) {
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ identity_info = &req->in.logon.network->identity_info;
+ break;
+
+ case NetlogonGenericInformation:
+ if (req->in.logon.generic == NULL) {
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ identity_info = &req->in.logon.generic->identity_info;
+ break;
+
+ default:
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ target_domain_name = identity_info->domain_name.string;
+ if (target_domain_name == NULL) {
+ target_domain_name = "";
+ }
+
+ account_name = identity_info->account_name.string;
+ if (account_name == NULL) {
+ account_name = "";
+ }
+
+ if (IS_DC && target_domain_name[0] == '\0') {
+ const char *p = NULL;
+
+ p = strchr_m(account_name, '@');
+ if (p != NULL) {
+ target_domain_name = p + 1;
+ }
+ }
+
+ if (IS_DC && target_domain_name[0] == '\0') {
+ DBG_ERR("target_domain[%s] account[%s]\n",
+ target_domain_name, account_name);
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ domain = find_auth_domain(0, target_domain_name);
+ if (domain == NULL) {
+ DBG_INFO("target_domain[%s] for account[%s] not known\n",
+ target_domain_name, account_name);
+ req->out.result = NT_STATUS_NO_SUCH_USER;
+ req->out.authoritative = 0;
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5, ("wb_irpc_SamLogon called\n"));
+
+ return wb_irpc_forward_rpc_call(msg, msg,
+ global_event_context(),
+ req, NDR_WINBIND_SAMLOGON,
+ "winbind_SamLogon",
+ domain, IRPC_CALL_TIMEOUT);
+}
+
+static NTSTATUS wb_irpc_LogonControl(struct irpc_message *msg,
+ struct winbind_LogonControl *req)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *domain_name = NULL;
+ struct winbindd_domain *domain = NULL;
+
+ DEBUG(5, ("wb_irpc_LogonControl called\n"));
+
+ switch (req->in.function_code) {
+ case NETLOGON_CONTROL_REDISCOVER:
+ case NETLOGON_CONTROL_TC_QUERY:
+ case NETLOGON_CONTROL_CHANGE_PASSWORD:
+ case NETLOGON_CONTROL_TC_VERIFY:
+ if (req->in.data->domain == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ domain_name = talloc_strdup(frame, req->in.data->domain);
+ if (domain_name == NULL) {
+ req->out.result = WERR_NOT_ENOUGH_MEMORY;
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ break;
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (req->in.function_code == NETLOGON_CONTROL_REDISCOVER) {
+ char *p = NULL;
+
+ /*
+ * NETLOGON_CONTROL_REDISCOVER
+ * get's an optional \dcname appended to the domain name
+ */
+ p = strchr_m(domain_name, '\\');
+ if (p != NULL) {
+ *p = '\0';
+ }
+ }
+
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ req->out.result = WERR_NO_SUCH_DOMAIN;
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ TALLOC_FREE(frame);
+ return wb_irpc_forward_rpc_call(msg, msg,
+ global_event_context(),
+ req, NDR_WINBIND_LOGONCONTROL,
+ "winbind_LogonControl",
+ domain, 45 /* timeout */);
+}
+
+static NTSTATUS wb_irpc_GetForestTrustInformation(struct irpc_message *msg,
+ struct winbind_GetForestTrustInformation *req)
+{
+ struct winbindd_domain *domain = NULL;
+
+ if (req->in.trusted_domain_name == NULL) {
+ req->out.result = WERR_NO_SUCH_DOMAIN;
+ return NT_STATUS_OK;
+ }
+
+ domain = find_trust_from_name_noinit(req->in.trusted_domain_name);
+ if (domain == NULL) {
+ req->out.result = WERR_NO_SUCH_DOMAIN;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * checking for domain->internal and domain->primary
+ * makes sure we only do some work when running as DC.
+ */
+
+ if (domain->internal) {
+ req->out.result = WERR_NO_SUCH_DOMAIN;
+ return NT_STATUS_OK;
+ }
+
+ if (domain->primary) {
+ req->out.result = WERR_NO_SUCH_DOMAIN;
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5, ("wb_irpc_GetForestTrustInformation called\n"));
+
+ return wb_irpc_forward_rpc_call(msg, msg,
+ global_event_context(),
+ req, NDR_WINBIND_GETFORESTTRUSTINFORMATION,
+ "winbind_GetForestTrustInformation",
+ domain, 45 /* timeout */);
+}
+
+static NTSTATUS wb_irpc_SendToSam(struct irpc_message *msg,
+ struct winbind_SendToSam *req)
+{
+ /* TODO make sure that it is RWDC */
+ struct winbindd_domain *domain = find_our_domain();
+ if (domain == NULL) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ DEBUG(5, ("wb_irpc_SendToSam called\n"));
+
+ return wb_irpc_forward_rpc_call(msg, msg,
+ global_event_context(),
+ req, NDR_WINBIND_SENDTOSAM,
+ "winbind_SendToSam",
+ domain, IRPC_CALL_TIMEOUT);
+}
+
+struct wb_irpc_lsa_LookupSids3_state {
+ struct irpc_message *msg;
+ struct lsa_LookupSids3 *req;
+};
+
+static void wb_irpc_lsa_LookupSids3_done(struct tevent_req *subreq);
+
+static NTSTATUS wb_irpc_lsa_LookupSids3_call(struct irpc_message *msg,
+ struct lsa_LookupSids3 *req)
+{
+ struct wb_irpc_lsa_LookupSids3_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ struct dom_sid *sids = NULL;
+ uint32_t i;
+
+ state = talloc_zero(msg, struct wb_irpc_lsa_LookupSids3_state);
+ if (state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ state->msg = msg;
+ state->req = req;
+
+ state->req->out.domains = talloc_zero(state->msg,
+ struct lsa_RefDomainList *);
+ if (state->req->out.domains == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req->out.names = talloc_zero(state->msg,
+ struct lsa_TransNameArray2);
+ if (state->req->out.names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req->out.count = talloc_zero(state->msg, uint32_t);
+ if (state->req->out.count == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ state->req->out.names->names = talloc_zero_array(state->msg,
+ struct lsa_TranslatedName2,
+ req->in.sids->num_sids);
+ if (state->req->out.names->names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sids = talloc_zero_array(state, struct dom_sid,
+ req->in.sids->num_sids);
+ if (sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < req->in.sids->num_sids; i++) {
+ if (req->in.sids->sids[i].sid == NULL) {
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ sids[i] = *req->in.sids->sids[i].sid;
+ }
+
+ subreq = wb_lookupsids_send(msg,
+ global_event_context(),
+ sids, req->in.sids->num_sids);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, wb_irpc_lsa_LookupSids3_done, state);
+ msg->defer_reply = true;
+
+ return NT_STATUS_OK;
+}
+
+static void wb_irpc_lsa_LookupSids3_done(struct tevent_req *subreq)
+{
+ struct wb_irpc_lsa_LookupSids3_state *state =
+ tevent_req_callback_data(subreq,
+ struct wb_irpc_lsa_LookupSids3_state);
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TransNameArray *names = NULL;
+ NTSTATUS status;
+ uint32_t i;
+
+ status = wb_lookupsids_recv(subreq, state->msg,
+ &domains, &names);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("RPC callback failed for %s - %s\n",
+ __func__, nt_errstr(status)));
+ irpc_send_reply(state->msg, status);
+ return;
+ }
+
+ if (names->count > state->req->in.sids->num_sids) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ DEBUG(0,("RPC callback failed for %s - %s\n",
+ __func__, nt_errstr(status)));
+ irpc_send_reply(state->msg, status);
+ return;
+ }
+
+ *state->req->out.domains = domains;
+ for (i = 0; i < names->count; i++) {
+ struct lsa_TranslatedName2 *n2 =
+ &state->req->out.names->names[i];
+
+ n2->sid_type = names->names[i].sid_type;
+ n2->name = names->names[i].name;
+ n2->sid_index = names->names[i].sid_index;
+ n2->unknown = 0;
+
+ if (n2->sid_type != SID_NAME_UNKNOWN) {
+ (*state->req->out.count)++;
+ }
+ }
+ state->req->out.names->count = names->count;
+
+ if (*state->req->out.count == 0) {
+ state->req->out.result = NT_STATUS_NONE_MAPPED;
+ } else if (*state->req->out.count != names->count) {
+ state->req->out.result = NT_STATUS_SOME_NOT_MAPPED;
+ } else {
+ state->req->out.result = NT_STATUS_OK;
+ }
+
+ irpc_send_reply(state->msg, NT_STATUS_OK);
+ return;
+}
+
+struct wb_irpc_lsa_LookupNames4_name {
+ void *state;
+ uint32_t idx;
+ const char *namespace;
+ const char *domain;
+ char *name;
+ struct dom_sid sid;
+ enum lsa_SidType type;
+ struct dom_sid *authority_sid;
+};
+
+struct wb_irpc_lsa_LookupNames4_state {
+ struct irpc_message *msg;
+ struct lsa_LookupNames4 *req;
+ struct wb_irpc_lsa_LookupNames4_name *names;
+ uint32_t num_pending;
+ uint32_t num_domain_sids;
+ struct dom_sid *domain_sids;
+};
+
+static void wb_irpc_lsa_LookupNames4_done(struct tevent_req *subreq);
+
+static NTSTATUS wb_irpc_lsa_LookupNames4_call(struct irpc_message *msg,
+ struct lsa_LookupNames4 *req)
+{
+ struct wb_irpc_lsa_LookupNames4_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint32_t i;
+
+
+ state = talloc_zero(msg, struct wb_irpc_lsa_LookupNames4_state);
+ if (state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ state->msg = msg;
+ state->req = req;
+
+ state->req->out.domains = talloc_zero(state->msg,
+ struct lsa_RefDomainList *);
+ if (state->req->out.domains == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req->out.sids = talloc_zero(state->msg,
+ struct lsa_TransSidArray3);
+ if (state->req->out.sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req->out.count = talloc_zero(state->msg, uint32_t);
+ if (state->req->out.count == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ state->req->out.sids->sids = talloc_zero_array(state->msg,
+ struct lsa_TranslatedSid3,
+ req->in.num_names);
+ if (state->req->out.sids->sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ state->names = talloc_zero_array(state,
+ struct wb_irpc_lsa_LookupNames4_name,
+ req->in.num_names);
+ if (state->names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < req->in.num_names; i++) {
+ struct wb_irpc_lsa_LookupNames4_name *nstate =
+ &state->names[i];
+ char *p = NULL;
+
+ if (req->in.names[i].string == NULL) {
+ DBG_ERR("%s: name[%s] NT_STATUS_REQUEST_NOT_ACCEPTED.\n",
+ __location__, req->in.names[i].string);
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+ nstate->state = state;
+ nstate->idx = i;
+ nstate->name = talloc_strdup(state->names,
+ req->in.names[i].string);
+ if (nstate->name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ nstate->type = SID_NAME_UNKNOWN;
+
+ /* cope with the name being a fully qualified name */
+ p = strchr(nstate->name, '\\');
+ if (p != NULL) {
+ *p = 0;
+ nstate->domain = nstate->name;
+ nstate->namespace = nstate->domain;
+ nstate->name = p+1;
+ } else if ((p = strchr(nstate->name, '@')) != NULL) {
+ /* upn */
+ nstate->domain = "";
+ nstate->namespace = p + 1;
+ } else {
+ /*
+ * TODO: select the domain based on
+ * req->in.level and req->in.client_revision
+ *
+ * For now we don't allow this.
+ */
+ DBG_ERR("%s: name[%s] NT_STATUS_REQUEST_NOT_ACCEPTED.\n",
+ __location__, nstate->name);
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ subreq = wb_lookupname_send(msg,
+ global_event_context(),
+ nstate->namespace,
+ nstate->domain,
+ nstate->name,
+ LOOKUP_NAME_NO_NSS);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq,
+ wb_irpc_lsa_LookupNames4_done,
+ nstate);
+ state->num_pending++;
+ }
+
+ msg->defer_reply = true;
+
+ return NT_STATUS_OK;
+}
+
+static void wb_irpc_lsa_LookupNames4_domains_done(struct tevent_req *subreq);
+
+static void wb_irpc_lsa_LookupNames4_done(struct tevent_req *subreq)
+{
+ struct wb_irpc_lsa_LookupNames4_name *nstate =
+ (struct wb_irpc_lsa_LookupNames4_name *)
+ tevent_req_callback_data_void(subreq);
+ struct wb_irpc_lsa_LookupNames4_state *state =
+ talloc_get_type_abort(nstate->state,
+ struct wb_irpc_lsa_LookupNames4_state);
+ struct dom_sid_buf buf;
+ NTSTATUS status;
+
+ SMB_ASSERT(state->num_pending > 0);
+ state->num_pending--;
+ status = wb_lookupname_recv(subreq, &nstate->sid, &nstate->type);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("RPC callback failed for %s - %s\n",
+ __func__, nt_errstr(status)));
+ irpc_send_reply(state->msg, status);
+ return;
+ }
+
+ status = dom_sid_split_rid(state, &nstate->sid,
+ &nstate->authority_sid, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("dom_sid_split_rid(%s) failed - %s\n",
+ dom_sid_str_buf(&nstate->sid, &buf),
+ nt_errstr(status));
+ irpc_send_reply(state->msg, status);
+ return;
+ }
+
+ status = add_sid_to_array_unique(state,
+ nstate->authority_sid,
+ &state->domain_sids,
+ &state->num_domain_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("add_sid_to_array_unique(%s) failed - %s\n",
+ dom_sid_str_buf(nstate->authority_sid, &buf),
+ nt_errstr(status));
+ irpc_send_reply(state->msg, status);
+ return;
+ }
+
+ if (state->num_pending > 0) {
+ /*
+ * wait for more...
+ */
+ return;
+ }
+
+ /*
+ * Now resolve all domains back to a name
+ * to get a good lsa_RefDomainList
+ */
+ subreq = wb_lookupsids_send(state,
+ global_event_context(),
+ state->domain_sids,
+ state->num_domain_sids);
+ if (subreq == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ DBG_ERR("wb_lookupsids_send - %s\n",
+ nt_errstr(status));
+ irpc_send_reply(state->msg, status);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ wb_irpc_lsa_LookupNames4_domains_done,
+ state);
+
+ return;
+}
+
+static void wb_irpc_lsa_LookupNames4_domains_done(struct tevent_req *subreq)
+{
+ struct wb_irpc_lsa_LookupNames4_state *state =
+ tevent_req_callback_data(subreq,
+ struct wb_irpc_lsa_LookupNames4_state);
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TransNameArray *names = NULL;
+ NTSTATUS status;
+ uint32_t i;
+
+ status = wb_lookupsids_recv(subreq, state->msg,
+ &domains, &names);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("RPC callback failed for %s - %s\n",
+ __func__, nt_errstr(status)));
+ irpc_send_reply(state->msg, status);
+ return;
+ }
+
+ *state->req->out.domains = domains;
+ for (i = 0; i < state->req->in.num_names; i++) {
+ struct wb_irpc_lsa_LookupNames4_name *nstate =
+ &state->names[i];
+ struct lsa_TranslatedSid3 *s3 =
+ &state->req->out.sids->sids[i];
+ uint32_t di;
+
+ s3->sid_type = nstate->type;
+ if (s3->sid_type != SID_NAME_UNKNOWN) {
+ s3->sid = &nstate->sid;
+ } else {
+ s3->sid = NULL;
+ }
+ s3->sid_index = UINT32_MAX;
+ for (di = 0; di < domains->count; di++) {
+ bool match;
+
+ if (domains->domains[di].sid == NULL) {
+ continue;
+ }
+
+ match = dom_sid_equal(nstate->authority_sid,
+ domains->domains[di].sid);
+ if (match) {
+ s3->sid_index = di;
+ break;
+ }
+ }
+ if (s3->sid_type != SID_NAME_UNKNOWN) {
+ (*state->req->out.count)++;
+ }
+ }
+ state->req->out.sids->count = state->req->in.num_names;
+
+ if (*state->req->out.count == 0) {
+ state->req->out.result = NT_STATUS_NONE_MAPPED;
+ } else if (*state->req->out.count != state->req->in.num_names) {
+ state->req->out.result = NT_STATUS_SOME_NOT_MAPPED;
+ } else {
+ state->req->out.result = NT_STATUS_OK;
+ }
+
+ irpc_send_reply(state->msg, NT_STATUS_OK);
+ return;
+}
+
+struct wb_irpc_GetDCName_state {
+ struct irpc_message *msg;
+ struct wbint_DsGetDcName *req;
+};
+
+static void wb_irpc_GetDCName_done(struct tevent_req *subreq);
+
+static NTSTATUS wb_irpc_GetDCName(struct irpc_message *msg,
+ struct wbint_DsGetDcName *req)
+{
+
+ struct tevent_req *subreq = NULL;
+ struct wb_irpc_GetDCName_state *state = NULL;
+
+ state = talloc_zero(msg, struct wb_irpc_GetDCName_state);
+ if (state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ state->msg = msg;
+ state->req = req;
+
+ subreq = wb_dsgetdcname_send(msg,
+ global_event_context(),
+ req->in.domain_name,
+ req->in.domain_guid,
+ req->in.site_name,
+ req->in.flags);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tevent_req_set_callback(subreq,
+ wb_irpc_GetDCName_done,
+ state);
+
+ msg->defer_reply = true;
+
+ return NT_STATUS_OK;
+}
+
+static void wb_irpc_GetDCName_done(struct tevent_req *subreq)
+{
+ struct wb_irpc_GetDCName_state *state = tevent_req_callback_data(
+ subreq, struct wb_irpc_GetDCName_state);
+ NTSTATUS status;
+
+ status = wb_dsgetdcname_recv(subreq, state->msg,
+ state->req->out.dc_info);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_INFO("RPC callback failed for %s - %s\n", "DSGETDCNAME",
+ nt_errstr(status));
+ }
+
+ state->req->out.result = status;
+
+ irpc_send_reply(state->msg, NT_STATUS_OK);
+}
+
+NTSTATUS wb_irpc_register(void)
+{
+ NTSTATUS status;
+
+ status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
+ wb_irpc_DsrUpdateReadOnlyServerDnsRecords, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SAMLOGON,
+ wb_irpc_SamLogon, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
+ WINBIND_LOGONCONTROL,
+ wb_irpc_LogonControl, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
+ WINBIND_GETFORESTTRUSTINFORMATION,
+ wb_irpc_GetForestTrustInformation, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SENDTOSAM,
+ wb_irpc_SendToSam, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = IRPC_REGISTER(winbind_imessaging_context(),
+ lsarpc, LSA_LOOKUPSIDS3,
+ wb_irpc_lsa_LookupSids3_call, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = IRPC_REGISTER(winbind_imessaging_context(),
+ lsarpc, LSA_LOOKUPNAMES4,
+ wb_irpc_lsa_LookupNames4_call, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = IRPC_REGISTER(winbind_imessaging_context(),
+ winbind, WBINT_DSGETDCNAME,
+ wb_irpc_GetDCName, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}