From f40bbaa3a21b4a9b8607f25eb831276cf16543b8 Mon Sep 17 00:00:00 2001
From: Ondrej Kos <okos@redhat.com>
Date: Tue, 3 Sep 2013 12:27:17 +0200
Subject: [PATCH 2/3] AD: Enable TokenGroups initgroups lookup

Process the group SIDs that are in sysdb. Update members of those and
those, which arent in db, are passed back as list of SIDs.

Resolves:
https://fedorahosted.org/sssd/ticket/1568
---
 src/providers/ldap/sdap_async.h               |   7 +-
 src/providers/ldap/sdap_async_initgroups.c    |  46 +++++----
 src/providers/ldap/sdap_async_initgroups_ad.c | 136 +++++++++++++++++++-------
 3 files changed, 133 insertions(+), 56 deletions(-)

diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index af41c719e40c263feeadaaf0f8919a61decbf852..0c682992a4037c30a347a19f06529d1920d2c099 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -286,10 +286,13 @@ sdap_get_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
                                         struct sdap_handle *sh,
                                         const char *name,
                                         const char *orig_dn,
-                                        int timeout);
+                                        int timeout,
+                                        bool use_id_mapping);
 
 errno_t
-sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req);
+sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req,
+                                        bool *_lookup_sids,
+                                        const char ***_group_sid_list);
 
 errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
                                    struct sss_domain_info *domain,
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index c27d587d15c6bdffd8fe168d96753793753165f6..31c33e785cd408bbc737c16433b97df9a84185ab 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -2547,6 +2547,7 @@ struct sdap_get_initgr_state {
     struct sdap_id_ctx *id_ctx;
     struct sdap_id_conn_ctx *conn;
     const char *name;
+    const char *cname;
     const char **grp_attrs;
     const char **user_attrs;
     const char *user_base_filter;
@@ -2594,6 +2595,7 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
     state->name = name;
     state->grp_attrs = grp_attrs;
     state->orig_user = NULL;
+    state->cname = NULL;
     state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
     state->user_base_iter = 0;
     state->user_search_bases = sdom->user_search_bases;
@@ -2688,7 +2690,6 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
     int ret;
     errno_t sret;
     const char *orig_dn;
-    const char *cname;
     bool in_transaction = false;
 
     DEBUG(9, ("Receiving info for the user\n"));
@@ -2761,7 +2762,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
     in_transaction = false;
 
     ret = sysdb_get_real_name(state, state->sysdb,
-                              state->dom, state->name, &cname);
+                              state->dom, state->name, &state->cname);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("Cannot canonicalize username\n"));
         tevent_req_error(req, ret);
@@ -2774,7 +2775,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
     case SDAP_SCHEMA_RFC2307:
         subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
                                           state->sysdb, state->dom, state->sh,
-                                          cname);
+                                          state->cname);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
             return;
@@ -2792,8 +2793,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
             return;
         }
 
-        if (state->use_id_mapping
-                && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
+        if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
             /* Take advantage of AD's tokenGroups mechanism to look up all
              * parent groups in a single request.
              */
@@ -2802,8 +2802,10 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
                                                              state->sysdb,
                                                              state->dom,
                                                              state->sh,
-                                                             cname, orig_dn,
-                                                             state->timeout);
+                                                             state->cname,
+                                                             orig_dn,
+                                                             state->timeout,
+                                                             state->use_id_mapping);
         } else if (state->opts->support_matching_rule
                     && dp_opt_get_bool(state->opts->basic,
                                        SDAP_AD_MATCHING_RULE_INITGROUPS)) {
@@ -2815,13 +2817,17 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
                                                             state->sysdb,
                                                             state->dom,
                                                             state->sh,
-                                                            cname, orig_dn,
+                                                            state->cname,
+                                                            orig_dn,
                                                             state->timeout);
         } else {
-            subreq = sdap_initgr_rfc2307bis_send(
-                    state, state->ev, state->opts, state->sysdb,
-                    state->dom, state->sh,
-                    cname, orig_dn);
+            subreq = sdap_initgr_rfc2307bis_send(state, state->ev,
+                                                 state->opts,
+                                                 state->sysdb,
+                                                 state->dom,
+                                                 state->sh,
+                                                 state->cname,
+                                                 orig_dn);
         }
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
@@ -2874,8 +2880,8 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
     char *dom_sid_str;
     char *group_sid_str;
     struct sdap_options *opts = state->opts;
