-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 03/22/2011 03:15 PM, Stephen Gallagher wrote:
> On 03/22/2011 03:04 PM, Stephen Gallagher wrote:
>> On 03/22/2011 02:35 PM, Jakub Hrozek wrote:
>>> On 03/22/2011 06:36 PM, Jakub Hrozek wrote:
>>>> Fixes:
>>>> https://fedorahosted.org/sssd/ticket/822
> 
>>>> [PATCH 1/2] Add originalDN to fake groups
>>>> Since we are storing expired groups during initgroups now and some of
>>>> the group processing routines depend on originalDN, I think the
>>>> originalDN should be stored with the fake groups.
> 
>>>> This would help for instance sdap_nested_group_process_step() which
>>>> would find the expired group in sysdb and refresh it immediately instead
>>>> of trying blind lookup for users and then groups.
> 
>>>> [PATCH 2/2] Use fake groups during IPA schema initgroups
>>>> Do not just store non-expired groups from LDAP during initgroups and
>>>> risks that some of the members might not be there. Instead, add fake
>>>> groups for those that are not yet cached and build correct
>>>> member/memberof relationship.
> 
>>>> There's one more optimization I'd like to make, although I'm not sure if
>>>> it is 1.5 material. Since we do not fetch the memberof attribute for
>>>> LDAP groups, we must look at all groups when searching for direct
>>>> parents for a group (see sdap_initgr_nested_get_direct_parents()).
> 
>>>> Having the memberof attribute would allow for an optimization where we
>>>> would first filter all parents and then just the direct ones. That would
>>>> be very similar to what we can do for the user since we search the
>>>> groups based on users' memberof anyway.
> 
>>>>    Jakub
> 
>>> Attached patches are rebased on top of Stephen's multiname patches.
> 
> 
>> Nack. The rebase needs to add support for sysdb_attrs_primary_name() in
>> sdap_initgr_nested_store_group() (instead of
>> sysdb_attrs_get_string(SYSDB_NAME))
> 
>> Otherwise, this would be regressing functionality from my multiname patches.
> 
> 
> Attaching a simple patch to address this. Assuming this is approved,
> I'll squash it in and push.
> 
> 


Jakub discovered another problem that's related to both this patch and
my multi-name patches. It would be too much trouble to stick this back
in the middle of the pile, so I've added it as patch 0004 of the set.
Testing should be done only with ALL patches in place.

I've reattached all four patches (Jakub's original two, my original fix
for his second patch which should be squashed in, and my new patch for
multi-named groups in the comparison lists)


- -- 
Stephen Gallagher
RHCE 804006346421761

Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAk2JGN8ACgkQeiVVYja6o6PJiACeIukYQaaK9q7y2Zt1ar8FKNz3
zSsAoIaoGAeaEr4ymV9yCvDjecd7mJL7
=rDdk
-----END PGP SIGNATURE-----
From 646a9229b094e822c5f85e6920fb1cad76f470f2 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Thu, 17 Mar 2011 17:54:06 +0100
Subject: [PATCH 1/4] Add originalDN to fake groups

---
 src/db/sysdb.h                           |    3 ++-
 src/db/sysdb_ops.c                       |    8 +++++++-
 src/providers/ldap/sdap_async_accounts.c |   11 ++++++++++-
 src/tests/sysdb-tests.c                  |    4 ++--
 4 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index e98426551d594ca7e53b7a056d314d80d096f2fe..971a35f99d07264a9d4950e5b852ab450340ddc5 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -496,7 +496,8 @@ int sysdb_add_group(TALLOC_CTX *mem_ctx,
 int sysdb_add_incomplete_group(struct sysdb_ctx *ctx,
                                struct sss_domain_info *domain,
                                const char *name,
-                               gid_t gid);
+                               gid_t gid,
+                               const char *original_dn);
 
 /* Add netgroup (only basic attrs and w/o checks) */
 int sysdb_add_basic_netgroup(struct sysdb_ctx *ctx,
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index e60af7175fe02d01b07fdb286438da2756e6d268..ba1f6672c72afd78fdb818630f1e92caf9c2e3de 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -1147,7 +1147,8 @@ done:
 int sysdb_add_incomplete_group(struct sysdb_ctx *ctx,
                                struct sss_domain_info *domain,
                                const char *name,
-                               gid_t gid)
+                               gid_t gid,
+                               const char *original_dn)
 {
     TALLOC_CTX *tmpctx;
     time_t now;
@@ -1178,6 +1179,11 @@ int sysdb_add_incomplete_group(struct sysdb_ctx *ctx,
                                  now-1);
     if (ret) goto done;
 
+    if (original_dn) {
+        ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, original_dn);
+        if (ret) goto done;
+    }
+
     ret = sysdb_set_group_attr(tmpctx, ctx,
                                domain, name, attrs, SYSDB_MOD_REP);
 
diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 27165a827e0c98c5488779e2da5733423e0ae6bc..e231a220e1d8d7866ad32a8c4f27043eec084622 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -1860,6 +1860,7 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
     struct ldb_message *msg;
     int i, mi, ai;
     const char *name;
+    const char *original_dn;
     char **missing;
     gid_t gid;
     int ret;
@@ -1931,9 +1932,17 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
                     goto fail;
                 }
 
+                ret = sysdb_attrs_get_string(ldap_groups[ai],
+                                             SYSDB_ORIG_DN,
+                                             &original_dn);
+                if (ret) {
+                    DEBUG(5, ("The group has no name original DN\n"));
+                    original_dn = NULL;
+                }
 
                 DEBUG(8, ("Adding fake group %s to sysdb\n", name));
-                ret = sysdb_add_incomplete_group(sysdb, dom, name, gid);
+                ret = sysdb_add_incomplete_group(sysdb, dom, name,
+                                                 gid, original_dn);
                 if (ret != EOK) {
                     goto fail;
                 }
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index eada9a3afa85c25f9bc24cd49b56bb41c6b7ea27..b856c093b24d4d5f8eb9280b1fbf0a812faf1095 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -268,7 +268,7 @@ static int test_add_incomplete_group(struct test_data *data)
     int ret;
 
     ret = sysdb_add_incomplete_group(data->ctx->sysdb, data->ctx->domain,
-                                     data->groupname, data->gid);
+                                     data->groupname, data->gid, NULL);
     return ret;
 }
 
@@ -2743,7 +2743,7 @@ START_TEST(test_odd_characters)
 
     /* Add */
     ret = sysdb_add_incomplete_group(test_ctx->sysdb, test_ctx->domain,
-                                     odd_groupname, 20000);
+                                     odd_groupname, 20000, NULL);
     fail_unless(ret == EOK, "sysdb_add_incomplete_group error [%d][%s]",
                             ret, strerror(ret));
 
-- 
1.7.4

From 5653de72713148dede367f8a172f5b1cc2c06dee Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Tue, 15 Mar 2011 16:52:06 +0100
Subject: [PATCH 2/4] Use fake groups during IPA schema initgroups

https://fedorahosted.org/sssd/ticket/822
---
 src/providers/ldap/sdap_async_accounts.c |  546 +++++++++++++++++++++++-------
 1 files changed, 425 insertions(+), 121 deletions(-)

diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index e231a220e1d8d7866ad32a8c4f27043eec084622..b879824924688e6b9b5f3dcb014e1906bfaf7805 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -1972,6 +1972,80 @@ fail:
     return ret;
 }
 
