>From 28f11aabb072f678fa3d8449df53474c2731c072 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Tue, 17 Nov 2009 20:22:36 -0500
Subject: [PATCH] Optimize sysdb_enumgrent

This brings down the time needed to enumerate my group database from 10s to 4s
The downside is that I can't filter group members by uid range.
---
 server/db/sysdb.h                 |   10 +-
 server/db/sysdb_search.c          |  341 ++----------------------------------
 server/responder/nss/nsssrv_cmd.c |  348 +++++++++++++++++++------------------
 3 files changed, 197 insertions(+), 502 deletions(-)

diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index a329985..0512a7f 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -31,9 +31,12 @@
 
 #define SYSDB_BASE "cn=sysdb"
 #define SYSDB_DOM_BASE "cn=%s,cn=sysdb"
-#define SYSDB_TMPL_USER_BASE "cn=users,cn=%s,"SYSDB_BASE
-#define SYSDB_TMPL_GROUP_BASE "cn=groups,cn=%s,"SYSDB_BASE
-#define SYSDB_TMPL_CUSTOM_BASE "cn=custom,cn=%s,"SYSDB_BASE
+#define SYSDB_USERS_CONTAINER "cn=users"
+#define SYSDB_GROUPS_CONTAINER "cn=groups"
+#define SYSDB_CUSTOM_CONTAINER "cn=custom"
+#define SYSDB_TMPL_USER_BASE SYSDB_USERS_CONTAINER",cn=%s,"SYSDB_BASE
+#define SYSDB_TMPL_GROUP_BASE SYSDB_GROUPS_CONTAINER",cn=%s,"SYSDB_BASE
+#define SYSDB_TMPL_CUSTOM_BASE SYSDB_CUSTOM_CONTAINER",cn=%s,"SYSDB_BASE
 
 #define SYSDB_USER_CLASS "user"
 #define SYSDB_GROUP_CLASS "group"
@@ -113,6 +116,7 @@
                         SYSDB_DEFAULT_ATTRS, \
                         NULL}
 #define SYSDB_GRSRC_ATTRS {SYSDB_NAME, SYSDB_GIDNUM, \
+                           SYSDB_MEMBER, \
                            SYSDB_DEFAULT_ATTRS, \
                            NULL}
 #define SYSDB_GRPW_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \
diff --git a/server/db/sysdb_search.c b/server/db/sysdb_search.c
index 2b5dc36..03c7b27 100644
--- a/server/db/sysdb_search.c
+++ b/server/db/sysdb_search.c
@@ -35,7 +35,6 @@ struct sysdb_search_ctx {
 
     struct sss_domain_info *domain;
 
-    bool enumeration;
     const char *expression;
 
     sysdb_callback_t callback;
@@ -43,8 +42,6 @@ struct sysdb_search_ctx {
 
     gen_callback gen_aux_fn;
 
-    struct get_mem_ctx *gmctx;
-
     struct ldb_result *res;
 
     const char **attrs;
@@ -96,12 +93,14 @@ static void request_done(struct sysdb_search_ctx *sctx)
     sctx->callback(sctx->ptr, EOK, sctx->res);
 }
 
+static int mpg_convert(struct ldb_message *msg);
+
 static int get_gen_callback(struct ldb_request *req,
                             struct ldb_reply *rep)
 {
     struct sysdb_search_ctx *sctx;
     struct ldb_result *res;
-    int n;
+    int n, ret;
 
     sctx = talloc_get_type(req->context, struct sysdb_search_ctx);
     res = sctx->res;
@@ -117,6 +116,15 @@ static int get_gen_callback(struct ldb_request *req,
 
     switch (rep->type) {
     case LDB_REPLY_ENTRY:
+
+        if (sctx->ctx->mpg) {
+            ret = mpg_convert(rep->message);
+            if (ret != EOK) {
+                request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
+                return LDB_ERR_OPERATIONS_ERROR;
+            }
+        }
+
         res->msgs = talloc_realloc(res, res->msgs,
                                    struct ldb_message *,
                                    res->count + 2);
@@ -298,8 +306,6 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx,
         return ENOMEM;
     }
 
-    sctx->enumeration = true;
-
     if (expression)
         sctx->expression = expression;
     else
@@ -320,225 +326,6 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx,
 
 /* groups */
 
-struct get_mem_ctx {
-    struct sysdb_search_ctx *ret_sctx;
-    struct ldb_message **grps;
-    int num_grps;
-};
-
-static void get_members(struct sysdb_search_ctx *sctx)
-{
-    struct get_mem_ctx *gmctx;
-    struct ldb_request *req;
-    struct ldb_message *msg;
-    struct ldb_dn *dn;
-    static const char *attrs[] = SYSDB_GRPW_ATTRS;
-    int ret;
-
-    gmctx = sctx->gmctx;
-
-    if (gmctx->grps[0] == NULL) {
-        return request_done(sctx);
-    }
-
-    /* fetch next group to search for members */
-    gmctx->num_grps--;
-    msg = gmctx->grps[gmctx->num_grps];
-    gmctx->grps[gmctx->num_grps] = NULL;
-
-    /* queue the group entry on the final result structure */
-    sctx->res->msgs = talloc_realloc(sctx->res, sctx->res->msgs,
-                                     struct ldb_message *,
-                                     sctx->res->count + 2);
-    if (!sctx->res->msgs) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-    sctx->res->msgs[sctx->res->count + 1] = NULL;
-    sctx->res->msgs[sctx->res->count] = talloc_steal(sctx->res->msgs, msg);
-    sctx->res->count++;
-
-    /* search for this group members */
-    sctx->expression = talloc_asprintf(sctx, SYSDB_GRNA2_FILTER,
-                                       ldb_dn_get_linearized(msg->dn));
-    if (!sctx->expression) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb,
-                        SYSDB_TMPL_USER_BASE, sctx->domain->name);
-    if (!dn) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    sctx->gen_aux_fn = get_members;
-
-    ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx,
-                               dn, LDB_SCOPE_SUBTREE,
-                               sctx->expression, attrs, NULL,
-                               sctx, get_gen_callback,
-                               NULL);
-    if (ret != LDB_SUCCESS) {
-        return request_ldberror(sctx, ret);
-    }
-
-    ret = ldb_request(sctx->ctx->ldb, req);
-    if (ret != LDB_SUCCESS) {
-        return request_ldberror(sctx, ret);
-    }
-}
-
-static void match_group_members(struct sysdb_search_ctx *sctx);
-static void enum_members(struct sysdb_search_ctx *sctx)
-{
-    static const char *attrs[] = SYSDB_GRENT_ATTRS;
-    struct ldb_request *req;
-    struct ldb_dn *dn;
-    int ret;
-
-    /* search for all users that have memberof set */
-    sctx->expression = talloc_asprintf(sctx, SYSDB_GRNA2_FILTER, "*");
-    if (!sctx->expression) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb,
-                        SYSDB_TMPL_USER_BASE, sctx->domain->name);
-    if (!dn) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    sctx->gen_aux_fn = match_group_members;
-
-    ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx,
-                               dn, LDB_SCOPE_SUBTREE,
-                               sctx->expression, attrs, NULL,
-                               sctx, get_gen_callback,
-                               NULL);
-    if (ret != LDB_SUCCESS) {
-        return request_ldberror(sctx, ret);
-    }
-
-    ret = ldb_request(sctx->ctx->ldb, req);
-    if (ret != LDB_SUCCESS) {
-        return request_ldberror(sctx, ret);
-    }
-}
-
-static void match_group_members(struct sysdb_search_ctx *sctx)
-{
-    struct get_mem_ctx *gmctx;
-    struct ldb_message **users;
-    size_t num_users;
-    size_t res_idx, grp_idx, i;
-    const char *grp_dn;
-
-    gmctx = sctx->gmctx;
-
-    /* we have groups in gmctx->grps, and users in res->msgs
-     * now we need to create a new set where we have each group
-     * followed by pointers to its users */
-    users = sctx->res->msgs;
-    num_users = sctx->res->count;
-
-    /* allocate initial storage all in one go */
-    sctx->res->count = gmctx->num_grps + num_users;
-    sctx->res->msgs = talloc_array(sctx->res, struct ldb_message *,
-                                   sctx->res->count + 1);
-    if (!sctx->res->msgs) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    res_idx = 0;
-    for (grp_idx = 0; grp_idx < gmctx->num_grps; grp_idx++) {
-
-        /* store the group first */
-
-        if (res_idx == sctx->res->count) {
-            sctx->res->count += 10; /* allocate 10 at a time */
-            sctx->res->msgs = talloc_realloc(sctx->res, sctx->res->msgs,
-                                             struct ldb_message *,
-                                             sctx->res->count + 1);
-            if (!sctx->res->msgs) {
-                return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-            }
-        }
-
-        sctx->res->msgs[res_idx] = gmctx->grps[grp_idx];
-        res_idx++;
-
-        grp_dn = ldb_dn_get_linearized(gmctx->grps[grp_idx]->dn);
-
-        /* now search for the members */
-        for (i = 0; i < num_users; i++) {
-            struct ldb_message_element *el;
-            struct ldb_val *val;
-            int j;
-
-            el = ldb_msg_find_element(users[i], SYSDB_MEMBEROF);
-            for (j = 0; j < el->num_values; j++) {
-                val = &(el->values[j]);
-                /* HACK: dn comparisons should be made with ldb_dn_compare() but
-                 * that function requires slow conversions and memory
-                 * allocations. ATM all DNs we use internally should be safe to
-                 * compare directly in a case-insensitive manner */
-                if (strncasecmp(grp_dn, (char *)val->data, val->length) != 0) {
-                    continue;
-                }
-
-                /* ok users belong to this group */
-                if (res_idx == sctx->res->count) {
-                    sctx->res->count += 10; /* allocate 10 at a time */
-                    sctx->res->msgs = talloc_realloc(sctx->res,
-                                                     sctx->res->msgs,
-                                                     struct ldb_message *,
-                                                     sctx->res->count + 1);
-                    if (!sctx->res->msgs) {
-                        return request_ldberror(sctx,
-                                                LDB_ERR_OPERATIONS_ERROR);
-                    }
-                }
-
-                sctx->res->msgs[res_idx] = users[i];
-                res_idx++;
-
-                /* now remove value so that we do not parse it again, and
-                 * completely remove the user if it has no more values */
-                if (el->num_values == 1) {
-
-                    /* make sure to remove memberof as we messed it up */
-                    ldb_msg_remove_element(users[i], el);
-
-                    /* remove user from list by swapping it out and replacing
-                     * it with the last on the list and shortening the list */
-                    num_users--;
-                    if (i == num_users) {
-                        users[i] = NULL;
-                    } else {
-                        users[i] = users[num_users];
-                        users[num_users] = NULL;
-                        /* need to rewind or this user won't be checked */
-                        i--;
-                    }
-
-                } else {
-                    /* still more values, just swap out this one */
-                    el->num_values--;
-                    if (j != el->num_values) {
-                        /* swap last in */
-                        el->values[j] = el->values[el->num_values];
-                    }
-                }
-            }
-        }
-    }
-
-    /* count may be larger as we allocate in chuncks of 10,
-     * make sure we report back the real size */
-    sctx->res->count = res_idx;
-
-    return request_done(sctx);
-}
-
 static int mpg_convert(struct ldb_message *msg)
 {
     struct ldb_message_element *el;
@@ -567,106 +354,6 @@ static int mpg_convert(struct ldb_message *msg)
     return EOK;
 }
 
