>From 31f09709cdb31d487637281aa0f79c706e5496c6 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Mon, 30 Nov 2009 21:51:41 -0500
Subject: [PATCH 7/7] Fix nested group memberships

Search the local db to find the local DN using the original DN as search key.
This way we do not have to rely on weak and faulty heuristicts based on DN
names.
Add a few helper functions in the process and change the way we pass members to
sysdb_store_group_send(), instead of passing users and groups list, just add
member DNs to the other sysdb attrs.
---
 server/db/sysdb.c                           |   97 ++++++++++
 server/db/sysdb.h                           |   13 +-
 server/db/sysdb_ops.c                       |   65 +-------
 server/providers/ldap/sdap_async_accounts.c |  272 +++++++++++++--------------
 server/providers/proxy.c                    |   71 ++++++-
 server/tests/sysdb-tests.c                  |    2 +-
 6 files changed, 299 insertions(+), 221 deletions(-)

diff --git a/server/db/sysdb.c b/server/db/sysdb.c
index 8ff9656..979acf8 100644
--- a/server/db/sysdb.c
+++ b/server/db/sysdb.c
@@ -68,6 +68,11 @@ struct ldb_context *sysdb_handle_get_ldb(struct sysdb_handle *handle)
     return handle->ctx->ldb;
 }
 
+struct sysdb_ctx *sysdb_handle_get_ctx(struct sysdb_handle *handle)
+{
+    return handle->ctx;
+}
+
 struct sysdb_attrs *sysdb_new_attrs(TALLOC_CTX *memctx)
 {
     return talloc_zero(memctx, struct sysdb_attrs);
@@ -254,6 +259,98 @@ int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs,
     return ret;
 }
 
