URL: https://github.com/SSSD/sssd/pull/332
Author: sumit-bose
 Title: #332: sydb: index improvements
Action: opened

PR body:
"""
This patch first adds some missing attributes to the index. The most
important one here is 'ghost' which is used in the backed during group
lookups.

Additionally the index for one-level searches @IDXONE is removed. One
level searches were only used in a few places and are replace by this
patch with sub-tree searches. The main reason for the removal is that
maintaining the index is quite costly because it is basically a single
huge blob in the underlying tdb database.

Finally this patch removes the index on the objectClass attribute and
adds a new index on an new attribute called objectCategory which is used
instead of objectClass for all objects expect user and group. Typically
user and group searches are done by name or ID attributes which are more
specific then objectClass. And since most of the objects in the cache
will be users and groups a search for all users or groups will be near
to a full database search so that the index won't help much in this case
either. The reason for removing it are the costs to manage it when there
are many users or groups.

Due to the index changes some search results are returned in different
order. I updated the related tests so that the checks do not depend on a
specific order anymore.

If 'LDB_WARN_UNINDEXED=1' is set in /etc/sysconfig/sssd full database
searches are indicated with a 'ldb FULL SEARCH: ...' debug message.
Since there are no extra costs we might want to enable this by default
with a certain debug level.

Currently there are two types of un-indexed searches. Searches with
'(distinguishedName=*)' in the filter are related to sub-tree deletes
and '(dataExpireTimestamp<=...)' are related to refresh and cleanup
tasks. Please note that '<=' and sub-string searches cannot be indexed.
"""

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/332/head:pr332
git checkout pr332
From ccf05b56aaff734ed084829f48cd1b6286618cbf Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Thu, 29 Jun 2017 11:54:05 +0200
Subject: [PATCH] sydb: index improvements

This patch first adds some missing attributes to the index. The most
important one here is 'ghost' which is used in the backed during group
lookups.

Additionally the index for one-level searches @IDXONE is removed. One
level searches were only used in a few places and are replace by this
patch with sub-tree searches. The main reason for the removal is that
maintaining the index is quite costly because it is basically a single
huge blob in the underlying tdb database.

Finally this patch removes the index on the objectClass attribute and
adds a new index on an new attribute called objectCategory which is used
instead of objectClass for all objects expect user and group. Typically
user and group searches are done by name or ID attributes which are more
specific then objectClass. And since most of the objects in the cache
will be users and groups a search for all users or groups will be near
to a full database search so that the index won't help much in this case
either. The reason for removing it are the costs to manage it when there
are many users or groups.

Due to the index changes some search results are returned in different
order. I updated the related tests so that the checks do not depend on a
specific order anymore.

If 'LDB_WARN_UNINDEXED=1' is set in /etc/sysconfig/sssd full database
searches are indicated with a 'ldb FULL SEARCH: ...' debug message.
Since there are no extra costs we might want to enable this by default
with a certain debug level.

Currently there are two types of un-indexed searches. Searches with
'(distinguishedName=*)' in the filter are related to sub-tree deletes
and '(dataExpireTimestamp<=...)' are related to refresh and cleanup
tasks. Please note that '<=' and sub-string searches cannot be indexed.
---
 src/db/sysdb.h                                |   1 +
 src/db/sysdb_autofs.c                         |  13 +-
 src/db/sysdb_certmap.c                        |   4 +-
 src/db/sysdb_init.c                           |  50 ++++-
 src/db/sysdb_private.h                        |  18 +-
 src/db/sysdb_ranges.c                         |   7 +-
 src/db/sysdb_selinux.c                        |   4 +-
 src/db/sysdb_subdomains.c                     |  11 +-
 src/db/sysdb_upgrade.c                        | 265 ++++++++++++++++++++++++++
 src/providers/ipa/ipa_access.c                |   3 +-
 src/providers/ipa/ipa_hbac_rules.c            |   9 +
 src/responder/ifp/ifp_users.c                 |   2 +-
 src/tests/cmocka/test_ipa_subdomains_server.c | 233 ++++++++++++----------
 src/tests/cmocka/test_sysdb_views.c           | 192 ++++++++++++++-----
 src/tests/sysdb-tests.c                       |  45 ++++-
 15 files changed, 677 insertions(+), 180 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 21d6cf4fc..f1fb3ab91 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -66,6 +66,7 @@
 #define SYSDB_NAME "name"
 #define SYSDB_NAME_ALIAS "nameAlias"
 #define SYSDB_OBJECTCLASS "objectClass"
+#define SYSDB_OBJECTCATEGORY "objectCategory"
 
 #define SYSDB_NEXTID "nextID"
 #define SYSDB_UIDNUM "uidNumber"
diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
index b3e9b4ec8..d5e66bc2d 100644
--- a/src/db/sysdb_autofs.c
+++ b/src/db/sysdb_autofs.c
@@ -272,7 +272,7 @@ sysdb_save_autofsentry(struct sss_domain_info *domain,
         }
     }
 
-    ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS,
+    ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCATEGORY,
                                  SYSDB_AUTOFS_ENTRY_OC);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "Could not set entry object class [%d]: %s\n",
@@ -377,14 +377,14 @@ sysdb_autofs_entries_by_map(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    filter = talloc_asprintf(tmp_ctx, "(objectclass=%s)",
-                             SYSDB_AUTOFS_ENTRY_OC);
+    filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
+                             SYSDB_OBJECTCATEGORY, SYSDB_AUTOFS_ENTRY_OC);
     if (!filter) {
         ret = ENOMEM;
         goto done;
     }
 
