#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 */
struct wb_irpc_forward_state {
struct irpc_message *msg;
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,
+ server_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 *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->name = p+1;
+ } else if ((p = strchr(nstate->name, '@')) != NULL) {
+ /* upn */
+ nstate->domain = p + 1;
+ *p = 0;
+ } 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,
+ server_event_context(),
+ 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);
+ 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",
+ sid_string_dbg(&nstate->sid), 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",
+ sid_string_dbg(nstate->authority_sid), 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,
+ server_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;
+}
+
NTSTATUS wb_irpc_register(void)
{
NTSTATUS status;
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;
+ }
return NT_STATUS_OK;
}