-static int get_grp_callback(struct ldb_request *req,
-                            struct ldb_reply *rep)
-{
-    struct sysdb_search_ctx *sctx;
-    struct ldb_result *res;
-    int n, ret;
-
-    sctx = talloc_get_type(req->context, struct sysdb_search_ctx);
-    res = sctx->res;
-
-    if (!rep) {
-        request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-        return LDB_ERR_OPERATIONS_ERROR;
-    }
-    if (rep->error != LDB_SUCCESS) {
-        request_ldberror(sctx, rep->error);
-        return rep->error;
-    }
-
-    switch (rep->type) {
-    case LDB_REPLY_ENTRY:
-
-        if (sctx->ctx->mpg) {
-            ret = mpg_convert(rep->message);
-            if (ret != EOK) {
-                request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-                return LDB_ERR_OPERATIONS_ERROR;
-            }
-        }
-
-        res->msgs = talloc_realloc(res, res->msgs,
-                                   struct ldb_message *,
-                                   res->count + 2);
-        if (!res->msgs) {
-            request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-            return LDB_ERR_OPERATIONS_ERROR;
-        }
-
-        res->msgs[res->count + 1] = NULL;
-
-        res->msgs[res->count] = talloc_steal(res->msgs, rep->message);
-        res->count++;
-        break;
-
-    case LDB_REPLY_REFERRAL:
-        if (res->refs) {
-            for (n = 0; res->refs[n]; n++) /*noop*/ ;
-        } else {
-            n = 0;
-        }
-
-        res->refs = talloc_realloc(res, res->refs, char *, n + 2);
-        if (! res->refs) {
-            request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-            return LDB_ERR_OPERATIONS_ERROR;
-        }
-
-        res->refs[n] = talloc_steal(res->refs, rep->referral);
-        res->refs[n + 1] = NULL;
-        break;
-
-    case LDB_REPLY_DONE:
-        res->controls = talloc_steal(res, rep->controls);
-
-        /* no results, return */
-        if (res->count == 0) {
-            request_done(sctx);
-            return LDB_SUCCESS;
-        }
-
-        if (res->count > 0) {
-
-            sctx->gmctx = talloc_zero(req, struct get_mem_ctx);
-            if (!sctx->gmctx) {
-                request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-                return LDB_ERR_OPERATIONS_ERROR;
-            }
-            sctx->gmctx->grps = res->msgs;
-            sctx->gmctx->num_grps = res->count;
-            res->msgs = NULL;
-            res->count = 0;
-
-            /* now get members */
-            if (sctx->enumeration) {
-                enum_members(sctx);
-            } else {
-                get_members(sctx);
-            }
-            return LDB_SUCCESS;
-        }
-
-        /* anything else is an error */
-        request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-        return LDB_ERR_OPERATIONS_ERROR;
-    }
-
-    talloc_free(rep);
-    return LDB_SUCCESS;
-}
-
 static void grp_search(struct tevent_req *treq)
 {
     struct sysdb_search_ctx *sctx;
@@ -696,7 +383,7 @@ static void grp_search(struct tevent_req *treq)
     ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx,
                                base_dn, LDB_SCOPE_SUBTREE,
                                sctx->expression, attrs, NULL,
-                               sctx, get_grp_callback,
+                               sctx, get_gen_callback,
                                NULL);
     if (ret != LDB_SUCCESS) {
         return request_ldberror(sctx, ret);
@@ -807,8 +494,6 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx,
         return ENOMEM;
     }
 