-    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, mapdn, LDB_SCOPE_ONELEVEL,
+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, mapdn, LDB_SCOPE_SUBTREE,
                              filter, attrs, &count, &msgs);
     if (ret != EOK && ret != ENOENT) {
         DEBUG(SSSDBG_OP_FAILURE, "sysdb search failed: %d\n", ret);
@@ -455,8 +455,9 @@ sysdb_invalidate_autofs_maps(struct sss_domain_info *domain)
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) return ENOMEM;
 
-    filter = talloc_asprintf(tmp_ctx, "(&(objectclass=%s)(%s=*))",
-                             SYSDB_AUTOFS_MAP_OC, SYSDB_NAME);
+    filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(%s=*))",
+                             SYSDB_OBJECTCATEGORY, SYSDB_AUTOFS_MAP_OC,
+                             SYSDB_NAME);
     if (!filter) {
         ret = ENOMEM;
         goto done;
diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c
index 2d89c08a0..6c1ea1d07 100644
--- a/src/db/sysdb_certmap.c
+++ b/src/db/sysdb_certmap.c
@@ -100,7 +100,7 @@ static errno_t sysdb_certmap_add(struct sysdb_ctx *sysdb,
         goto done;
     }
 
-    ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_CERTMAP_CLASS);
+    ret = sysdb_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_CERTMAP_CLASS);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n");
         goto done;
@@ -311,7 +311,7 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
 
     ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
                      container_dn, LDB_SCOPE_SUBTREE,
-                     attrs, "objectclass=%s", SYSDB_CERTMAP_CLASS);
+                     attrs, "%s=%s", SYSDB_OBJECTCATEGORY, SYSDB_CERTMAP_CLASS);
     if (ret != LDB_SUCCESS) {
         DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n");
         ret = EIO;
diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
index 538ba027c..34d8f8a8e 100644
--- a/src/db/sysdb_init.c
+++ b/src/db/sysdb_init.c
@@ -358,8 +358,47 @@ static errno_t sysdb_ts_cache_upgrade(TALLOC_CTX *mem_ctx,
                                       const char *cur_version,
                                       const char **_new_version)
 {
-    /* Currently the sysdb cache only has one version */
-    return EFAULT;
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx;
+    const char *version;
+    struct ldb_context *save_ldb;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    /* The upgrade process depends on having ldb around, yet the upgrade
+     * function shouldn't set the ldb pointer, only the connect function
+     * should after it's successful. To avoid hard refactoring, save the
+     * ldb pointer here and restore in the 'done' handler
+     */
+    save_ldb = sysdb->ldb;
+    sysdb->ldb = ldb;
+
+    version = talloc_strdup(tmp_ctx, cur_version);
+    if (version == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_CONF_SETTINGS,
+          "Upgrading timstamp cache of DB [%s] from version: %s\n",
+          domain->name, version);
+
+    if (strcmp(version, SYSDB_TS_VERSION_0_1) == 0) {
+        ret = sysdb_ts_upgrade_01(sysdb, &version);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    ret = EOK;
+done:
+    sysdb->ldb = save_ldb;
+    *_new_version = version;
+    talloc_free(tmp_ctx);
+    return ret;
 }
 
 static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
@@ -503,6 +542,13 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
         }
     }
 
+    if (strcmp(version, SYSDB_VERSION_0_18) == 0) {
+        ret = sysdb_upgrade_18(sysdb, &version);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
     ret = EOK;
 done:
     sysdb->ldb = save_ldb;
diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
index 433220dcc..87e3c5314 100644
--- a/src/db/sysdb_private.h
+++ b/src/db/sysdb_private.h
@@ -23,6 +23,7 @@
 #ifndef __INT_SYS_DB_H__
 #define __INT_SYS_DB_H__
 
+#define SYSDB_VERSION_0_19 "0.19"
 #define SYSDB_VERSION_0_18 "0.18"
 #define SYSDB_VERSION_0_17 "0.17"
 #define SYSDB_VERSION_0_16 "0.16"
@@ -42,7 +43,7 @@
 #define SYSDB_VERSION_0_2 "0.2"
 #define SYSDB_VERSION_0_1 "0.1"
 
-#define SYSDB_VERSION SYSDB_VERSION_0_18
+#define SYSDB_VERSION SYSDB_VERSION_0_19
 
 #define SYSDB_BASE_LDIF \
      "dn: @ATTRIBUTES\n" \
@@ -56,7 +57,6 @@
      "\n" \
      "dn: @INDEXLIST\n" \
      "@IDXATTR: cn\n" \
-     "@IDXATTR: objectclass\n" \
      "@IDXATTR: member\n" \
      "@IDXATTR: memberof\n" \
      "@IDXATTR: name\n" \
@@ -71,7 +71,12 @@
      "@IDXATTR: sudoUser\n" \
      "@IDXATTR: sshKnownHostsExpire\n" \
      "@IDXATTR: objectSIDString\n" \
-     "@IDXONE: 1\n" \
+     "@IDXATTR: ghost\n" \
+     "@IDXATTR: userPrincipalName\n" \
+     "@IDXATTR: canonicalUserPrincipalName\n" \
+     "@IDXATTR: uniqueID\n" \
+     "@IDXATTR: mail\n" \
+     "@IDXATTR: objectCategory\n" \
      "\n" \
      "dn: @MODULES\n" \
      "@LIST: asq,memberof\n" \
@@ -86,9 +91,10 @@
      "\n"
 
 /* The timestamp cache has its own versioning */
+#define SYSDB_TS_VERSION_0_2 "0.2"
 #define SYSDB_TS_VERSION_0_1 "0.1"
 
-#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_1
+#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_2
 
 #define SYSDB_TS_BASE_LDIF \
      "dn: @ATTRIBUTES\n" \
@@ -97,7 +103,6 @@
      "dn: @INDEXLIST\n" \
      "@IDXATTR: lastUpdate\n" \
      "@IDXATTR: dataExpireTimestamp\n" \
-     "@IDXONE: 1\n" \
      "\n" \
      "dn: cn=sysdb\n" \
      "cn: sysdb\n" \
@@ -162,6 +167,9 @@ int sysdb_upgrade_16(struct sysdb_ctx *sysdb, const char **ver);
 int sysdb_upgrade_17(struct sysdb_ctx *sysdb,
                      struct sysdb_dom_upgrade_ctx *upgrade_ctx,
                      const char **ver);
+int sysdb_upgrade_18(struct sysdb_ctx *sysdb, const char **ver);
+
+int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver);
 
 int sysdb_add_string(struct ldb_message *msg,
                      const char *attr, const char *value);