+static int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
+                                    struct sdap_options *opts,
+                                    struct sss_domain_info *dom,
+                                    const char *name,
+                                    enum sysdb_member_type type,
+                                    char **sysdb_grouplist,
+                                    struct sysdb_attrs **ldap_groups,
+                                    int ldap_groups_count,
+                                    bool add_fake)
+{
+    TALLOC_CTX *tmp_ctx;
+    char **ldap_grouplist = NULL;
+    char **add_groups;
+    char **del_groups;
+    int ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    if (ldap_groups_count == 0) {
+        /* No groups for this user in LDAP.
+         * We need to ensure that there are no groups
+         * in the sysdb either.
+         */
+        ldap_grouplist = NULL;
+    } else {
+        ret = sysdb_attrs_to_list(tmp_ctx, ldap_groups,
+                                  ldap_groups_count,
+                                  SYSDB_NAME,
+                                  &ldap_grouplist);
+        if (ret != EOK) {
+            DEBUG(1, ("sysdb_attrs_to_list failed [%d]: %s\n",
+                      ret, strerror(ret)));
+            goto done;
+        }
+    }
+
+    /* Find the differences between the sysdb and LDAP lists
+     * Groups in the sysdb only must be removed.
+     */
+    ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist,
+                            &add_groups, &del_groups, NULL);
+    if (ret != EOK) goto done;
+
+    /* Add fake entries for any groups the user should be added as
+     * member of but that are not cached in sysdb
+     */
+    if (add_fake && add_groups && add_groups[0]) {
+        ret = sdap_add_incomplete_groups(sysdb, opts, dom,
+                                         add_groups, ldap_groups,
+                                         ldap_groups_count);
+        if (ret != EOK) {
+            DEBUG(1, ("Adding incomplete users failed\n"));
+            goto done;
+        }
+    }
+
+    DEBUG(8, ("Updating memberships for %s\n", name));
+    ret = sysdb_update_members(sysdb, dom, name,
+                               type,
+                               (const char *const *) add_groups,
+                               (const char *const *) del_groups);
+    if (ret != EOK) {
+        DEBUG(1, ("Membership update failed [%d]: %s\n",
+                  ret, strerror(ret)));
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
 /* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */
 
 struct sdap_initgr_rfc2307_state {
@@ -2065,10 +2139,7 @@ static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
     struct tevent_req *req;
     struct sdap_initgr_rfc2307_state *state;
     struct sysdb_attrs **ldap_groups;
-    char **ldap_grouplist = NULL;
     char **sysdb_grouplist = NULL;
-    char **add_groups;
-    char **del_groups;
     struct ldb_message *msg;
     struct ldb_message_element *groups;
     size_t count;
@@ -2086,22 +2157,6 @@ static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
         return;
     }
 
-    if (count == 0) {
-        /* No groups for this user in LDAP.
-         * We need to ensure that there are no groups
-         * in the sysdb either.
-         */
-        ldap_grouplist = NULL;
-    } else {
-        ret = sysdb_attrs_to_list(state, ldap_groups, count,
-                                  SYSDB_NAME,
-                                  &ldap_grouplist);
-        if (ret != EOK) {
-            tevent_req_error(req, ret);
-            return;
-        }
-    }
-
     /* Search for all groups for which this user is a member */
     attrs[0] = SYSDB_MEMBEROF;
     attrs[1] = NULL;
@@ -2137,34 +2192,12 @@ static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
         sysdb_grouplist[groups->num_values] = NULL;
     }
 