-    sctx->enumeration = true;
-
     if (ctx->mpg) {
         sctx->expression = SYSDB_GRENT_MPG_FILTER;
     } else {
diff --git a/server/responder/nss/nsssrv_cmd.c b/server/responder/nss/nsssrv_cmd.c
index a029baf..4206419 100644
--- a/server/responder/nss/nsssrv_cmd.c
+++ b/server/responder/nss/nsssrv_cmd.c
@@ -1477,6 +1477,7 @@ static int fill_grent(struct sss_packet *packet,
                       int max, int *count)
 {
     struct ldb_message *msg;
+    struct ldb_message_element *el;
     uint8_t *body;
     size_t blen;
     uint32_t gid, uid;
@@ -1484,7 +1485,9 @@ static int fill_grent(struct sss_packet *packet,
     size_t nsize;
     size_t delim;
     size_t dom_len;
-    int i, ret, num, memnum, used;
+    int i, j;
+    int ret, num, memnum;
+    size_t sysnamelen, sysuserslen;
     size_t rzero, rsize;
     bool add_domain = dom->fqnames;
     const char *domain = dom->name;
@@ -1498,9 +1501,10 @@ static int fill_grent(struct sss_packet *packet,
         dom_len = 0;
     }
 
+    sysnamelen = strlen(SYSDB_NAME);
+    sysuserslen = strlen(SYSDB_USERS_CONTAINER);
+
     num = 0;
-    memnum = 0;
-    used = 0;
 
     /* first 2 fields (len and reserved), filled up later */
     ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
@@ -1511,220 +1515,222 @@ static int fill_grent(struct sss_packet *packet,
     rzero = 2*sizeof(uint32_t);
     rsize = 0;
 
-    for (i = 0; i < *count; i++, used++) {
+    for (i = 0; i < *count; i++) {
         msg = msgs[i];
 
         /* new group */
-        if (ldb_msg_check_string_attribute(msg, "objectClass",
-                                                SYSDB_GROUP_CLASS)) {
-            if (memnum) {
-                /* set num of members */
-                ((uint32_t *)(&body[rzero+MNUM_ROFFSET]))[0] = memnum;
-                memnum = 0;
-            }
+        if (!ldb_msg_check_string_attribute(msg, "objectClass",
+                                            SYSDB_GROUP_CLASS)) {
+            DEBUG(1, ("Wrong object (%s) found on stack!\n",
+                      ldb_dn_get_linearized(msg->dn)));
+            continue;
+        }
 
-            /* if we reached the max allowed entries, simply return */
-            if (num >= max) {
-                goto done;
-            }
+        /* if we reached the max allowed entries, simply return */
+        if (num >= max) {
+            goto done;
+        }
+
+        /* new result starts at end of previous result */
+        rzero += rsize;
+        rsize = 0;
 
-            /* new result starts at end of previous result */
-            rzero += rsize;
-            rsize = 0;
+        /* find group name/gid */
+        name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+        gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
+        if (!name || !gid) {
+            DEBUG(1, ("Incomplete group object for %s[%llu]! Skipping\n",
+                      name?name:"<NULL>", (unsigned long long int)gid));
+            continue;
+        }
 
-            /* find group name/gid */
-            name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-            gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
-            if (!name || !gid) {
-                DEBUG(1, ("Incomplete group object for %s[%llu]! Skipping\n",
-                          name?name:"<NULL>", (unsigned long long int)gid));
+        if (filter_groups) {
+            ret = nss_ncache_check_group(nctx->ncache,
+                                         nctx->neg_timeout, domain, name);
+            if (ret == EEXIST) {
+                DEBUG(4, ("Group [%s@%s] filtered out! (negative cache)\n",
+                          name, domain));
                 continue;
             }
+        }
 
-            if (filter_groups) {
-                ret = nss_ncache_check_group(nctx->ncache,
-                                             nctx->neg_timeout, domain, name);
-                if (ret == EEXIST) {
-                    DEBUG(4, ("Group [%s@%s] filtered out! (negative cache)\n",
-                              name, domain));
-                    continue;
-                }
-            }
+        /* check that the gid is valid for this domain */
+        if ((dom->id_min && (gid < dom->id_min)) ||
+            (dom->id_max && (gid > dom->id_max))) {
+                DEBUG(4, ("Group [%s@%s] filtered out! (id out of range)\n",
+                          name, domain));
+            continue;
+        }
 
-            /* check that the gid is valid for this domain */
-            if ((dom->id_min && (gid < dom->id_min)) ||
-                (dom->id_max && (gid > dom->id_max))) {
-                    DEBUG(4, ("Group [%s@%s] filtered out! (id out of range)\n",
-                              name, domain));
-                continue;
-            }
+        nsize = strlen(name) + 1; /* includes terminating \0 */
+        if (add_domain) nsize += delim + dom_len;
 
-            nsize = strlen(name) + 1; /* includes terminating \0 */
-            if (add_domain) nsize += delim + dom_len;
+        /* fill in gid and name and set pointer for number of members */
+        rsize = STRS_ROFFSET + nsize + 2; /* name\0x\0 */
 
-            /* fill in gid and name and set pointer for number of members */
-            rsize = STRS_ROFFSET + nsize + 2; /* name\0x\0 */
+        ret = sss_packet_grow(packet, rsize);
+        if (ret != EOK) {
+            num = 0;
+            goto done;
+        }
+        sss_packet_get_body(packet, &body, &blen);
 
-            ret = sss_packet_grow(packet, rsize);
-            if (ret != EOK) {
-                num = 0;
-                goto done;
-            }
-            sss_packet_get_body(packet, &body, &blen);
+        /*  0-3: 32bit number gid */
+        ((uint32_t *)(&body[rzero+GID_ROFFSET]))[0] = gid;
 
-            /*  0-3: 32bit number gid */
-            ((uint32_t *)(&body[rzero+GID_ROFFSET]))[0] = gid;
+        /*  4-7: 32bit unsigned number of members */
+        ((uint32_t *)(&body[rzero+MNUM_ROFFSET]))[0] = 0;
 
-            /*  4-7: 32bit unsigned number of members */
-            ((uint32_t *)(&body[rzero+MNUM_ROFFSET]))[0] = 0;
+        /*  8-X: sequence of strings (name, passwd, mem..) */
+        if (add_domain) {
+            ret = snprintf((char *)&body[rzero+STRS_ROFFSET],
+                            nsize, namefmt, name, domain);
+            if (ret >= nsize) {
+                /* need more space, got creative with the print format ? */
+                int t = ret - nsize + 1;
+                ret = sss_packet_grow(packet, t);
+                if (ret != EOK) {
+                    num = 0;
+                    goto done;
+                }
+                sss_packet_get_body(packet, &body, &blen);
+                rsize += t;
+                delim += t;
+                nsize += t;
 
-            /*  8-X: sequence of strings (name, passwd, mem..) */
-            if (add_domain) {
+                /* retry */
                 ret = snprintf((char *)&body[rzero+STRS_ROFFSET],
                                 nsize, namefmt, name, domain);
-                if (ret >= nsize) {
-                    /* need more space, got creative with the print format ? */
-                    int t = ret - nsize + 1;
-                    ret = sss_packet_grow(packet, t);
-                    if (ret != EOK) {
-                        num = 0;
-                        goto done;
-                    }
-                    sss_packet_get_body(packet, &body, &blen);
-                    rsize += t;
-                    delim += t;
-                    nsize += t;
-
-                    /* retry */
-                    ret = snprintf((char *)&body[rzero+STRS_ROFFSET],
-                                    nsize, namefmt, name, domain);
-                }
+            }
 
-                if (ret != nsize-1) {
-                    DEBUG(1, ("Failed to generate a fully qualified name for"
-                              " group [%s] in [%s]! Skipping\n", name, domain));
-                    /* reclaim space */
-                    ret = sss_packet_shrink(packet, rsize);
-                    if (ret != EOK) {
-                        num = 0;
-                        goto done;
-                    }
-                    rsize = 0;
-                    continue;
+            if (ret != nsize-1) {
+                DEBUG(1, ("Failed to generate a fully qualified name for"
+                          " group [%s] in [%s]! Skipping\n", name, domain));
+                /* reclaim space */
+                ret = sss_packet_shrink(packet, rsize);
+                if (ret != EOK) {
+                    num = 0;
+                    goto done;
                 }
-            } else {
-                memcpy(&body[rzero+STRS_ROFFSET], name, nsize);
+                rsize = 0;
+                continue;
             }
-
-            body[rzero + rsize -2] = 'x'; /* group passwd field */
-            body[rzero + rsize -1] = '\0';
-
-            num++;
-            continue;
+        } else {
+            memcpy(&body[rzero+STRS_ROFFSET], name, nsize);
         }
 
-        if (rsize == 0) {
-            /* some error occurred and there is no result structure ready to
-             * store members */
-            continue;
-        }
+        body[rzero + rsize -2] = 'x'; /* group passwd field */
+        body[rzero + rsize -1] = '\0';
 
-        /* member */
-        if (ldb_msg_check_string_attribute(msg, "objectClass",
-                                                SYSDB_USER_CLASS)) {
+        el = ldb_msg_find_element(msg, SYSDB_MEMBER);
+        if (el) {
+            memnum = 0;
 
-            nsize = 0;
+            for (j = 0; j < el->num_values; j++) {
+                int nlen;
+                char *p;
 
-            name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-            uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
-            if (!name || !uid) {
-                DEBUG(1, ("Incomplete user object! Skipping\n"));
-                continue;
-            }
+                if (strncmp((const char *)el->values[j].data,
+                            SYSDB_NAME, sysnamelen) != 0) {
+                    DEBUG(1, ("Member [%.*s] not in the std format ?! "
+                              "("SYSDB_NAME"=value,...)\n",
+                              el->values[i].length,
+                              (const char *)el->values[i].data));
+                    continue;
+                }
 
-            if (nctx->filter_users_in_groups) {
-                ret = nss_ncache_check_user(nctx->ncache,
-                                            nctx->neg_timeout, domain, name);
-                if (ret == EEXIST) {
-                    DEBUG(4, ("Group [%s] member [%s@%s] filtered out! (negative"
-                              " cache)\n", (char *)&body[rzero+STRS_ROFFSET],
-                              name, domain));
+                name = &((const char *)el->values[j].data)[sysnamelen + 1];
+                p = strchr(name, ',');
+                if (!p) {
+                    DEBUG(1, ("Member [%.*s] not in the std format ?! "
+                              "("SYSDB_NAME"=value,...)\n",
+                              el->values[i].length,
+                              (const char *)el->values[j].data));
+                    continue;
+                }
+                nlen = p - name;
+                p++;
+                if (strncmp(p, SYSDB_USERS_CONTAINER, sysuserslen) != 0) {
+                    DEBUG(1, ("Member [%.*s] not in the std format ?! "
+                              "("SYSDB_NAME"=value,...)\n",
+                              el->values[i].length,
+                              (const char *)el->values[j].data));
                     continue;
                 }
-            }
 
-            /* check that the uid is valid for this domain */
-            if ((dom->id_min && (uid < dom->id_min)) ||
-                (dom->id_max && (uid > dom->id_max))) {
-                    DEBUG(4, ("Group [%s] member [%s@%s] filtered out! (id out"
-                              " of range)\n", (char *)&body[rzero+STRS_ROFFSET],
-                              name, domain));
-                continue;
-            }
+                nsize = nlen + 1; /* includes terminating \0 */
+                if (add_domain) nsize += delim + dom_len;
 
-            nsize = strlen(name) + 1;
-            if (add_domain) nsize += delim + dom_len;
+                ret = sss_packet_grow(packet, nsize);
+                if (ret != EOK) {
+                    num = 0;
+                    goto done;
+                }
+                sss_packet_get_body(packet, &body, &blen);
 
-            ret = sss_packet_grow(packet, nsize);
-            if (ret != EOK) {
-                num = 0;
-                goto done;
-            }
-            sss_packet_get_body(packet, &body, &blen);
+                if (add_domain) {
+                    char tmp[nlen+1];
+
+                    memcpy(tmp, name, nlen);
+                    tmp[nlen] = '\0';
 
-            if (add_domain) {
-                ret = snprintf((char *)&body[rzero + rsize],
-                                nsize, namefmt, name, domain);
-                if (ret >= nsize) {
-                    /* need more space, got creative with the print format ? */
-                    int t = ret - nsize + 1;
-                    ret = sss_packet_grow(packet, t);
-                    if (ret != EOK) {
-                        num = 0;
-                        goto done;
-                    }
-                    sss_packet_get_body(packet, &body, &blen);
-                    delim += t;
-                    nsize += t;
 
-                    /* retry */
                     ret = snprintf((char *)&body[rzero + rsize],
-                                    nsize, namefmt, name, domain);
-                }
+                                    nsize, namefmt, tmp, domain);
+                    if (ret >= nsize) {
+                        /* need more space,
+                         * got creative with the print format ? */
+                        int t = ret - nsize + 1;
+                        ret = sss_packet_grow(packet, t);
+                        if (ret != EOK) {
+                            num = 0;
+                            goto done;
+                        }
+                        sss_packet_get_body(packet, &body, &blen);
+                        delim += t;
+                        nsize += t;
+
+                        /* retry */
+                        ret = snprintf((char *)&body[rzero + rsize],
+                                        nsize, namefmt, tmp, domain);
+                    }
 
-                if (ret != nsize-1) {
-                    DEBUG(1, ("Failed to generate a fully qualified name for"
-                              " member [%s@%s] of group [%s]! Skipping\n", name,
-                              domain, (char *)&body[rzero+STRS_ROFFSET]));
-                    /* reclaim space */
-                    ret = sss_packet_shrink(packet, nsize);
-                    if (ret != EOK) {
-                        num = 0;
-                        goto done;
+                    if (ret != nsize-1) {
+                        DEBUG(1, ("Failed to generate a fully qualified name"
+                                  " for member [%s@%s] of group [%s]!"
+                                  " Skipping\n", name, domain,
+                                  (char *)&body[rzero+STRS_ROFFSET]));
+                        /* reclaim space */
+                        ret = sss_packet_shrink(packet, nsize);
+                        if (ret != EOK) {
+                            num = 0;
+                            goto done;
+                        }
+                        continue;
                     }
-                    continue;
+
+                } else {
+                    memcpy(&body[rzero + rsize], name, nlen);
+                    body[rzero + rsize + nlen] = '\0';
                 }
-            } else {
-                memcpy(&body[rzero + rsize], name, nsize);
+
+                rsize += nsize;
+
+                memnum++;
             }
 
-            rsize += nsize;
-            memnum++;
-            continue;
+            if (memnum) {
+                /* set num of members */
+                ((uint32_t *)(&body[rzero+MNUM_ROFFSET]))[0] = memnum;
+            }
         }
 
-        DEBUG(1, ("Wrong object (%s) found on stack!\n",
-                  ldb_dn_get_linearized(msg->dn)));
+        num++;
         continue;
     }
 
-    if (memnum) {
-        /* set num of members for the last result */
-        ((uint32_t *)(&body[rzero+MNUM_ROFFSET]))[0] = memnum;
-    }
-
 done:
-    *count = used;
+    *count = i;
 
     if (num == 0) {
         /* if num is 0 most probably something went wrong,
-- 
1.6.2.5