diff --git a/src/db/sysdb_ranges.c b/src/db/sysdb_ranges.c
index 511e4785d..c11045725 100644
--- a/src/db/sysdb_ranges.c
+++ b/src/db/sysdb_ranges.c
@@ -71,8 +71,9 @@ errno_t sysdb_get_ranges(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
         goto done;
     }
     ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
-                     basedn, LDB_SCOPE_ONELEVEL,
-                     attrs, "objectclass=%s", SYSDB_ID_RANGE_CLASS);
+                     basedn, LDB_SCOPE_SUBTREE,
+                     attrs, "%s=%s", SYSDB_OBJECTCATEGORY,
+                                     SYSDB_ID_RANGE_CLASS);
     if (ret != LDB_SUCCESS) {
         ret = EIO;
         goto done;
@@ -198,7 +199,7 @@ errno_t sysdb_range_create(struct sysdb_ctx *sysdb, struct range_info *range)
         goto done;
     }
 
-    ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_ID_RANGE_CLASS);
+    ret = sysdb_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_ID_RANGE_CLASS);
     if (ret) goto done;
 
     if (range->trusted_dom_sid == NULL && range->secondary_base_rid != 0) {
diff --git a/src/db/sysdb_selinux.c b/src/db/sysdb_selinux.c
index 2dbbb75b9..614679f3b 100644
--- a/src/db/sysdb_selinux.c
+++ b/src/db/sysdb_selinux.c
@@ -51,7 +51,7 @@ sysdb_add_selinux_entity(struct sysdb_ctx *sysdb,
         goto done;
     }
 
-    ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, objectclass);
+    ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCATEGORY, objectclass);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "Could not set map object class [%d]: %s\n",
               ret, strerror(ret));
@@ -261,7 +261,7 @@ sysdb_get_selinux_usermaps(TALLOC_CTX *mem_ctx,
     }
 
     filter = talloc_asprintf(mem_ctx, "(%s=%s)",
-                             SYSDB_OBJECTCLASS, SYSDB_SELINUX_USERMAP_CLASS);
+                             SYSDB_OBJECTCATEGORY, SYSDB_SELINUX_USERMAP_CLASS);
     if (filter == NULL) {
         talloc_free(basedn);
         return ENOMEM;
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index 2789cc494..6268b03e6 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -338,8 +338,9 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
         goto done;
     }
     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
-                     basedn, LDB_SCOPE_ONELEVEL,
-                     attrs, "objectclass=%s", SYSDB_SUBDOMAIN_CLASS);
+                     basedn, LDB_SCOPE_SUBTREE,
+                     attrs, "%s=%s", SYSDB_OBJECTCATEGORY,
+                                     SYSDB_SUBDOMAIN_CLASS);
     if (ret != LDB_SUCCESS) {
         ret = EIO;
         goto done;
@@ -1038,13 +1039,15 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
     msg->dn = dn;
 
     if (store) {
-        ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCLASS, LDB_FLAG_MOD_ADD, NULL);
+        ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCATEGORY, LDB_FLAG_MOD_ADD,
+                                NULL);
         if (ret != LDB_SUCCESS) {
             ret = sysdb_error_to_errno(ret);
             goto done;
         }
 
-        ret = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_SUBDOMAIN_CLASS);
+        ret = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY,
+                                      SYSDB_SUBDOMAIN_CLASS);
         if (ret != LDB_SUCCESS) {
             ret = sysdb_error_to_errno(ret);
             goto done;
diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
index 4ca8433f9..0c7412905 100644
--- a/src/db/sysdb_upgrade.c
+++ b/src/db/sysdb_upgrade.c
@@ -2236,6 +2236,271 @@ int sysdb_upgrade_17(struct sysdb_ctx *sysdb,
     }
     return ret;
 }
