>From 41db87713146e9808f3fce18ab32701374cdcdb4 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
Date: Tue, 17 Jun 2014 17:16:14 +0100
Subject: [PATCH 1/2] LDAP: tokengroups do not work with id_provider=ldap

With plain LDAP provider we already have a sdap_handle, so it should be possible
that in the case where sdom->pvt == NULL sdap_id_op_connect_send() can be
skipped and sdap_get_ad_tokengroups_send() can be already send with the
sdap_handle passed to sdap_ad_tokengroups_initgr_mapping_send(). So we should
only fail if sdom->pvt == NULL and sh == NULL.

if find_subdomain_by_sid() failed we can check if there is only one domain in
the domain list (state->domain) and in this case continue with this domain since
the LDAP provider does not know about sub-domains and hence can only have one
configured domain.

Resolves:
https://fedorahosted.org/sssd/ticket/2345
---
 src/providers/ldap/sdap_async_groups.c        |  5 +-
 src/providers/ldap/sdap_async_initgroups_ad.c | 82 +++++++++++++++++++++++----
 src/util/domain_info_utils.c                  | 14 +++++
 src/util/util.h                               |  5 ++
 4 files changed, 93 insertions(+), 13 deletions(-)

diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index ead5d4060d66e27441dab961cee60be7f8cd8ee9..a21b0332e0acc111d387cc39fe8009794a4baa43 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -513,7 +513,8 @@ static int sdap_save_group(TALLOC_CTX *memctx,
     /* If this object has a SID available, we will determine the correct
      * domain by its SID. */
     if (sid_str != NULL) {
-        subdomain = find_subdomain_by_sid(get_domains_head(dom), sid_str);
+        subdomain = sss_get_domain_by_sid_ldap_fallback(get_domains_head(dom),
+                                                        sid_str);
         if (subdomain) {
             dom = subdomain;
         } else {
@@ -537,7 +538,7 @@ static int sdap_save_group(TALLOC_CTX *memctx,
             goto done;
         }
 
-        DEBUG(SSSDBG_TRACE_ALL, "AD group [%s] has type flags %#x.",
+        DEBUG(SSSDBG_TRACE_ALL, "AD group [%s] has type flags %#x.\n",
                                  group_name, ad_group_type);
         /* Only security groups from AD are considered for POSIX groups.
          * Additionally only global and universal group are taken to account
diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
index 80e4f29ad8556944c42669350339f62cfb28b36e..114552eba37be2bd73da72b77be18f4ad8917bbe 100644
--- a/src/providers/ldap/sdap_async_initgroups_ad.c
+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
@@ -606,7 +606,9 @@ static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req)
         }
         state->index++;
 
-        domain = find_subdomain_by_sid(state->domain, state->current_sid);
+        domain = sss_get_domain_by_sid_ldap_fallback(state->domain,
+                                                     state->current_sid);
+
         if (domain == NULL) {
             DEBUG(SSSDBG_MINOR_FAILURE, "SID %s does not belong to any known "
                                          "domain\n", state->current_sid);
@@ -691,6 +693,15 @@ struct sdap_ad_tokengroups_initgr_mapping_state {
 static void
 sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq);
 static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq);
+static errno_t handle_missing_pvt(TALLOC_CTX *mem_ctx,
+                                  struct tevent_context *ev,
+                                  struct sdap_options *opts,
+                                  const char *orig_dn,
+                                  int timeout,
+                                  const char *username,
+                                  struct sdap_handle *sh,
+                                  struct tevent_req *req,
+                                  tevent_req_fn callback);
 
 static struct tevent_req *
 sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx,
@@ -733,11 +744,18 @@ sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx,
 
     sdom = sdap_domain_get(opts, domain);
     if (sdom == NULL || sdom->pvt == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "No ID ctx available for [%s].\n",
-                                    domain->name);
-        ret = EINVAL;
-        goto immediately;
+        ret = handle_missing_pvt(mem_ctx, ev, opts, orig_dn, timeout,
+                                 state->username, sh, req,
+                                 sdap_ad_tokengroups_initgr_mapping_done);
+        if (ret == EOK) {
+            return req;
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE, "No ID ctx available for [%s].\n",
+                  domain->name);
+            goto immediately;
+        }
     }
+
     subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
     state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache);
     if (!state->op) {
@@ -872,7 +890,7 @@ static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq)
             continue;
         }
 
-        domain = find_subdomain_by_sid(get_domains_head(state->domain), sid);
+        domain = sss_get_domain_by_sid_ldap_fallback(state->domain, sid);
         if (domain == NULL) {
             DEBUG(SSSDBG_MINOR_FAILURE, "Domain not found for SID %s\n", sid);
             continue;
@@ -1028,10 +1046,16 @@ sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx,
 
     sdom = sdap_domain_get(opts, domain);
     if (sdom == NULL || sdom->pvt == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "No ID ctx available for [%s].\n",
-                                    domain->name);
-        ret = EINVAL;
-        goto immediately;
+        ret = handle_missing_pvt(mem_ctx, ev, opts, orig_dn, timeout,
+                                 state->username, sh, req,
+                                 sdap_ad_tokengroups_initgr_posix_tg_done);
+        if (ret == EOK) {
+            return req;
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE, "No ID ctx available for [%s].\n",
+                  domain->name);
+            goto immediately;
+        }
     }
     subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
     state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache);
@@ -1161,7 +1185,7 @@ sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq)
         sid = sids[i];
         DEBUG(SSSDBG_TRACE_LIBS, "Processing membership SID [%s]\n", sid);
 
-        domain = find_subdomain_by_sid(get_domains_head(state->domain), sid);
+        domain = sss_get_domain_by_sid_ldap_fallback(state->domain, sid);
         if (domain == NULL) {
             DEBUG(SSSDBG_MINOR_FAILURE, "Domain not found for SID %s\n", sid);
             continue;
@@ -1378,3 +1402,39 @@ errno_t sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req)
 
     return EOK;
 }
+
+static errno_t handle_missing_pvt(TALLOC_CTX *mem_ctx,
+                                  struct tevent_context *ev,
+                                  struct sdap_options *opts,
+                                  const char *orig_dn,
+                                  int timeout,
+                                  const char *username,
+                                  struct sdap_handle *sh,
+                                  struct tevent_req *req,
+                                  tevent_req_fn callback)
+{
+    struct tevent_req *subreq = NULL;
+    errno_t ret;
+
+    if (sh != NULL) {
+        /*  plain LDAP provider already has a sdap_handle */
+        subreq = sdap_get_ad_tokengroups_send(mem_ctx, ev, opts, sh, username,
+                                              orig_dn, timeout);
+        if (subreq == NULL) {
+            ret = ENOMEM;
+            tevent_req_error(req, ret);
+            goto done;
+        }
+
+        tevent_req_set_callback(subreq, callback, req);
+        ret = EOK;
+        goto done;
+
+    } else {
+        ret = EINVAL;
+        goto done;
+    }
+
+done:
+    return ret;
+}
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index a0fb7b2abe720e798817636b3810d36b7bbc0d93..2a87684394628bb170f008630b74b7e0ca168674 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -153,6 +153,20 @@ struct sss_domain_info *find_subdomain_by_sid(struct sss_domain_info *domain,
     return NULL;
 }
 
+struct sss_domain_info*
+sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
+                                    const char* sid)
+{
+    /* LDAP provider doesn't know about sub-domains and hence can only
+     * have one configured domain
+     */
+    if (strcmp(domain->provider, "ldap") == 0) {
+        return domain;
+    } else {
+        return find_subdomain_by_sid(get_domains_head(domain), sid);
+    }
+}
+
 struct sss_domain_info *
 find_subdomain_by_object_name(struct sss_domain_info *domain,
                               const char *object_name)
diff --git a/src/util/util.h b/src/util/util.h
index b605f230aa88958e4af598e5fa7896e5a74ce9d9..52135e6b07b6db58bf6c7a25cbfcf1b9ba4c447a 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -516,6 +516,11 @@ struct sss_domain_info *find_subdomain_by_name(struct sss_domain_info *domain,
                                                bool match_any);
 struct sss_domain_info *find_subdomain_by_sid(struct sss_domain_info *domain,
                                               const char *sid);
+
+struct sss_domain_info*
+sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
+                                    const char* sid);
+
 struct sss_domain_info *
 find_subdomain_by_object_name(struct sss_domain_info *domain,
                               const char *object_name);
-- 
1.9.3