-
-    DEBUG(9, ("Initgroups done\n"));
+    const char **group_sid_list;
+    bool lookup_sids = false;
 
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) {
@@ -2890,9 +2896,8 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
 
     case SDAP_SCHEMA_RFC2307BIS:
     case SDAP_SCHEMA_AD:
-        if (state->use_id_mapping
-                && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
-            ret = sdap_get_ad_tokengroups_initgroups_recv(subreq);
+        if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
+            ret = sdap_get_ad_tokengroups_initgroups_recv(subreq, &lookup_sids, &group_sid_list);
         }
         else if (state->opts->support_matching_rule
                 && dp_opt_get_bool(state->opts->basic,
@@ -2913,6 +2918,13 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
         break;
     }
 
+    if (lookup_sids) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Some of users TokenGroups not found in "
+                                  "cache, will perform LDAP lookup.\n"));
+    }
+
+    DEBUG(9, ("Initgroups done\n"));
+
     talloc_zfree(subreq);
     if (ret) {
         DEBUG(9, ("Error in initgroups: [%d][%s]\n",
diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
index e5649a2b9793253a55c48fba69cd3a902c0dc967..723b009c223118160e310e6a5efd5c4d12a85883 100644
--- a/src/providers/ldap/sdap_async_initgroups_ad.c
+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
@@ -305,6 +305,9 @@ struct sdap_ad_tokengroups_initgr_state {
     struct sss_domain_info *domain;
     struct sdap_handle *sh;
     const char *username;
+    bool use_id_mapping;
+    bool lookup_sids;
+    const char **group_sid_list;
 };
 
 static void
@@ -319,7 +322,8 @@ sdap_get_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
                                         struct sdap_handle *sh,
                                         const char *name,
                                         const char *orig_dn,
-                                        int timeout)
+                                        int timeout,
+                                        bool use_id_mapping)
 {
     struct tevent_req *req;
     struct tevent_req *subreq;
@@ -336,6 +340,9 @@ sdap_get_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
     state->domain = domain;
     state->sh = sh;
     state->username = name;
+    state->use_id_mapping = use_id_mapping;
+    state->lookup_sids = false;
+    state->group_sid_list = NULL;
 
     subreq = sdap_get_generic_send(
             state, state->ev, state->opts, state->sh,
@@ -359,6 +366,7 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
     errno_t ret, sret;
     enum idmap_error_code err;
     size_t user_count, group_count, i;
+    size_t sid_count = 0;
     TALLOC_CTX *tmp_ctx;
     bool in_transaction = false;
     char *sid_str;
@@ -442,6 +450,14 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
     }
     group_count = 0;
 
+    if (!state->use_id_mapping) {
+        state->group_sid_list = talloc_array(state, const char*, el->num_values + 1);
+        if (!state->group_sid_list) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
     for (i = 0; i < el->num_values; i++) {
         /* Get the SID and convert it to a GID */
 
@@ -464,20 +480,29 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
             DEBUG(SSSDBG_TRACE_FUNC, ("Skipping built-in object.\n"));
             ret = EOK;
             continue;
-        } else if (ret != EOK) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("Could not convert SID to GID: [%s]. Skipping\n",
-                   strerror(ret)));
-            continue;
         }
 
-        DEBUG(SSSDBG_TRACE_LIBS,
-              ("Processing membership GID [%lu]\n",
-               gid));
+        if (state->use_id_mapping) {
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE,
+                      ("Could not convert SID to GID: [%s]. Skipping\n",
+                       strerror(ret)));
+                continue;
+            }
+
+            DEBUG(SSSDBG_TRACE_LIBS,
+                  ("Processing membership GID [%lu]\n",
+                   gid));
+
+            /* Check whether this GID already exists in the sysdb */
+            ret = sysdb_search_group_by_gid(tmp_ctx, state->sysdb, state->domain,
+                                            gid, attrs, &msg);
+        } else {
+            ret = sysdb_search_group_by_sid_str(tmp_ctx, state->sysdb,
+                                                state->domain, sid_str, attrs,
+                                                &msg);
+        }
 