+
+static void add_object_category(struct ldb_context *ldb,
+                                struct upgrade_ctx *ctx)
+{
+    errno_t ret;
+    struct ldb_result *objects = NULL;
+    const char *attrs[] = { SYSDB_OBJECTCLASS, NULL };
+    struct ldb_dn *base_dn;
+    size_t c;
+    const char *class_name;
+    struct ldb_message *msg = NULL;
+
+    base_dn = ldb_dn_new(ctx, ldb, SYSDB_BASE);
+    if (base_dn == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed create base dn.\n");
+        return;
+    }
+
+    ret = ldb_search(ldb, ctx, &objects, base_dn,
+                     LDB_SCOPE_SUBTREE, attrs, SYSDB_OBJECTCLASS"=*");
+    talloc_free(base_dn);
+    if (ret != LDB_SUCCESS) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to search objects: %d\n", ret);
+        return;
+    }
+
+    if (objects == NULL || objects->count == 0) {
+        DEBUG(SSSDBG_TRACE_LIBS, "No objects found, nothing to do.");
+        return;
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL, "Found [%d] objects.\n", objects->count);
+    for (c = 0; c < objects->count; c++) {
+        DEBUG(SSSDBG_TRACE_ALL, "Updating [%s].\n",
+              ldb_dn_get_linearized(objects->msgs[c]->dn));
+
+        class_name = ldb_msg_find_attr_as_string(objects->msgs[c],
+                                                 SYSDB_OBJECTCLASS, NULL);
+        if (class_name == NULL || strcmp(class_name, SYSDB_USER_CLASS) == 0
+                || strcmp(class_name, SYSDB_GROUP_CLASS) == 0) {
+            continue;
+        }
+
+        talloc_free(msg);
+        msg = ldb_msg_new(ctx);
+        if (msg == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
+            continue;
+        }
+
+        msg->dn = objects->msgs[c]->dn;
+
+        ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCATEGORY, LDB_FLAG_MOD_ADD,
+                                NULL);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
+            continue;
+        }
+
+        ret = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY, class_name);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
+            continue;
+        }
+
+        DEBUG(SSSDBG_TRACE_ALL, "Adding [%s] to [%s].\n", class_name,
+              ldb_dn_get_linearized(objects->msgs[c]->dn));
+        ret = ldb_modify(ldb, msg);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Failed to add objectCategory to %s: %d.\n",
+                  ldb_dn_get_linearized(objects->msgs[c]->dn),
+                  sysdb_error_to_errno(ret));
+        }
+    }
+
+    talloc_free(msg);
+    talloc_free(objects);
+}
+
+int sysdb_upgrade_18(struct sysdb_ctx *sysdb, const char **ver)
+{
+    struct upgrade_ctx *ctx;
+    errno_t ret;
+    struct ldb_message *msg = NULL;
+
+    ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_19, &ctx);
+    if (ret) {
+        return ret;
+    }
+
+    add_object_category(sysdb->ldb, ctx);
+
+    /* Add missing indices */
+    msg = ldb_msg_new(ctx);
+    if (msg == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+    if (msg->dn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_GHOST);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_UPN);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_CANONICAL_UPN);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_UUID);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_USER_EMAIL);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_OBJECTCATEGORY);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_modify(sysdb->ldb, msg);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    /* Remove SYSDB_OBJECTCLASS from index */
+    talloc_free(msg);
+    msg = ldb_msg_new(ctx);
+    if (msg == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+    if (msg->dn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_DELETE, NULL);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, "@IDXATTR", "objectclass");
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_modify(sysdb->ldb, msg);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    /* Remove @IDXONE from index */
+    talloc_free(msg);
+    msg = ldb_msg_new(ctx);
+    if (msg == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+    if (msg->dn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_modify(sysdb->ldb, msg);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    /* conversion done, update version number */
+    ret = update_version(ctx);
+
+done:
+    ret = finish_upgrade(ret, &ctx, ver);
+    return ret;
+}
+
+int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver)
+{
+    struct upgrade_ctx *ctx;
+    errno_t ret;
+    struct ldb_message *msg = NULL;
+
+    ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_TS_VERSION_0_2, &ctx);
+    if (ret) {
+        return ret;
+    }
+
+    /* Remove @IDXONE from index */
+    talloc_free(msg);
+    msg = ldb_msg_new(ctx);
+    if (msg == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+    if (msg->dn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL);
+    if (ret != LDB_SUCCESS) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ldb_modify(sysdb->ldb, msg);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    /* conversion done, update version number */
+    ret = update_version(ctx);
+
+done:
+    ret = finish_upgrade(ret, &ctx, ver);
+    return ret;
+}
+
 /*
  * Example template for future upgrades.
  * Copy and change version numbers as appropriate.
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 9682613e9..cf80f8352 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -669,7 +669,8 @@ errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) return ENOMEM;
 
-    filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE);
+    filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_OBJECTCATEGORY,
+                                                 IPA_HBAC_RULE);
     if (filter == NULL) {
         ret = ENOMEM;
         goto done;
diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c
index 7912dbec9..dae66393a 100644
--- a/src/providers/ipa/ipa_hbac_rules.c
+++ b/src/providers/ipa/ipa_hbac_rules.c
@@ -266,6 +266,15 @@ ipa_hbac_rule_info_done(struct tevent_req *subreq)
 
         i = 0;
         while (state->rule_count < total_count) {
+            /* add indexed SYSDB_OBJECTCATEGORY to speed up searches */
+            ret = sysdb_attrs_add_string(rules[i], SYSDB_OBJECTCATEGORY,
+                                                   IPA_HBAC_RULE);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "Failed to add " SYSDB_OBJECTCATEGORY
+                                         " to HBAC rule, searches might not "
+                                         "use an index, ignoring.\n");
+            }
+
             target = &state->rules[state->rule_count];
             *target = talloc_steal(state->rules, rules[i]);
 
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index 90b947ed9..86b492d00 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -1436,7 +1436,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
     }
 
     ret = sysdb_search_entry(sbus_req, domain->sysdb, basedn,
-                             LDB_SCOPE_ONELEVEL, filter,
+                             LDB_SCOPE_SUBTREE, filter,
                              extra, &count, &user);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user [%d]: %s\n",
diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c
index eccfc2fe1..2f1971c22 100644
--- a/src/tests/cmocka/test_ipa_subdomains_server.c
+++ b/src/tests/cmocka/test_ipa_subdomains_server.c
@@ -387,75 +387,123 @@ static void test_ipa_server_create_trusts_none(struct tevent_req *req)
 
 }
 