-    /* Find the differences between the sysdb and LDAP lists
-     * Groups in LDAP only must be added to the sysdb;
-     * groups in the sysdb only must be removed.
-     */
-    ret = diff_string_lists(state, ldap_grouplist, sysdb_grouplist,
-                            &add_groups, &del_groups, NULL);
-    if (ret != EOK) {
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    /* Add fake entries for any groups the user should be added as
-     * member of but that are not cached in sysdb
-     */
-    if (add_groups && add_groups[0]) {
-        ret = sdap_add_incomplete_groups(state->sysdb, state->opts,
-                                         state->dom, add_groups,
-                                         ldap_groups, count);
-        if (ret != EOK) {
-            tevent_req_error(req, ret);
-            return;
-        }
-    }
-
-    ret = sysdb_update_members(state->sysdb, state->dom, state->name,
-                               SYSDB_MEMBER_USER,
-                               (const char *const *)add_groups,
-                               (const char *const *)del_groups);
+    /* There are no nested groups here so we can just update the
+     * memberships */
+    ret = sdap_initgr_common_store(state->sysdb, state->opts,
+                                   state->dom, state->name,
+                                   SYSDB_MEMBER_USER, sysdb_grouplist,
+                                   ldap_groups, count, true);
     if (ret != EOK) {
         tevent_req_error(req, ret);
         return;
@@ -2190,6 +2223,7 @@ struct sdap_initgr_nested_state {
     struct sss_domain_info *dom;
     struct sdap_handle *sh;
 
+    struct sysdb_attrs *user;
     const char *username;
 
     const char **grp_attrs;
@@ -2231,6 +2265,7 @@ static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
     state->dom = dom;
     state->sh = sh;
     state->grp_attrs = grp_attrs;
+    state->user = user;
     state->op = NULL;
 
     ret = sysdb_attrs_primary_name(sysdb, user,
@@ -2351,115 +2386,182 @@ static void sdap_initgr_nested_search(struct tevent_req *subreq)
     }
 }
 
+static int sdap_initgr_nested_store_group(struct sysdb_ctx *sysdb,
+                                          struct sdap_options *opts,
+                                          struct sss_domain_info *dom,
+                                          struct sysdb_attrs *group,
+                                          struct sysdb_attrs **groups,
+                                          int ngroups);
+
 static void sdap_initgr_nested_store(struct tevent_req *req)
 {
     struct sdap_initgr_nested_state *state;
-    errno_t ret, sret;
-    const char *attrs[] = { SYSDB_MEMBEROF, NULL };
-    struct ldb_message *msg;
-    struct ldb_message_element *groups;
+
+    struct ldb_message_element *el;
+    errno_t ret;
+    int i, mi;
+    struct ldb_message **direct_sysdb_groups = NULL;
+    size_t direct_sysdb_count = 0;
+
+    const char *orig_dn;
+    const char *user_dn;
+    struct ldb_dn *basedn;
+    static const char *group_attrs[] = { SYSDB_NAME, NULL };
+    const char *member_filter;
     char **sysdb_grouplist = NULL;
     char **ldap_grouplist = NULL;
-    char **del_groups;
-    size_t i, count;
+    const char *tmp_str;
+
+    int ndirect;
+    struct sysdb_attrs **direct_groups;
 
     state = tevent_req_data(req, struct sdap_initgr_nested_state);
 
-    ret = sysdb_transaction_start(state->sysdb);
+    /* Get direct LDAP parents */
+    ret = sysdb_attrs_get_string(state->user, SYSDB_ORIG_DN, &orig_dn);
     if (ret != EOK) {
-        DEBUG(1, ("Could not create sysdb transaction\n"));
+        DEBUG(2, ("The user has no original DN\n"));
         goto done;
     }
 
-    ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
-                           state->groups, state->groups_cur, false, NULL);
-    if (ret != EOK) {
+    direct_groups = talloc_zero_array(state, struct sysdb_attrs *,
+                                      state->count + 1);
+    if (!direct_groups) {
+        ret = ENOMEM;
         goto done;
     }
+    ndirect = 0;
 
-    /* Get the list of groups this user belongs to */
-    ret = sysdb_search_user_by_name(state, state->sysdb, state->dom,
-                                    state->username, attrs,
-                                    &msg);
-    if (ret != EOK) {
-        goto done;
-    }
+    for (i=0; i < state->groups_cur ; i++) {
+        ret = sysdb_attrs_get_el(state->groups[i], SYSDB_MEMBER, &el);
+        if (ret) {
+            DEBUG(3, ("A group with no members during initgroups?\n"));
+            goto done;
+        }
 
-    groups = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
-    if (!groups || groups->num_values == 0) {
-        /* No groups for this user in sysdb currently, so
-         * nothing to delete.
-         */
-        ret = EOK;
-        goto done;
-    }
+        for (mi = 0; mi < el->num_values; mi++) {
+            if (strcasecmp((const char *) el->values[mi].data, orig_dn) != 0) {
+                continue;
+            }
 
-    sysdb_grouplist = talloc_array(state, char *, groups->num_values+1);
-    if (!sysdb_grouplist) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* Get a list of the groups by name */
-    for (i = 0; i < groups->num_values; i++) {
-        ret = sysdb_group_dn_name(state->sysdb,
-                                  sysdb_grouplist,
-                                  (const char *)groups->values[i].data,
-                                  &sysdb_grouplist[i]);
-        if (ret != EOK) goto done;
+            direct_groups[ndirect] = state->groups[i];
+            ndirect++;
+        }
     }
-    sysdb_grouplist[groups->num_values] = NULL;
 
-    count = 0;
-    while (state->group_dns[count]) count++;
+    DEBUG(7, ("The user %s is a direct member of %d LDAP groups\n",
+              state->username, ndirect));
 
-    ldap_grouplist = talloc_array(state, char *, count+1);
-    if (!ldap_grouplist) {
+    /* Get direct sysdb parents */
+    user_dn = sysdb_user_strdn(state, state->dom->name, state->username);
+    if (!user_dn) {
         ret = ENOMEM;
         goto done;
     }
 
-    for (i = 0; i < count; i++) {
-        ret = sysdb_group_dn_name(state->sysdb,
-                                  ldap_grouplist,
-                                  state->group_dns[i],
-                                  &ldap_grouplist[i]);
-        if (ret != EOK) goto done;
+    member_filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))",
+                                    SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS,
+                                    SYSDB_MEMBER, user_dn);
+    if (!member_filter) {
+        ret = ENOMEM;
+        goto done;
     }
-    ldap_grouplist[count] = NULL;
-
-    /* Find the differences between the sysdb and LDAP lists
-     * Groups in the sysdb only must be removed.
-     */
-    ret = diff_string_lists(state, ldap_grouplist, sysdb_grouplist,
-                            NULL, &del_groups, NULL);
-    if (ret != EOK) goto done;
 
-    if (!del_groups || !del_groups[0]) {
-        /* No groups to delete */
-        ret = EOK;
+    basedn = ldb_dn_new_fmt(state, sysdb_ctx_get_ldb(state->sysdb),
+                            SYSDB_TMPL_GROUP_BASE,
+                            state->dom->name);
+    if (!basedn) {
+        ret = ENOMEM;
         goto done;
     }
 
-    ret = sysdb_update_members(state->sysdb, state->dom, state->username,
-                               SYSDB_MEMBER_USER, NULL,
-                               (const char *const *)del_groups);
+    DEBUG(8, ("searching sysdb with filter [%s]\n", member_filter));
 
-done:
+    ret = sysdb_search_entry(state, state->sysdb, basedn,
+                             LDB_SCOPE_SUBTREE, member_filter, group_attrs,
+                             &direct_sysdb_count, &direct_sysdb_groups);
     if (ret == EOK) {
-        ret = sysdb_transaction_commit(state->sysdb);
+        /* Get the list of sysdb groups by name */
+        sysdb_grouplist = talloc_array(state, char *, direct_sysdb_count+1);
+        if (!sysdb_grouplist) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        for(i = 0; i < direct_sysdb_count; i++) {
+            tmp_str = ldb_msg_find_attr_as_string(direct_sysdb_groups[i],
+                                                SYSDB_NAME, NULL);
+            if (!tmp_str) {
+                /* This should never happen, but if it does, just continue */
+                continue;
+            }
+
+            sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
+            if (!sysdb_grouplist[i]) {
+                DEBUG(1, ("A group with no name?\n"));
+                ret = EIO;
+                goto done;
+            }
+        }
+        sysdb_grouplist[i] = NULL;
+    } else if (ret == ENOENT) {
+        direct_sysdb_groups = NULL;
+        direct_sysdb_count = 0;
+    } else {
+        DEBUG(2, ("sysdb_search_entry failed: [%d]: %s\n", ret, strerror(ret)));
+        goto done;
+    }
+    DEBUG(7, ("The user %s is a member of %d sysdb groups\n",
+              state->username, direct_sysdb_count));
+
+    /* Store the direct parents with full member/memberof pairs */
+    ret = sdap_initgr_common_store(state->sysdb, state->opts,
+                                   state->dom,
+                                   state->username,
+                                   SYSDB_MEMBER_USER,
+                                   sysdb_grouplist,
+                                   direct_groups,
+                                   ndirect, true);
+    if (ret != EOK) {
+        DEBUG(1, ("sdap_initgr_common_store failed [%d]: %s\n",
+                  ret, strerror(ret)));
+        goto done;
+    }
+
+    /* Not all indirect groups may be cached.
+     * Add fake entries for those that are not */
+    ret = sysdb_attrs_to_list(state, state->groups,
+                              state->groups_cur,
+                              SYSDB_NAME,
+                              &ldap_grouplist);
+    if (ret != EOK) {
+        DEBUG(1, ("sysdb_attrs_to_list failed [%d]: %s\n",
+                    ret, strerror(ret)));
+        goto done;
+    }
+
+    ret = sdap_add_incomplete_groups(state->sysdb, state->opts,
+                                     state->dom, ldap_grouplist,
+                                     state->groups, state->groups_cur);
+    if (ret != EOK) {
+        DEBUG(1, ("adding incomplete groups failed [%d]: %s\n",
+                    ret, strerror(ret)));
+        goto done;
+    }
+
+    /* Set the indirect memberships */
+    for (i=0; i < state->groups_cur ; i++) {
+        ret = sdap_initgr_nested_store_group(state->sysdb, state->opts,
+                                             state->dom, state->groups[i],
+                                             state->groups, state->groups_cur);
         if (ret != EOK) {
-            DEBUG(1, ("Could not commit transaction! [%d][%s]\n",
-                      ret, strerror(ret)));
+            DEBUG(2, ("Cannot fix nested group membership\n"));
+            goto done;
         }
     }
 
+done:
     if (ret != EOK) {
-        sret = sysdb_transaction_cancel(state->sysdb);
-        if (sret != EOK) {
-            DEBUG(0, ("Unable to cancel transaction! [%d][%s]\n",
-                      sret, strerror(sret)));
-        }
         tevent_req_error(req, ret);
         return;
     }
@@ -2467,6 +2569,208 @@ done:
     tevent_req_done(req);
 }
 
+static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
+                                                 struct sysdb_attrs *attrs,
+                                                 struct sysdb_attrs **groups,
+                                                 int ngroups,
+                                                 struct sysdb_attrs ***_direct_parents,
+                                                 int *_ndirect);
+
+static int sdap_initgr_nested_store_group(struct sysdb_ctx *sysdb,
+                                          struct sdap_options *opts,
+                                          struct sss_domain_info *dom,
+                                          struct sysdb_attrs *group,
+                                          struct sysdb_attrs **groups,
+                                          int ngroups)
+{
+    TALLOC_CTX *tmp_ctx;
+    const char *member_filter;
+    const char *group_orig_dn;
+    const char *group_name;
+    const char *group_dn;
+    int ret;
+    int i;
+    struct ldb_message **direct_sysdb_groups = NULL;
+    size_t direct_sysdb_count = 0;
+    static const char *group_attrs[] = { SYSDB_NAME, NULL };
+    struct ldb_dn *basedn;
+    int ndirect;
+    struct sysdb_attrs **direct_groups;
+    char **sysdb_grouplist = NULL;
+    const char *tmp_str;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(sysdb),
+                            SYSDB_TMPL_GROUP_BASE,
+                            dom->name);
+    if (!basedn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN, &group_orig_dn);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sysdb_attrs_get_string(group, SYSDB_NAME, &group_name);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* Get direct sysdb parents */
+    group_dn = sysdb_group_strdn(tmp_ctx, dom->name, group_name);
+    if (!group_dn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    member_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(%s=%s))",
+                                    SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS,
+                                    SYSDB_MEMBER, group_dn);
+    if (!member_filter) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    DEBUG(8, ("searching sysdb with filter %s\n", member_filter));
+
+    ret = sysdb_search_entry(tmp_ctx, sysdb, basedn,
+                             LDB_SCOPE_SUBTREE, member_filter, group_attrs,
+                             &direct_sysdb_count, &direct_sysdb_groups);
+    if (ret == EOK) {
+        /* Get the list of sysdb groups by name */
+        sysdb_grouplist = talloc_array(tmp_ctx, char *, direct_sysdb_count+1);
+        if (!sysdb_grouplist) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        for(i = 0; i < direct_sysdb_count; i++) {
+            tmp_str = ldb_msg_find_attr_as_string(direct_sysdb_groups[i],
+                                                SYSDB_NAME, NULL);
+            if (!tmp_str) {
+                /* This should never happen, but if it does, just continue */
+                continue;
+            }
+
+            sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
+            if (!sysdb_grouplist[i]) {
+                DEBUG(1, ("A group with no name?\n"));
+                ret = EIO;
+                goto done;
+            }
+        }
+        sysdb_grouplist[i] = NULL;
+    } else if (ret == ENOENT) {
+        direct_sysdb_groups = NULL;
+        direct_sysdb_count = 0;
+    } else {
+        DEBUG(2, ("sysdb_search_entry failed: [%d]: %s\n", ret, strerror(ret)));
+        goto done;
+    }
+    DEBUG(7, ("The group %s is a member of %d sysdb groups\n",
+              group_name, direct_sysdb_count));
+
+    /* Filter only parents from full set */
+    ret = sdap_initgr_nested_get_direct_parents(tmp_ctx, group, groups,
+                                                ngroups, &direct_groups,
+                                                &ndirect);
+    if (ret != EOK) {
+        DEBUG(1, ("Cannot get parent groups [%d]: %s\n",
+                  ret, strerror(ret)));
+        goto done;
+    }
+    DEBUG(7, ("The group %s is a direct member of %d LDAP groups\n",
+              group_name, ndirect));
+
+    /* Store the direct parents with full member/memberof pairs */
+    ret = sdap_initgr_common_store(sysdb, opts, dom, group_name,
+                                   SYSDB_MEMBER_GROUP, sysdb_grouplist,
+                                   direct_groups, ndirect, false);
+    if (ret != EOK) {
+        DEBUG(1, ("sdap_initgr_common_store failed [%d]: %s\n",
+                  ret, strerror(ret)));
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
+                                                 struct sysdb_attrs *attrs,
+                                                 struct sysdb_attrs **groups,
+                                                 int ngroups,
+                                                 struct sysdb_attrs ***_direct_parents,
+                                                 int *_ndirect)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_message_element *member;
+    int i, mi;
+    int ret;
+    const char *orig_dn;
+
+    int ndirect;
+    struct sysdb_attrs **direct_groups;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+
+    direct_groups = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
+                                      ngroups + 1);
+    if (!direct_groups) {
+        ret = ENOMEM;
+        goto done;
+    }
+    ndirect = 0;
+
+    ret = sysdb_attrs_get_string(attrs, SYSDB_ORIG_DN, &orig_dn);
+    if (ret != EOK) {
+        DEBUG(3, ("Missing originalDN\n"));
+        goto done;
+    }
+    DEBUG(9, ("Looking up direct parents for group [%s]\n", orig_dn));
+
+    /* FIXME - Filter only parents from full set to avoid searching
+     * through all members of huge groups. That requires asking for memberOf
+     * with the group LDAP search
+     */
+
+    /* Filter only direct parents from the list of all groups */
+    for (i=0; i < ngroups; i++) {
+        ret = sysdb_attrs_get_el(groups[i], SYSDB_MEMBER, &member);
+        if (ret) {
+            DEBUG(7, ("A group with no members during initgroups?\n"));
+            continue;
+        }
+
+        for (mi = 0; mi < member->num_values; mi++) {
+            if (strcasecmp((const char *) member->values[mi].data, orig_dn) != 0) {
+                continue;
+            }
+
+            direct_groups[ndirect] = groups[i];
+            ndirect++;
+        }
+    }
+    direct_groups[ndirect] = NULL;
+
+    DEBUG(9, ("The group [%s] has %d direct parents\n", orig_dn, ndirect));
+
+    *_direct_parents = direct_groups;
+    *_ndirect = ndirect;
+    ret = EOK;
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
 static int sdap_initgr_nested_recv(struct tevent_req *req)
 {
     TEVENT_REQ_RETURN_ON_ERROR(req);
@@ -4107,7 +4411,7 @@ static errno_t rfc2307bis_nested_groups_update_sysdb(
     }
 
     if (reply_count == 0) {
-        DEBUG(6, ("User [%s] is not a direct member of any groups\n", name));
+        DEBUG(6, ("Group [%s] is not a direct member of any groups\n", name));
         sysdb_grouplist = NULL;
     } else {
         sysdb_grouplist = talloc_array(tmp_ctx, char *, reply_count+1);
-- 
1.7.4

From 1e4af798fb9be6a64a1c5dfabf7dee37f0f3629e Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgall...@redhat.com>
Date: Tue, 22 Mar 2011 15:08:50 -0400
Subject: [PATCH 3/4] Use sysdb_attrs_primary_name() in sdap_initgr_nested_store_group

---
 src/providers/ldap/sdap_async_accounts.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index b879824924688e6b9b5f3dcb014e1906bfaf7805..80f2b3a33b6853b4821efb8e2875bbfa6b979e5a 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -2615,7 +2615,9 @@ static int sdap_initgr_nested_store_group(struct sysdb_ctx *sysdb,
         goto done;
     }
 
-    ret = sysdb_attrs_get_string(group, SYSDB_NAME, &group_name);
+    ret = sysdb_attrs_primary_name(sysdb, group,
+                                   opts->group_map[SDAP_AT_GROUP_NAME].name,
+                                   &group_name);
     if (ret != EOK) {
         goto done;
     }
-- 
1.7.4

From 23daf1ae79ac214f8c12c80b9bcbcaa525f5113e Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgall...@redhat.com>
Date: Tue, 22 Mar 2011 17:42:55 -0400
Subject: [PATCH 4/4] Add sysdb_attrs_primary_name_list() routine

This routine will replace the use of sysdb_attrs_to_list() for any
case where we're trying to get the name of the entry. It's a
necessary precaution in case the name is multi-valued.
---
 src/db/sysdb.c                           |   53 ++++++++++++++++++++++++++++++
 src/db/sysdb.h                           |    6 +++
 src/providers/ldap/sdap_async_accounts.c |   40 ++++++++++++----------
 3 files changed, 81 insertions(+), 18 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index ef9d0a237645f8b52e9a64eedd54d7d9f3762f05..94738c606a9c4b69ce2cda1a1629aba9524cd68b 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -2256,3 +2256,56 @@ done:
     talloc_free(tmpctx);
     return ret;
 }
+
+errno_t sysdb_attrs_primary_name_list(struct sysdb_ctx *sysdb,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct sysdb_attrs **attr_list,
+                                      size_t attr_count,
+                                      const char *ldap_attr,
+                                      char ***name_list)
+{
+    errno_t ret;
+    size_t i, j;
+    char **list;
+    const char *name;
+
+    /* Assume that every entry has a primary name */
+    list = talloc_array(mem_ctx, char *, attr_count+1);
+    if (!list) {
+        return ENOMEM;
+    }
+
+    j = 0;
+    for (i = 0; i < attr_count; i++) {
+        ret = sysdb_attrs_primary_name(sysdb,
+                                       attr_list[i],
+                                       ldap_attr,
+                                       &name);
+        if (ret != EOK) {
+            DEBUG(1, ("Could not determine primary name\n"));
+            /* Skip and continue. Don't advance 'j' */
+            continue;
+        }
+
+        list[j] = talloc_strdup(list, name);
+        if (!list[j]) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        j++;
+    }
+
+    /* NULL-terminate the list */
+    list[j] = NULL;
+
+    *name_list = list;
+
+    ret = EOK;
+
+done:
+    if (ret != EOK) {
+        talloc_free(list);
+    }
+    return ret;
+}
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 971a35f99d07264a9d4950e5b852ab450340ddc5..b7256911a793c575f716a8728503b6c58bb6dce3 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -219,6 +219,12 @@ errno_t sysdb_attrs_primary_name(struct sysdb_ctx *sysdb,
                                  struct sysdb_attrs *attrs,
                                  const char *ldap_attr,
                                  const char **_primary);
+errno_t sysdb_attrs_primary_name_list(struct sysdb_ctx *sysdb,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct sysdb_attrs **attr_list,
+                                      size_t attr_count,
+                                      const char *ldap_attr,
+                                      char ***name_list);
 
 /* convert an ldb error into an errno error */
 int sysdb_error_to_errno(int ldberr);
diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 80f2b3a33b6853b4821efb8e2875bbfa6b979e5a..b6e392b206a527fdf189d18bf7a41a5e76d864bd 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -1998,12 +1998,13 @@ static int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
          */
         ldap_grouplist = NULL;
     } else {
-        ret = sysdb_attrs_to_list(tmp_ctx, ldap_groups,
-                                  ldap_groups_count,
-                                  SYSDB_NAME,
-                                  &ldap_grouplist);
+        ret = sysdb_attrs_primary_name_list(
+                sysdb, tmp_ctx,
+                ldap_groups, ldap_groups_count,
+                opts->group_map[SDAP_AT_GROUP_NAME].name,
+                &ldap_grouplist);
         if (ret != EOK) {
-            DEBUG(1, ("sysdb_attrs_to_list failed [%d]: %s\n",
+            DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
                       ret, strerror(ret)));
             goto done;
         }
@@ -2530,12 +2531,13 @@ static void sdap_initgr_nested_store(struct tevent_req *req)
 
     /* Not all indirect groups may be cached.
      * Add fake entries for those that are not */
-    ret = sysdb_attrs_to_list(state, state->groups,
-                              state->groups_cur,
-                              SYSDB_NAME,
-                              &ldap_grouplist);
+    ret = sysdb_attrs_primary_name_list(
+            state->sysdb, state,
+            state->groups, state->groups_cur,
+            state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+            &ldap_grouplist);
     if (ret != EOK) {
-        DEBUG(1, ("sysdb_attrs_to_list failed [%d]: %s\n",
+        DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
                     ret, strerror(ret)));
         goto done;
     }
@@ -3957,10 +3959,11 @@ errno_t save_rfc2307bis_user_memberships(
         ldap_grouplist = NULL;
     }
     else {
-        ret = sysdb_attrs_to_list(tmp_ctx,
-                                  state->ldap_groups, state->ldap_groups_count,
-                                  SYSDB_NAME,
-                                  &ldap_grouplist);
+        ret = sysdb_attrs_primary_name_list(
+                state->sysdb, tmp_ctx,
+                state->ldap_groups, state->ldap_groups_count,
+                state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+                &ldap_grouplist);
         if (ret != EOK) {
             goto error;
         }
@@ -4446,10 +4449,11 @@ static errno_t rfc2307bis_nested_groups_update_sysdb(
         ldap_grouplist = NULL;
     }
     else {
-        ret = sysdb_attrs_to_list(tmp_ctx,
-                                  state->ldap_groups, state->ldap_groups_count,
-                                  SYSDB_NAME,
-                                  &ldap_grouplist);
+        ret = sysdb_attrs_primary_name_list(
+                state->sysdb, tmp_ctx,
+                state->ldap_groups, state->ldap_groups_count,
+                state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+                &ldap_grouplist);
         if (ret != EOK) {
             goto error;
         }
-- 
1.7.4

Attachment: 0001-Add-originalDN-to-fake-groups.patch.sig
Description: PGP signature

Attachment: 0002-Use-fake-groups-during-IPA-schema-initgroups.patch.sig
Description: PGP signature

Attachment: 0003-Use-sysdb_attrs_primary_name-in-sdap_initgr_nested_s.patch.sig
Description: PGP signature

Attachment: 0004-Add-sysdb_attrs_primary_name_list-routine.patch.sig
Description: PGP signature

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to