-        /* Check whether this GID already exists in the sysdb */
-        ret = sysdb_search_group_by_gid(tmp_ctx, state->sysdb, state->domain,
-                                        gid, attrs, &msg);
         if (ret == EOK) {
             group_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
             if (!group_name) {
@@ -486,22 +511,58 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
                 ret = EINVAL;
                 goto done;
             }
+
+            ldap_grouplist[group_count] =
+                    talloc_strdup(ldap_grouplist, group_name);
+            if (!ldap_grouplist[group_count]) {
+                ret = ENOMEM;
+                goto done;
+            }
+
+            group_count++;
+
         } else if (ret == ENOENT) {
-            /* This is a new group. For now, we will store it
-             * under the name of its SID. When a direct lookup of
-             * the group or its GID occurs, it will replace this
-             * temporary entry.
-             */
-            group_name = sid_str;
-            ret = sysdb_add_incomplete_group(state->sysdb,
-                                             state->domain,
-                                             group_name, gid,
-                                             NULL, sid_str, false, now);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_MINOR_FAILURE,
-                      ("Could not create incomplete group: [%s]\n",
-                       strerror(ret)));
-                goto done;
+            if (state->use_id_mapping) {
+                /* This is a new group. For now, we will store it
+                 * under the name of its SID. When a direct lookup of
+                 * the group or its GID occurs, it will replace this
+                 * temporary entry.
+                 */
+                group_name = sid_str;
+                ret = sysdb_add_incomplete_group(state->sysdb,
+                                                 state->domain,
+                                                 group_name, gid,
+                                                 NULL, sid_str, false, now);
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_MINOR_FAILURE,
+                          ("Could not create incomplete group: [%s]\n",
+                           strerror(ret)));
+                    goto done;
+                }
+
+                ldap_grouplist[group_count] =
+                        talloc_strdup(ldap_grouplist, group_name);
+                if (!ldap_grouplist[group_count]) {
+                    ret = ENOMEM;
+                    goto done;
+                }
+
+                group_count++;
+
+            } else {
+                DEBUG(SSSDBG_MINOR_FAILURE, ("SID [%s] not found in cache, "
+                                             "will be looked up\n", sid_str));
+
+                state->lookup_sids = true;
+
+                state->group_sid_list[sid_count] =
+                        talloc_strdup(state, sid_str);
+                if (!state->group_sid_list[sid_count]) {
+                    ret = ENOMEM;
+                    goto done;
+                }
+
+                sid_count++;
             }
         } else {
             /* Unexpected error */
@@ -510,17 +571,9 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq)
                    strerror(ret)));
             goto done;
         }
-
-        ldap_grouplist[group_count] =
-                talloc_strdup(ldap_grouplist, group_name);
-        if (!ldap_grouplist[group_count]) {
-            ret = ENOMEM;
-            goto done;
-        }
-
-        group_count++;
     }
     ldap_grouplist[group_count] = NULL;
+    state->group_sid_list[sid_count] = NULL;
 
     /* Get the current sysdb group list for this user
      * so we can update it.
@@ -582,8 +635,17 @@ done:
 }
 
 errno_t
-sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req)
+sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req,
+                                        bool *_lookup_sids,
+                                        const char ***_group_sid_list)
 {
+    struct sdap_ad_tokengroups_initgr_state *state =
+            tevent_req_data(req, struct sdap_ad_tokengroups_initgr_state);
+
     TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *_lookup_sids = state->lookup_sids;
+    *_group_sid_list = state->group_sid_list;
+
     return EOK;
 }
-- 
1.8.1.4