-static void assert_trust_object(struct ipa_ad_server_ctx *trust,
-                                const char *dom_name,
-                                const char *dom_realm,
-                                const char *sid,
-                                const char *keytab,
-                                const char *authid,
-                                const char *sdap_realm)
+struct exp_trust_object {
+    const char *dom_name;
+    const char *dom_realm;
+    const char *sid;
+    const char *keytab;
+    const char *authid;
+    const char *sdap_realm;
+    bool found;
+};
+
+static void check_trust_object(struct ipa_ad_server_ctx *trust,
+                               struct exp_trust_object exp[])
 {
     const char *s;
+    size_t c;
 
     assert_non_null(trust);
     assert_non_null(trust->dom);
-    assert_string_equal(trust->dom->name, dom_name);
-    assert_string_equal(trust->dom->domain_id, sid);
-
-    s = dp_opt_get_string(trust->ad_id_ctx->ad_options->basic,
-                          AD_KRB5_REALM);
-    if (dom_realm != NULL) {
-        assert_non_null(s);
-        assert_string_equal(s, dom_realm);
-    } else {
-        assert_null(s);
-    }
 
-    s = dp_opt_get_string(trust->ad_id_ctx->ad_options->basic,
-                          AD_DOMAIN);
-    if (dom_name != NULL) {
-        assert_non_null(s);
-        assert_string_equal(s, dom_name);
-    } else {
-        assert_null(s);
-    }
+    for (c = 0; exp[c].dom_name != NULL; c++) {
 
-    /* the system keytab is always used with two-way trusts */
-    s = dp_opt_get_string(trust->ad_id_ctx->ad_options->id->basic,
-                          SDAP_KRB5_KEYTAB);
-    if (keytab != NULL) {
-        assert_non_null(s);
-        assert_string_equal(s, keytab);
-    } else {
-        assert_null(s);
-    }
+        if (strcmp(trust->dom->name, exp[c].dom_name) != 0) {
+            continue;
+        }
 
-    s = dp_opt_get_string(trust->ad_id_ctx->ad_options->id->basic,
-                          SDAP_SASL_REALM);
-    if (sdap_realm != NULL) {
-        assert_non_null(s);
-        assert_string_equal(s, sdap_realm);
-    } else {
-        assert_null(s);
-    }
+        if (strcmp(trust->dom->domain_id, exp[c].sid) != 0) {
+            continue;
+        }
 
-    s = dp_opt_get_string(trust->ad_id_ctx->ad_options->id->basic,
-                          SDAP_SASL_AUTHID);
-    if (authid != NULL) {
-        assert_non_null(s);
-        assert_string_equal(s, authid);
-    } else {
-        assert_null(s);
+        s = dp_opt_get_string(trust->ad_id_ctx->ad_options->basic,
+                              AD_KRB5_REALM);
+        if (exp[c].dom_realm != NULL) {
+            if (s == NULL || strcmp(s, exp[c].dom_realm) != 0) {
+                continue;
+            }
+        } else {
+            if (s != NULL) {
+                continue;
+            }
+        }
+
+        s = dp_opt_get_string(trust->ad_id_ctx->ad_options->basic,
+                              AD_DOMAIN);
+        if (exp[c].dom_name != NULL) {
+            if (s == NULL || strcmp(s, exp[c].dom_name) != 0) {
+                continue;
+            }
+        } else {
+            if (s != NULL) {
+                continue;
+            }
+        }
+
+        /* the system keytab is always used with two-way trusts */
+        s = dp_opt_get_string(trust->ad_id_ctx->ad_options->id->basic,
+                              SDAP_KRB5_KEYTAB);
+        if (exp[c].keytab != NULL) {
+            if (s == NULL || strcmp(s, exp[c].keytab) != 0) {
+                continue;
+            }
+        } else {
+            if (s != NULL) {
+                continue;
+            }
+        }
+
+        s = dp_opt_get_string(trust->ad_id_ctx->ad_options->id->basic,
+                              SDAP_SASL_REALM);
+        if (exp[c].sdap_realm != NULL) {
+            if (s == NULL || strcmp(s, exp[c].sdap_realm) != 0) {
+                continue;
+            }
+        } else {
+            if (s != NULL) {
+                continue;
+            }
+        }
+
+        s = dp_opt_get_string(trust->ad_id_ctx->ad_options->id->basic,
+                              SDAP_SASL_AUTHID);
+        if (exp[c].authid != NULL) {
+            if (s == NULL || strcmp(s, exp[c].authid) != 0 ) {
+                continue;
+            }
+        } else {
+            if (s != NULL) {
+                continue;
+            }
+        }
+
+        assert_false(exp[c].found);
+        exp[c].found = true;
     }
 }
 
 static void test_ipa_server_create_trusts_twoway(struct tevent_req *req)
 {
+    size_t c;
     struct trust_test_ctx *test_ctx = \
         tevent_req_callback_data(req, struct trust_test_ctx);
     errno_t ret;
     struct sss_domain_info *child_dom;
 
+    struct exp_trust_object exp[] = {
+        { SUBDOM_NAME, DOM_REALM, SUBDOM_SID, NULL, TEST_AUTHID, DOM_REALM,
+          false},
+        { CHILD_NAME, DOM_REALM, CHILD_SID, NULL, TEST_AUTHID, DOM_REALM,
+          false},
+        { NULL, NULL, NULL, NULL, NULL, NULL, false},
+    };
+
+    struct exp_trust_object exp_subdom[] = {
+        { SUBDOM_NAME, DOM_REALM, SUBDOM_SID, NULL, TEST_AUTHID, DOM_REALM,
+          false},
+        { NULL, NULL, NULL, NULL, NULL, NULL, false},
+    };
+
     ret = ipa_server_create_trusts_recv(req);
     talloc_zfree(req);
     assert_int_equal(ret, EOK);
@@ -464,26 +512,17 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req)
     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts);
 
     /* Two-way trusts should use the system realm */