+int sysdb_attrs_users_from_str_list(struct sysdb_attrs *attrs,
+                                    const char *attr_name,
+                                    const char *domain,
+                                    const char **list)
+{
+    struct ldb_message_element *el = NULL;
+    struct ldb_val *vals;
+    int i, j, num;
+    char *member;
+    int ret;
+
+    ret = sysdb_attrs_get_el(attrs, attr_name, &el);
+    if (!ret) {
+        return ret;
+    }
+
+    for (num = 0; list[num]; num++) /* count */ ;
+
+    vals = talloc_realloc(attrs->a, el->values,
+                          struct ldb_val, el->num_values + num);
+    if (!vals) {
+        return ENOMEM;
+    }
+    el->values = vals;
+
+    DEBUG(9, ("Adding %d members to existing %d ones\n",
+              num, el->num_values));
+
+    for (i = 0, j = el->num_values; i < num; i++) {
+
+        member = sysdb_user_strdn(el->values, domain, list[i]);
+        if (!member) {
+            DEBUG(4, ("Failed to get user dn for [%s]\n", list[i]));
+            continue;
+        }
+        el->values[j].data = (uint8_t *)member;
+        el->values[j].length = strlen(member);
+        j++;
+
+        DEBUG(7, ("    member #%d: [%s]\n", i, member));
+    }
+    el->num_values = j;
+
+    return EOK;
+}
+
+int sysdb_attrs_users_from_ldb_vals(struct sysdb_attrs *attrs,
+                                    const char *attr_name,
+                                    const char *domain,
+                                    struct ldb_val *values,
+                                    int num_values)
+{
+    struct ldb_message_element *el = NULL;
+    struct ldb_val *vals;
+    int i, j;
+    char *member;
+    int ret;
+
+    ret = sysdb_attrs_get_el(attrs, attr_name, &el);
+    if (!ret) {
+        return ret;
+    }
+
+    vals = talloc_realloc(el, el->values, struct ldb_val,
+                          el->num_values + num_values);
+    if (!vals) {
+        return ENOMEM;
+    }
+    el->values = vals;
+
+    DEBUG(9, ("Adding %d members to existing %d ones\n",
+              num_values, el->num_values));
+
+    for (i = 0, j = el->num_values; i < num_values; i++) {
+        member = sysdb_user_strdn(el->values, domain,
+                                  (char *)values[i].data);
+        if (!member) {
+            DEBUG(4, ("Failed to get user dn for [%s]\n",
+                      (char *)values[i].data));
+            return ENOMEM;
+        }
+        el->values[j].data = (uint8_t *)member;
+        el->values[j].length = strlen(member);
+        j++;
+
+        DEBUG(7, ("    member #%d: [%s]\n", i, member));
+    }
+    el->num_values = j;
+
+    return EOK;
+}
+
 static char *build_dom_dn_str_escape(TALLOC_CTX *memctx, const char *template,
                                      const char *domain, const char *name)
 {
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index 33e1728..a1851cd 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -175,6 +175,16 @@ int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,
 int sysdb_attrs_replace_name(struct sysdb_attrs *attrs, const char *oldname,
                                  const char *newname);
 
+int sysdb_attrs_users_from_str_list(struct sysdb_attrs *attrs,
+                                    const char *attr_name,
+                                    const char *domain,
+                                    const char **list);
+int sysdb_attrs_users_from_ldb_vals(struct sysdb_attrs *attrs,
+                                    const char *attr_name,
+                                    const char *domain,
+                                    struct ldb_val *values,
+                                    int num_values);
+
 /* convert an ldb error into an errno error */
 int sysdb_error_to_errno(int ldberr);
 
@@ -200,6 +210,7 @@ char *sysdb_group_strdn(TALLOC_CTX *memctx,
 
 struct ldb_context *sysdb_ctx_get_ldb(struct sysdb_ctx *ctx);
 struct ldb_context *sysdb_handle_get_ldb(struct sysdb_handle *handle);
+struct sysdb_ctx *sysdb_handle_get_ctx(struct sysdb_handle *handle);
 
 int compare_ldb_dn_comp_num(const void *m1, const void *m2);
 
@@ -497,8 +508,6 @@ struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx,
                                           struct sss_domain_info *domain,
                                           const char *name,
                                           gid_t gid,
-                                          const char **member_users,
-                                          const char **member_groups,
                                           struct sysdb_attrs *attrs,
                                           uint64_t cache_timeout);
 int sysdb_store_group_recv(struct tevent_req *req);
diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c
index 93c24b1..8819919 100644
--- a/server/db/sysdb_ops.c
+++ b/server/db/sysdb_ops.c
@@ -2778,8 +2778,6 @@ struct sysdb_store_group_state {
 
     const char *name;
     gid_t gid;
-    const char **member_users;
-    const char **member_groups;
 
     struct sysdb_attrs *attrs;
 
@@ -2796,8 +2794,6 @@ struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx,
                                           struct sss_domain_info *domain,
                                           const char *name,
                                           gid_t gid,
-                                          const char **member_users,
-                                          const char **member_groups,
                                           struct sysdb_attrs *attrs,
                                           uint64_t cache_timeout)
 {
@@ -2815,8 +2811,6 @@ struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx,
     state->domain = domain;
     state->name = name;
     state->gid = gid;
-    state->member_users = member_users;
-    state->member_groups = member_groups;
     state->attrs = attrs;
     state->cache_timeout = cache_timeout;
 
@@ -2845,7 +2839,7 @@ static void sysdb_store_group_check(struct tevent_req *subreq)
     struct ldb_message *msg;
     time_t now = time(NULL);
     bool new_group = false;
-    int ret, i;
+    int ret;
 
     ret = sysdb_search_group_recv(subreq, state, &msg);
     talloc_zfree(subreq);
@@ -2860,63 +2854,6 @@ static void sysdb_store_group_check(struct tevent_req *subreq)
     /* FIXME: use the remote modification timestamp to know if the
      * group needs any update */
 
-    if (state->member_users || state->member_groups) {
-        if (!state->attrs) {
-            state->attrs = sysdb_new_attrs(state);
-            if (!state->attrs) {
-                DEBUG(6, ("Error: Out of memory\n"));
-                tevent_req_error(req, ENOMEM);
-                return;
-            }
-        }
-
-        for (i = 0; state->member_users && state->member_users[i]; i++) {
-            char *member;
-
-            member = sysdb_user_strdn(state,
-                                      state->domain->name,
-                                      state->member_users[i]);
-            if (!member) {
-                DEBUG(4, ("Error: Out of memory\n"));
-                tevent_req_error(req, ENOMEM);
-                return;
-            }
-            DEBUG(9, ("adding member: %s to group %s\n",
-                      member, state->name));
-
-            ret = sysdb_attrs_steal_string(state->attrs,
-                                           SYSDB_MEMBER, member);
-            if (ret) {
-                DEBUG(4, ("Error: %d (%s)\n", ret, strerror(ret)));
-                tevent_req_error(req, ret);
-                return;
-            }
-        }
-
-        for (i = 0; state->member_groups && state->member_groups[i]; i++) {
-            char *member;
-
-            member = sysdb_group_strdn(state,
-                                       state->domain->name,
-                                       state->member_groups[i]);
-            if (!member) {
-                DEBUG(4, ("Error: Out of memory\n"));
-                tevent_req_error(req, ENOMEM);
-                return;
-            }
-            DEBUG(9, ("adding member: %s to group %s\n",
-                      member, state->name));
-
-            ret = sysdb_attrs_steal_string(state->attrs,
-                                           SYSDB_MEMBER, member);
-            if (ret) {
-                DEBUG(4, ("Error: %d (%s)\n", ret, strerror(ret)));
-                tevent_req_error(req, ret);
-                return;
-            }
-        }
-    }
-
     if (new_group) {
         /* group doesn't exist, turn into adding a group */
         subreq = sysdb_add_group_send(state, state->ev, state->handle,
diff --git a/server/providers/ldap/sdap_async_accounts.c b/server/providers/ldap/sdap_async_accounts.c
index 157ec3e..e4656cd 100644
--- a/server/providers/ldap/sdap_async_accounts.c
+++ b/server/providers/ldap/sdap_async_accounts.c
@@ -624,64 +624,110 @@ int sdap_get_users_recv(struct tevent_req *req,
 
 /* ==Group-Parsing Routines=============================================== */
 
-static int sdap_parse_memberships(TALLOC_CTX *memctx,
-                                  struct sysdb_handle *handle,
-                                  struct sdap_options *opts,
-                                  struct ldb_val *values,
-                                  int num_values,
-                                  const char ***member_users,
-                                  const char ***member_groups)
+struct sdap_orig_entry_state {
+    int done;
+};
+
+static void sdap_find_entry_by_origDN_done(struct tevent_req *req)
+{
+    struct sdap_orig_entry_state *state = tevent_req_callback_data(req,
+                                               struct sdap_orig_entry_state);
+    state->done = 1;
+}
+
+/* WARNING: this is a sync routine for now */
+static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
+                                     struct tevent_context *ev,
+                                     struct sysdb_handle *handle,
+                                     struct sss_domain_info *domain,
+                                     const char *orig_dn,
+                                     char **localdn)
 {
-    const char **mgs = NULL;
-    const char **mus = NULL;
-    int i, u, g;
+    struct tevent_req *req;
+    struct sdap_orig_entry_state *state;
+    static const char *attrs[] = { NULL };
+    struct ldb_dn *base_dn;
+    char *filter;
+    struct ldb_message **msgs;
+    size_t num_msgs;
     int ret;
 
-    /* if this is the first time we are called, check if users and
-     * groups base DNs are set, if not do it */
-    if (!opts->users_base) {
-        opts->users_base = ldb_dn_new_fmt(opts,
-                                sysdb_handle_get_ldb(handle), "%s",
-                                dp_opt_get_string(opts->basic,
-                                           SDAP_USER_SEARCH_BASE));
-        if (!opts->users_base) {
-            DEBUG(1, ("Unable to get casefold Users Base DN from [%s]\n",
-                      dp_opt_get_string(opts->basic,
-                                        SDAP_USER_SEARCH_BASE)));
-            DEBUG(1, ("Out of memory?!\n"));
-            ret = ENOMEM;
-            goto done;
-        }
+    state = talloc_zero(memctx, struct sdap_orig_entry_state);
+    if (!state) {
+        ret = ENOMEM;
+        goto done;
     }
-    if (!opts->groups_base) {
-        opts->groups_base = ldb_dn_new_fmt(opts,
-                                sysdb_handle_get_ldb(handle), "%s",
-                                dp_opt_get_string(opts->basic,
-                                           SDAP_GROUP_SEARCH_BASE));
-        if (!opts->users_base) {
-            DEBUG(1, ("Unable to get casefold Users Base DN from [%s]\n",
-                      dp_opt_get_string(opts->basic,
-                                        SDAP_GROUP_SEARCH_BASE)));
-            DEBUG(1, ("Out of memory?!\n"));
-            ret = ENOMEM;
-            goto done;
-        }
+
+    filter = talloc_asprintf(state, "%s=%s", SYSDB_ORIG_DN, orig_dn);
+    if (!filter) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    base_dn = sysdb_domain_dn(sysdb_handle_get_ctx(handle),
+                              state, domain->name);
+    if (!base_dn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    req = sysdb_search_entry_send(state, ev, handle, base_dn,
+                                  LDB_SCOPE_SUBTREE, filter, attrs);
+    if (!req) {
+        ret = ENOMEM;
+        goto done;
+    }
+    tevent_req_set_callback(req, sdap_find_entry_by_origDN_done, state);
+
+    /* WARNING: SYNC LOOP HERE */
+    while (state->done == 0) {
+        tevent_loop_once(ev);
+    }
+
+    ret = sysdb_search_entry_recv(req, state, &num_msgs, &msgs);
+    if (ret) {
+        goto done;
+    }
+    if (num_msgs != 1) {
+        ret = ENOENT;
+        goto done;
+    }
+
+    *localdn = talloc_strdup(memctx, ldb_dn_get_linearized(msgs[0]->dn));
+    if (!*localdn) {
+        ret = ENOENT;
+        goto done;
     }
 
+    ret = EOK;
+
+done:
+    talloc_zfree(state);
+    return ret;
+}
+
+static int sdap_fill_memberships(struct sysdb_attrs *group_attrs,
+                                 struct tevent_context *ev,
+                                 struct sysdb_handle *handle,
+                                 struct sdap_options *opts,
+                                 struct sss_domain_info *domain,
+                                 struct ldb_val *values,
+                                 int num_values)
+{
+    struct ldb_message_element *el;
+    int i, j;
+    int ret;
+
     switch (opts->schema_type) {
     case SDAP_SCHEMA_RFC2307:
         DEBUG(9, ("[RFC2307 Schema]\n"));
 
-        mus = talloc_array(memctx, const char *, num_values +1);
-        if (!mus) {
-            ret = ENOMEM;
+        ret = sysdb_attrs_users_from_ldb_vals(group_attrs, SYSDB_MEMBER,
+                                              domain->name,
+                                              values, num_values);
+        if (ret) {
             goto done;
         }
-        for (i = 0; i < num_values; i++) {
-            mus[i] = (char *)values[i].data;
-            DEBUG(7, ("    member user %d: [%s]\n", i, mus[i]));
-        }
-        mus[i] = NULL;
 
         break;
 
@@ -690,93 +736,43 @@ static int sdap_parse_memberships(TALLOC_CTX *memctx,
     case SDAP_SCHEMA_AD:
         DEBUG(9, ("[IPA or AD Schema]\n"));
 
-        /* Just allocate both big enough to contain all members for now */
-        mus = talloc_array(memctx, const char *, num_values +1);
-        if (!mus) {
-            ret = ENOMEM;
+        ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el);
+        if (ret) {
             goto done;
         }
 
-        mgs = talloc_array(memctx, const char *, num_values +1);
-        if (!mgs) {
+        /* Just allocate both big enough to contain all members for now */
+        el->values = talloc_realloc(el, el->values, struct ldb_val,
+                                    el->num_values + num_values);
+        if (!el->values) {
             ret = ENOMEM;
             goto done;
         }
 
-        u = 0;
-        g = 0;
-
-        for (i = 0; i < num_values; i++) {
-            struct ldb_dn *tmp_dn = NULL;
-            const struct ldb_val *v;
-
-            /* parse out DN */
-            tmp_dn = ldb_dn_new_fmt(mus,
-                                    sysdb_handle_get_ldb(handle),
-                                    "%.*s",
-                                    (int)values[i].length,
-                                    (char *)values[i].data);
-            if (!tmp_dn) {
-                DEBUG(1, ("Unable to parse DN: [%.*s]\n",
-                          (int)values[i].length,
-                          (char *)values[i].data));
-                continue;
-            }
-            v = ldb_dn_get_rdn_val(tmp_dn);
-            if (!v) {
-                DEBUG(1, ("Unable to parse DN: [%.*s]\n",
-                          (int)values[i].length,
-                          (char *)values[i].data));
-                continue;
-            }
-            DEBUG(9, ("Member DN [%.*s], RDN [%.*s]\n",
-                      (int)values[i].length, (char *)values[i].data,
-                      (int)v->length, (char *)v->data));
-
-            if (ldb_dn_compare_base(opts->users_base, tmp_dn) == 0) {
-                mus[u] = talloc_asprintf(mus, "%.*s",
-                                         (int)v->length,
-                                         (char *)v->data);
-                if (!mus[u]) {
-                    DEBUG(1, ("Out of memory?!\n"));
-                    continue;
-                }
-                u++;
-
-                DEBUG(7, ("    member user %d: [%.*s]\n", i,
-                          (int)v->length, (char *)v->data));
-            } else
-            if (ldb_dn_compare_base(opts->groups_base, tmp_dn) == 0) {
-                mgs[g] = talloc_asprintf(mgs, "%.*s",
-                                         (int)v->length,
-                                         (char *)v->data);
-                if (!mgs[g]) {
-                    DEBUG(1, ("Out of memory?!\n"));
-                    continue;
+        for (i = 0, j = el->num_values; i < num_values; i++) {
+
+            /* sync search entry with this as origDN */
+            ret = sdap_find_entry_by_origDN(el->values, ev,
+                                            handle, domain,
+                                            (char *)values[i].data,
+                                            (char **)&el->values[j].data);
+            if (ret != EOK) {
+                if (ret != ENOENT) {
+                    goto done;
                 }
-                g++;
 
-                DEBUG(7, ("    member group %d: [%.*s]\n", i,
-                          (int)v->length, (char *)v->data));
+                DEBUG(7, ("    member #%d (%s): not found!\n",
+                          i, (char *)values[i].data));
             } else {
-                DEBUG(1, ("Unkown Member type for DN: [%.*s]\n",
-                          (int)values[i].length,
-                          (char *)values[i].data));
-                continue;
-            }
-        }
+                DEBUG(7, ("    member #%d (%s): [%s]\n",
+                          i, (char *)values[i].data,
+                          (char *)el->values[j].data));
 
-        if (g) {
-            mgs[g] = NULL;
-        } else {
-            talloc_zfree(mgs);
-        }
-
-        if (u) {
-            mus[u] = NULL;
-        } else {
-            talloc_zfree(mus);
+                el->values[j].length = strlen((char *)el->values[j].data);
+                j++;
+            }
         }
+        el->num_values = j;
 
         break;
 
@@ -790,14 +786,6 @@ static int sdap_parse_memberships(TALLOC_CTX *memctx,
     ret = EOK;
 
 done:
-    if (ret != EOK) {
-        talloc_zfree(mus);
-        talloc_zfree(mgs);
-    }
-
-    *member_users = mus;
-    *member_groups = mgs;
-
     return ret;
 }
 
@@ -830,8 +818,6 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
     struct tevent_req *req, *subreq;
     struct sdap_save_group_state *state;
     struct ldb_message_element *el;
-    const char **member_groups = NULL;
-    const char **member_users = NULL;
     struct sysdb_attrs *group_attrs;
     long int l;
     gid_t gid;
@@ -937,9 +923,8 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
         } else {
             DEBUG(7, ("Adding member users to group [%s]\n", state->name));
 
-            ret = sdap_parse_memberships(state, handle, opts,
-                                         el->values, el->num_values,
-                                         &member_users, &member_groups);
+            ret = sdap_fill_memberships(group_attrs, ev, handle, opts, dom,
+                                        el->values, el->num_values);
             if (ret) {
                 goto fail;
             }
@@ -951,7 +936,6 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
     subreq = sysdb_store_group_send(state, state->ev,
                                     state->handle, state->dom,
                                     state->name, gid,
-                                    member_users, member_groups,
                                     group_attrs,
                                     dp_opt_get_int(opts->basic,
                                                    SDAP_ENTRY_CACHE_TIMEOUT));
@@ -1031,8 +1015,7 @@ static struct tevent_req *sdap_save_grpmem_send(TALLOC_CTX *memctx,
     struct tevent_req *req, *subreq;
     struct sdap_save_grpmem_state *state;
     struct ldb_message_element *el;
-    const char **member_groups = NULL;
-    const char **member_users = NULL;
+    struct sysdb_attrs *group_attrs = NULL;
     int ret;
 
     req = tevent_req_create(memctx, &state, struct sdap_save_grpmem_state);
@@ -1061,9 +1044,14 @@ static struct tevent_req *sdap_save_grpmem_send(TALLOC_CTX *memctx,
     } else {
         DEBUG(7, ("Adding member users to group [%s]\n", state->name));
 
-        ret = sdap_parse_memberships(state, handle, opts,
-                                     el->values, el->num_values,
-                                     &member_users, &member_groups);
+        group_attrs = sysdb_new_attrs(state);
+        if (!group_attrs) {
+            ret = ENOMEM;
+            goto fail;
+        }
+
+        ret = sdap_fill_memberships(group_attrs, ev, handle, opts, dom,
+                                    el->values, el->num_values);
         if (ret) {
             goto fail;
         }
@@ -1074,8 +1062,7 @@ static struct tevent_req *sdap_save_grpmem_send(TALLOC_CTX *memctx,
     subreq = sysdb_store_group_send(state, state->ev,
                                     state->handle, state->dom,
                                     state->name, 0,
-                                    member_users, member_groups,
-                                    NULL,
+                                    group_attrs,
                                     dp_opt_get_int(opts->basic,
                                                SDAP_ENTRY_CACHE_TIMEOUT));
     if (!subreq) {
@@ -1982,7 +1969,6 @@ static void sdap_get_initgr_process(struct tevent_req *subreq)
                                                       struct tevent_req);
     struct sdap_get_initgr_state *state = tevent_req_data(req,
                                                struct sdap_get_initgr_state);
-    const char *user_dn;
     int ret;
 
     DEBUG(9, ("Process user's groups\n"));
diff --git a/server/providers/proxy.c b/server/providers/proxy.c
index f55b1c2..ef52ae9 100644
--- a/server/providers/proxy.c
+++ b/server/providers/proxy.c
@@ -956,7 +956,7 @@ static void get_gr_name_process(struct tevent_req *subreq)
     char *newbuf;
     size_t buflen;
     bool delete_group = false;
-    const char **members;
+    struct sysdb_attrs *members;
     int ret;
 
     DEBUG(7, ("Searching group by name (%s)\n", state->name));
@@ -1031,7 +1031,18 @@ again:
         DEBUG_GR_MEM(7, state);
 
         if (state->grp->gr_mem && state->grp->gr_mem[0]) {
-            members = (const char **)state->grp->gr_mem;
+            members = sysdb_new_attrs(state);
+            if (!members) {
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
+                                                  state->domain->name,
+                                                  (const char **)state->grp->gr_mem);
+            if (ret) {
+                tevent_req_error(req, ret);
+                return;
+            }
         } else {
             members = NULL;
         }
@@ -1040,7 +1051,7 @@ again:
                                         state->domain,
                                         state->grp->gr_name,
                                         state->grp->gr_gid,
-                                        members, NULL, NULL,
+                                        members,
                                         ctx->entry_cache_timeout);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
@@ -1178,7 +1189,7 @@ static void get_gr_gid_process(struct tevent_req *subreq)
     char *newbuf;
     size_t buflen;
     bool delete_group = false;
-    const char **members;
+    struct sysdb_attrs *members;
     int ret;
 
     DEBUG(7, ("Searching group by gid (%d)\n", state->gid));
@@ -1251,7 +1262,18 @@ again:
         DEBUG_GR_MEM(7, state);
 
         if (state->grp->gr_mem && state->grp->gr_mem[0]) {
-            members = (const char **)state->grp->gr_mem;
+            members = sysdb_new_attrs(state);
+            if (!members) {
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
+                                                  state->domain->name,
+                                                  (const char **)state->grp->gr_mem);
+            if (ret) {
+                tevent_req_error(req, ret);
+                return;
+            }
         } else {
             members = NULL;
         }
@@ -1260,7 +1282,7 @@ again:
                                         state->domain,
                                         state->grp->gr_name,
                                         state->grp->gr_gid,
-                                        members, NULL, NULL,
+                                        members,
                                         ctx->entry_cache_timeout);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
@@ -1405,7 +1427,7 @@ static void enum_groups_process(struct tevent_req *subreq)
     struct proxy_ctx *ctx = state->ctx;
     struct sss_domain_info *dom = ctx->be->domain;
     enum nss_status status;
-    const char **members;
+    struct sysdb_attrs *members;
     char *newbuf;
     int ret;
 
@@ -1486,7 +1508,18 @@ again:
         DEBUG_GR_MEM(7, state);
 
         if (state->grp->gr_mem && state->grp->gr_mem[0]) {
-            members = (const char **)state->grp->gr_mem;
+            members = sysdb_new_attrs(state);
+            if (!members) {
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
+                                                  state->domain->name,
+                                                  (const char **)state->grp->gr_mem);
+            if (ret) {
+                tevent_req_error(req, ret);
+                return;
+            }
         } else {
             members = NULL;
         }
@@ -1495,7 +1528,7 @@ again:
                                        state->domain,
                                        state->grp->gr_name,
                                        state->grp->gr_gid,
-                                       members, NULL, NULL,
+                                       members,
                                        ctx->entry_cache_timeout);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
@@ -1881,6 +1914,7 @@ static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx,
     char *newbuf;
     size_t buflen;
     bool delete_group = false;
+    struct sysdb_attrs *members;
     int ret;
 
     req = tevent_req_create(mem_ctx, &state, struct proxy_state);
@@ -1948,12 +1982,27 @@ again:
             break;
         }
 
+        if (state->grp->gr_mem && state->grp->gr_mem[0]) {
+            members = sysdb_new_attrs(state);
+            if (!members) {
+                ret = ENOMEM;
+                goto fail;
+            }
+            ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
+                                                  state->domain->name,
+                                                  (const char **)state->grp->gr_mem);
+            if (ret) {
+                goto fail;
+            }
+        } else {
+            members = NULL;
+        }
+
         subreq = sysdb_store_group_send(state, state->ev, state->handle,
                                         state->domain,
                                         state->grp->gr_name,
                                         state->grp->gr_gid,
-                                        (const char **)state->grp->gr_mem,
-                                        NULL, NULL,
+                                        members,
                                         ctx->entry_cache_timeout);
         if (!subreq) {
             ret = ENOMEM;
diff --git a/server/tests/sysdb-tests.c b/server/tests/sysdb-tests.c
index d4f0e2f..771f6a4 100644
--- a/server/tests/sysdb-tests.c
+++ b/server/tests/sysdb-tests.c
@@ -479,7 +479,7 @@ static void test_store_group(struct tevent_req *req)
 
     subreq = sysdb_store_group_send(data, data->ev, data->handle,
                                     data->ctx->domain, data->groupname,
-                                    data->gid, NULL, NULL, NULL, -1);
+                                    data->gid, NULL, -1);
     if (!subreq) {
         test_return(data, ret);
     }
-- 
1.6.2.5