-    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts,
-                        CHILD_NAME,
-                        DOM_REALM,
-                        CHILD_SID,
-                        NULL,
-                        TEST_AUTHID,
-                        DOM_REALM);
+    check_trust_object(test_ctx->ipa_ctx->server_mode->trusts, exp);
 
     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
 
-    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next,
-                        SUBDOM_NAME,
-                        DOM_REALM,
-                        SUBDOM_SID,
-                        NULL,
-                        TEST_AUTHID,
-                        DOM_REALM);
+    check_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next, exp);
 
     /* No more trust objects */
     assert_null(test_ctx->ipa_ctx->server_mode->trusts->next->next);
+    for (c = 0; exp[c].dom_name != NULL; c++) {
+        assert_true(exp[c].found);
+    }
 
     ret = sysdb_subdomain_delete(test_ctx->tctx->sysdb, CHILD_NAME);
     assert_int_equal(ret, EOK);
@@ -493,13 +532,8 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req)
 
     ipa_ad_subdom_remove(test_ctx->be_ctx, test_ctx->ipa_ctx, child_dom);
 
-    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts,
-                        SUBDOM_NAME,
-                        DOM_REALM,
-                        SUBDOM_SID,
-                        NULL,
-                        TEST_AUTHID,
-                        DOM_REALM);
+    check_trust_object(test_ctx->ipa_ctx->server_mode->trusts, exp_subdom);
+    assert_true(exp[0].found);
     assert_null(test_ctx->ipa_ctx->server_mode->trusts->next);
 
     test_ev_done(test_ctx->tctx, EOK);
@@ -518,12 +552,20 @@ ipa_server_init_done(struct tevent_context *ev,
 
 static void test_ipa_server_trust_init(void **state)
 {
+    size_t c;
     struct trust_test_ctx *test_ctx =
         talloc_get_type(*state, struct trust_test_ctx);
     errno_t ret;
     struct tevent_timer *timeout_handler;
     struct timeval tv;
 
+    struct exp_trust_object exp[] = {
+        { SUBDOM_NAME, DOM_REALM, SUBDOM_SID, NULL, TEST_AUTHID, DOM_REALM,
+          false},
+        { CHILD_NAME, DOM_REALM, CHILD_SID, NULL, TEST_AUTHID, DOM_REALM,
+          false},
+        { NULL, NULL, NULL, NULL, NULL, NULL, false},
+    };
     add_test_2way_subdomains(test_ctx);
 
     ret = ipa_ad_subdom_init(test_ctx->be_ctx, test_ctx->ipa_ctx);
@@ -543,26 +585,17 @@ static void test_ipa_server_trust_init(void **state)
     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts);
 
     /* Two-way trusts should use the system realm */
-    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts,
-                        CHILD_NAME,
-                        DOM_REALM,
-                        CHILD_SID,
-                        NULL,
-                        TEST_AUTHID,
-                        DOM_REALM);
+    check_trust_object(test_ctx->ipa_ctx->server_mode->trusts, exp);
 
     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
 
-    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next,
-                        SUBDOM_NAME,
-                        DOM_REALM,
-                        SUBDOM_SID,
-                        NULL,
-                        TEST_AUTHID,
-                        DOM_REALM);
+    check_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next, exp);
 
     /* No more trust objects */
     assert_null(test_ctx->ipa_ctx->server_mode->trusts->next->next);
+    for (c = 0; exp[c].dom_name != NULL; c++) {
+        assert_true(exp[c].found);
+    }
 }
 
 struct dir_test_ctx {
@@ -705,10 +738,19 @@ static void test_ipa_server_create_oneway(void **state)
 
 static void test_ipa_server_create_trusts_oneway(struct tevent_req *req)
 {
+    size_t c;
     struct trust_test_ctx *test_ctx = \
         tevent_req_callback_data(req, struct trust_test_ctx);
     errno_t ret;
 
+    struct exp_trust_object exp[] = {
+        { SUBDOM_NAME, SUBDOM_REALM, SUBDOM_SID, ONEWAY_KEYTAB, ONEWAY_PRINC,
+          SUBDOM_REALM, false},
+        { CHILD_NAME, CHILD_REALM, CHILD_SID, ONEWAY_KEYTAB, ONEWAY_PRINC,
+          SUBDOM_REALM, false},
+        { NULL, NULL, NULL, NULL, NULL, NULL, false},
+    };
+
     ret = ipa_server_create_trusts_recv(req);
     talloc_zfree(req);
     assert_int_equal(ret, EOK);
@@ -721,27 +763,18 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req)
     /* Trust object should be around now */
     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts);
 
-    assert_trust_object(
-        test_ctx->ipa_ctx->server_mode->trusts,
-        CHILD_NAME,    /* AD domain name */
-        CHILD_REALM,   /* AD realm can be child if SDAP realm is parent's */
-        CHILD_SID,
-        ONEWAY_KEYTAB,    /* Keytab shared with parent AD dom */
-        ONEWAY_PRINC,     /* Principal shared with parent AD dom */
-        SUBDOM_REALM); /* SDAP realm must be AD root domain */
+    check_trust_object(test_ctx->ipa_ctx->server_mode->trusts, exp);
+
 
     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
 
     /* Here all properties point to the AD domain */
-    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next,
-                        SUBDOM_NAME,
-                        SUBDOM_REALM,
-                        SUBDOM_SID,
-                        ONEWAY_KEYTAB,
-                        ONEWAY_PRINC,
-                        SUBDOM_REALM);
+    check_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next, exp);
 
     assert_null(test_ctx->ipa_ctx->server_mode->trusts->next->next);
+    for (c = 0; exp[c].dom_name != NULL; c++) {
+        assert_true(exp[c].found);
+    }
     test_ev_done(test_ctx->tctx, EOK);
 }
 
diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
index 0378254b4..867a44e59 100644
--- a/src/tests/cmocka/test_sysdb_views.c
+++ b/src/tests/cmocka/test_sysdb_views.c
@@ -612,37 +612,82 @@ static int test_enum_users_setup(void **state)
     return 0;
 }
 
-static void assert_user_attrs(struct ldb_message *msg,
-                              struct sss_domain_info *dom,
-                              const char *shortname,
-                              bool has_views)
+struct exp_user {
+    const char *name;
+    bool found;
+};
+
+static void check_user_attrs(struct ldb_message *msg,
+                             struct sss_domain_info *dom,
+                             struct exp_user exp[],
+                             bool has_views)
 {
     const char *str;
-    char *fqname;
-
-    fqname = sss_create_internal_fqname(msg, shortname, dom->name);
-    assert_non_null(fqname);
+    char *fqname = NULL;
+    char *override = NULL;
+    size_t c;
 
-    str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-    assert_string_equal(str, fqname);
-    str = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL);
-    assert_string_equal(str, fqname);
+    for (c = 0; exp[c].name != NULL; c++) {
+        talloc_free(fqname);
+        fqname = sss_create_internal_fqname(msg, exp[c].name, dom->name);
+        if (fqname == NULL) {
+            continue;
+        }
 
-    str = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_GECOS, NULL);
-    if (has_views) {
-        char *override;
+        str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+        if (strcmp(str, fqname) != 0) {
+            continue;
+        }
+        str = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL);
+        if (strcmp(str, fqname) != 0) {
+            continue;
+        }
 
-        assert_non_null(str);
-        override = talloc_asprintf(msg, "%s_GECOS_OVERRIDE", fqname);
-        assert_non_null(override);
+        str = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_GECOS, NULL);
+        if (has_views) {
+
+            if (str == NULL) {
+                continue;
+            }
+
+            talloc_free(override);
+            override = talloc_asprintf(msg, "%s_GECOS_OVERRIDE", fqname);
+            if (override == NULL) {
+                continue;
+            }
+
+            if (strcmp(str, override) != 0) {
+                continue;
+            }
+        } else {
+            if (str != NULL) {
+                continue;
+            }
+        }
 
-        assert_string_equal(str, override);
-        talloc_free(override);
-    } else {
-        assert_null(str);
+        assert_false(exp[c].found);
+        exp[c].found = true;
+        break;
     }
 
     talloc_free(fqname);
+    talloc_free(override);
+
+    return;
+}
+
+static void assert_user_attrs(struct ldb_message *msg,
+                              struct sss_domain_info *dom,
+                              const char *shortname,
+                              bool has_views)
+{
+    struct exp_user exp[] = {
+        { shortname, false},
+        { NULL, false}
+    };
+
+    check_user_attrs(msg, dom, exp, has_views);
+    assert_true(exp[0].found);
 }
 
 static int test_enum_users_teardown(void **state)
@@ -657,12 +702,24 @@ static int test_enum_users_teardown(void **state)
 static void check_enumpwent(int ret, struct sss_domain_info *dom,
                             struct ldb_result *res, bool views)
 {
+    size_t c;
+    struct exp_user exp[] = {
+        { "alice", false},
+        { "barney", false},
+        { "bob", false},
+        { NULL, false}
+    };
+
     assert_int_equal(ret, EOK);
     assert_int_equal(res->count, N_ELEMENTS(users)-1);
 
-    assert_user_attrs(res->msgs[0], dom, "barney", views);
-    assert_user_attrs(res->msgs[1], dom, "alice", views);
-    assert_user_attrs(res->msgs[2], dom, "bob", views);
+    for (c = 0; c < res->count; c++) {
+        check_user_attrs(res->msgs[c], dom, exp, views);
+    }
+
+    for (c = 0; exp[c].name != NULL; c++) {
+        assert_true(exp[c].found);
+    }
 }
 
 static void test_sysdb_enumpwent(void **state)
@@ -869,39 +926,86 @@ static int test_enum_groups_teardown(void **state)
     return test_sysdb_teardown(state);
 }
 
-static void assert_group_attrs(struct ldb_message *msg,
-                               struct sss_domain_info *dom,
-                               const char *shortname,
-                               unsigned expected_override_gid)
+struct exp_group {
+    const char *name;
+    unsigned gid;
+    bool found;
+};
+
+static void check_group_attrs(struct ldb_message *msg,
+                              struct sss_domain_info *dom,
+                              struct exp_group exp[])
 {
     const char *str;
     unsigned gid;
-    char *fqname;
+    char *fqname = NULL;
+    size_t c;
 
-    fqname = sss_create_internal_fqname(msg, shortname, dom->name);
-    assert_non_null(fqname);
+    for (c = 0; exp[c].name != NULL; c++) {
+        talloc_free(fqname);
+        fqname = sss_create_internal_fqname(msg, exp[c].name, dom->name);
+        if (fqname == NULL) {
+            continue;
+        }
+
+        str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+        if (strcmp(str, fqname) != 0) {
+            continue;
+        }
 
-    str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-    assert_string_equal(str, fqname);
+        if (exp[c].gid) {
+            gid = ldb_msg_find_attr_as_uint64(msg,
+                                              OVERRIDE_PREFIX SYSDB_GIDNUM, 0);
+            if (gid != exp[c].gid) {
+                continue;
+            }
+        }
 
-    if (expected_override_gid) {
-        gid = ldb_msg_find_attr_as_uint64(msg,
-                                          OVERRIDE_PREFIX SYSDB_GIDNUM, 0);
-        assert_int_equal(gid, expected_override_gid);
+        assert_false(exp[c].found);
+        exp[c].found = true;
+        break;
     }
+
+    talloc_free(fqname);
+}
+
+static void assert_group_attrs(struct ldb_message *msg,
+                               struct sss_domain_info *dom,
+                               const char *shortname,
+                               unsigned expected_override_gid)
+{
+    struct exp_group exp[] = {
+        { shortname, expected_override_gid, false},
+        { NULL, 0, false}
+    };
+
+    check_group_attrs(msg, dom, exp);
+    assert_true(exp[0].found);
 }
 
+
 static void check_enumgrent(int ret, struct sss_domain_info *dom,
                             struct ldb_result *res, bool views)
 {
+    size_t c;
+    size_t d;
+    struct exp_group exp[] = {
+        { "one",   views ? TEST_GID_OVERRIDE_BASE     : 0, false},
+        { "two",   views ? TEST_GID_OVERRIDE_BASE + 1 : 0, false},
+        { "three", views ? TEST_GID_OVERRIDE_BASE + 2 : 0, false},
+        { NULL, 0, false}
+    };
+
     assert_int_equal(ret, EOK);
     assert_int_equal(res->count, N_ELEMENTS(groups)-1);
-    assert_group_attrs(res->msgs[0], dom, "three",
-                       views ? TEST_GID_OVERRIDE_BASE + 2 : 0);
-    assert_group_attrs(res->msgs[1], dom, "one",
-                       views ? TEST_GID_OVERRIDE_BASE : 0);
-    assert_group_attrs(res->msgs[2], dom, "two",
-                       views ? TEST_GID_OVERRIDE_BASE + 1 : 0);
+
+    for (c = 0; c < res->count; c++) {
+        check_group_attrs(res->msgs[c], dom, exp);
+    }
+
+    for (d = 0; exp[d].name != NULL; d++) {
+        assert_true(exp[d].found);
+    }
 }
 
 static void test_sysdb_enumgrent(void **state)
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index c186ed2fb..e6cf4f5fd 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -2219,7 +2219,23 @@ START_TEST (test_sysdb_search_all_users)
     struct test_data *data;
     int ret;
     int i;
-    char *uid_str;
+    struct exp {
+        const char *uid_str;
+        bool found;
+    } exp[] = {
+        {"27010", false},
+        {"27011", false},
+        {"27012", false},
+        {"27013", false},
+        {"27014", false},
+        {"27015", false},
+        {"27016", false},
+        {"27017", false},
+        {"27018", false},
+        {"27019", false},
+        {NULL , false}
+    };
+    size_t c;
 
     /* Setup */
     ret = setup_sysdb_tests(&test_ctx);
@@ -2253,14 +2269,22 @@ START_TEST (test_sysdb_search_all_users)
                     "wrong number of values, found [%d] expected [1]",
                     data->msgs[i]->elements[0].num_values);
 
-        uid_str = talloc_asprintf(data, "%d", 27010 + i);
-        fail_unless(uid_str != NULL, "talloc_asprintf failed.");
-        fail_unless(strncmp(uid_str,
-                            (char *) data->msgs[i]->elements[0].values[0].data,
-                            data->msgs[i]->elements[0].values[0].length)  == 0,
-                            "wrong value, found [%.*s] expected [%s]",
+        for (c = 0; exp[c].uid_str != NULL; c++) {
+            if (strncmp(exp[c].uid_str,
+                        (char *) data->msgs[i]->elements[0].values[0].data,
+                        data->msgs[i]->elements[0].values[0].length)  == 0) {
+                exp[c].found = true;
+                break;
+            }
+        }
+        fail_unless(exp[c].uid_str != NULL,
+                            "wrong value, found [%.*s]",
                             data->msgs[i]->elements[0].values[0].length,
-                            data->msgs[i]->elements[0].values[0].data, uid_str);
+                            data->msgs[i]->elements[0].values[0].data);
+    }
+
+    for (c = 0; exp[c].uid_str != NULL; c++) {
+        fail_unless(exp[c].found, "missing uid [%s]", exp[c].uid_str);
     }
 
     talloc_free(test_ctx);
@@ -6279,8 +6303,9 @@ START_TEST(test_autofs_get_duplicate_keys)
     autofskey = talloc_asprintf(test_ctx, "testkey");
     fail_if(autofskey == NULL, "Out of memory\n");
 
-    filter = talloc_asprintf(test_ctx, "(&(objectclass=%s)(%s=%s))",
-                             SYSDB_AUTOFS_ENTRY_OC, SYSDB_AUTOFS_ENTRY_KEY, autofskey);
+    filter = talloc_asprintf(test_ctx, "(&(%s=%s)(%s=%s))",
+                             SYSDB_OBJECTCATEGORY, SYSDB_AUTOFS_ENTRY_OC,
+                             SYSDB_AUTOFS_ENTRY_KEY, autofskey);
     fail_if(filter == NULL, "Out of memory\n");
 
     dn = ldb_dn_new_fmt(test_ctx, test_ctx->sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE,
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org

Reply via email to