[SSSD] [PATCH] Use fake users for RFC2307bis nested group processing

Jakub Hrozek jhrozek at redhat.com
Thu Sep 29 19:47:27 UTC 2011


https://bugzilla.redhat.com/show_bug.cgi?id=742052

Attached are two patches that should be commited to 1.5. They are
already present in 1.6 and later branches.

Instead of downloading all user attributes and saving complete user data
during nested RFC2307bis group processing, download only the necessary
attributes (objectclass and name) and save the users as "fake".

This lowers the network traffic needed to download all the attributes, reduces
the cache size and provides a minor speedup.

The speedup really is minor compared to what dereference brings because
the RFC2307bis processing code still needs to perform at least N LDAP
lookups for N group members that are not cached.
-------------- next part --------------
From 77bc3d93ddd41edee6046508884d7e95553ed5b7 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 7 Mar 2011 09:59:13 +0100
Subject: [PATCH 1/2] Change sysdb_add_fake_user to add OriginalDN

RFC2307bis code relies heavily on originalDN, so the fake users need to
have an option to store it, too.
---
 src/db/sysdb.h                           |    3 ++-
 src/db/sysdb_ops.c                       |    9 ++++++++-
 src/providers/ldap/sdap_async_accounts.c |    2 +-
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index c133072..190e812 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -495,7 +495,8 @@ int sysdb_add_user(TALLOC_CTX *mem_ctx,
 
 int sysdb_add_fake_user(struct sysdb_ctx *ctx,
                         struct sss_domain_info *domain,
-                        const char *name);
+                        const char *name,
+                        const char *original_dn);
 
 /* Add group (only basic attrs and w/o checks) */
 int sysdb_add_basic_group(TALLOC_CTX *mem_ctx,
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index d6260b9..1fb389d 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -934,7 +934,8 @@ done:
 
 int sysdb_add_fake_user(struct sysdb_ctx *ctx,
                         struct sss_domain_info *domain,
-                        const char *name)
+                        const char *name,
+                        const char *original_dn)
 {
     TALLOC_CTX *tmpctx;
     struct ldb_message *msg;
@@ -983,6 +984,12 @@ int sysdb_add_fake_user(struct sysdb_ctx *ctx,
                     (unsigned long) now-1);
     if (ret) goto done;
 
+    if (original_dn) {
+        ret = add_string(msg, LDB_FLAG_MOD_ADD,
+                         SYSDB_ORIG_DN, original_dn);
+        if (ret) goto done;
+    }
+
     ret = ldb_add(ctx->ldb, msg);
     ret = sysdb_error_to_errno(ret);
 
diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 9e059bf..3387e3e 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -1406,7 +1406,7 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state,
         *in_transaction = true;
     }
 
-    ret = sysdb_add_fake_user(state->sysdb, state->dom, username);
+    ret = sysdb_add_fake_user(state->sysdb, state->dom, username, NULL);
     if (ret != EOK) {
         DEBUG(1, ("Cannot store fake user entry: [%d]: %s\n",
                   ret, strerror(ret)));
-- 
1.7.6.2

-------------- next part --------------
From c18bd9de80daf87e33d60c6c44d83b418cfe37b3 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Fri, 29 Apr 2011 13:24:42 +0200
Subject: [PATCH 2/2] Use fake users during RFC2307bis nested group processing

Instead of downloading complete user data which is potentionally very
slow, only download the necessary minimum information and store the
users as dummy entries.
---
 src/providers/ldap/sdap_async_accounts.c |  178 +++++++++++++++++++++++++++--
 1 files changed, 165 insertions(+), 13 deletions(-)

diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 3387e3e..d2913e2 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -1817,6 +1817,12 @@ int sdap_get_groups_recv(struct tevent_req *req,
     return EOK;
 }
 
+static errno_t sdap_nested_group_populate_users(struct sysdb_ctx *sysdb,
+                                                struct sss_domain_info *dom,
+                                                struct sdap_options *opts,
+                                                struct sysdb_attrs **users,
+                                                int num_users);
+
 static void sdap_nested_done(struct tevent_req *subreq)
 {
     errno_t ret;
@@ -1862,9 +1868,8 @@ static void sdap_nested_done(struct tevent_req *subreq)
     /* Save all of the users first so that they are in
      * place for the groups to add them.
      */
-    ret = sdap_save_users(state, state->sysdb, state->attrs,
-                          state->dom, state->opts,
-                          users, count, &state->higher_usn);
+    ret = sdap_nested_group_populate_users(state->sysdb, state->dom,
+                                           state->opts, users, count);
     if (ret != EOK) {
         tevent_req_error(req, ret);
         return;
@@ -1900,6 +1905,138 @@ static void sdap_nested_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
+static errno_t sdap_nested_group_populate_users(struct sysdb_ctx *sysdb,
+                                                struct sss_domain_info *dom,
+                                                struct sdap_options *opts,
+                                                struct sysdb_attrs **users,
+                                                int num_users)
+{
+    int i;
+    errno_t ret, sret;
+    struct ldb_message_element *el;
+    const char *username;
+    char *clean_orig_dn;
+    const char *original_dn;
+
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_message **msgs;
+    char *filter;
+    const char *sysdb_name;
+    struct sysdb_attrs *attrs;
+    static const char *search_attrs[] = { SYSDB_NAME, NULL };
+    size_t count;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    if (num_users == 0) {
+        /* Nothing to do if there are no users */
+        return EOK;
+    }
+
+    ret = sysdb_transaction_start(sysdb);
+    if (ret) {
+        DEBUG(1, ("Failed to start transaction!\n"));
+        goto done;
+    }
+
+    for (i = 0; i < num_users; i++) {
+        ret = sysdb_attrs_primary_name(sysdb, users[i],
+                                    opts->user_map[SDAP_AT_USER_NAME].name,
+                                    &username);
+        if (ret != EOK) {
+            DEBUG(1, ("User entry %d has no name attribute\n", i));
+            goto done;
+        }
+
+        ret = sysdb_attrs_get_el(users[i], SYSDB_ORIG_DN, &el);
+        if (el->num_values == 0) {
+            ret = EINVAL;
+        }
+        if (ret != EOK) {
+            DEBUG(1, ("User entry %s has no originalDN attribute\n", i));
+            goto done;
+        }
+        original_dn = (const char *) el->values[0].data;
+
+        ret = sss_filter_sanitize(tmp_ctx, original_dn,
+                                  &clean_orig_dn);
+        if (ret != EOK) {
+            DEBUG(1, ("Cannot sanitize originalDN\n", i));
+            goto done;
+        }
+
+        /* Check for the specified origDN in the sysdb */
+        filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
+                                 SYSDB_ORIG_DN,
+                                 clean_orig_dn);
+        if (!filter) {
+            ret = ENOMEM;
+            goto done;
+        }
+        ret = sysdb_search_users(tmp_ctx, sysdb, dom, filter,
+                                 search_attrs, &count, &msgs);
+        talloc_zfree(filter);
+        talloc_zfree(clean_orig_dn);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(1, ("Error checking cache for user entry\n"));
+            goto done;
+        }
+        if (ret == EOK) {
+            /* The entry is cached but expired. Update the username
+             * if needed. */
+            if (count != 1) {
+                DEBUG(1, ("More than one entry with this origDN? Skipping\n"));
+                continue;
+            }
+
+            sysdb_name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
+            if (strcmp(sysdb_name, username) == 0) {
+                /* Username is correct, continue */
+                continue;
+            }
+
+            attrs = sysdb_new_attrs(tmp_ctx);
+            if (!attrs) {
+                ret = ENOMEM;
+                goto done;
+            }
+
+            ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, username);
+            if (ret) goto done;
+            ret = sysdb_set_user_attr(tmp_ctx, sysdb,
+                                      dom, sysdb_name, attrs, SYSDB_MOD_REP);
+            if (ret != EOK) goto done;
+        }
+
+        /* If the entry does not exist add a fake user record */
+        ret = sysdb_add_fake_user(sysdb, dom, username, original_dn);
+        if (ret != EOK) {
+            DEBUG(1, ("Cannot store fake user entry, ignoring: [%d]: %s\n",
+                      ret, strerror(ret)));
+            continue;
+        } else {
+            DEBUG(9, ("Added incomplete user %s!\n", username));
+        }
+    }
+
+    ret = sysdb_transaction_commit(sysdb);
+    if (ret) {
+        DEBUG(1, ("Failed to commit transaction!\n"));
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    talloc_zfree(tmp_ctx);
+    if (ret != EOK) {
+        sret = sysdb_transaction_cancel(sysdb);
+        if (sret != EOK) {
+            DEBUG(2, ("Could not cancel transaction\n"));
+        }
+    }
+    return ret;
+}
 
 /* ==Save-fake-group-list=====================================*/
 static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
@@ -3268,7 +3405,6 @@ immediate:
     return req;
 }
 
-
 static void sdap_nested_group_process_ldap_user(struct tevent_req *subreq);
 static void sdap_nested_group_process_user(struct tevent_req *subreq);
 static errno_t sdap_nested_group_lookup_user(struct tevent_req *req,
@@ -3285,10 +3421,12 @@ static errno_t sdap_nested_group_process_step(struct tevent_req *req)
     size_t count;
     struct ldb_message **msgs;
     uint64_t expiration;
+    uint64_t create_time;
     bool has_key = false;
     hash_key_t key;
     uint8_t *data;
     time_t now = time(NULL);
+    uid_t user_uid;
 
     while (true) {
         /* Continue to loop through until all entries have been
@@ -3419,9 +3557,22 @@ static errno_t sdap_nested_group_process_step(struct tevent_req *req)
             continue;
         }
 
-        expiration = ldb_msg_find_attr_as_uint64(msgs[0],
-                                                 SYSDB_CACHE_EXPIRE,
-                                                 0);
+        user_uid = ldb_msg_find_attr_as_uint64(msgs[0], SYSDB_UIDNUM, 0);
+        if (!user_uid) {
+            /* Refresh the fake user if he was created before cache_timeout */
+            create_time = ldb_msg_find_attr_as_uint64(msgs[0],
+                                                    SYSDB_CREATE_TIME,
+                                                    0);
+            expiration = create_time +
+                            dp_opt_get_int(state->opts->basic,
+                                        SDAP_ENTRY_CACHE_TIMEOUT);
+        } else {
+            /* Regular user, check if we need a refresh */
+            expiration = ldb_msg_find_attr_as_uint64(msgs[0],
+                                                    SYSDB_CACHE_EXPIRE,
+                                                    0);
+        }
+
         if (expiration && expiration > now) {
             DEBUG(6, ("Cached values are still valid. Skipping\n"));
             state->member_index++;
@@ -3445,18 +3596,19 @@ error:
 static errno_t sdap_nested_group_lookup_user(struct tevent_req *req,
                                              tevent_req_fn fn)
 {
-    errno_t ret;
     const char **sdap_attrs;
     char *filter;
     struct tevent_req *subreq;
     struct sdap_nested_group_ctx *state =
             tevent_req_data(req, struct sdap_nested_group_ctx);
 
-    ret = build_attrs_from_map(state, state->opts->user_map,
-                               SDAP_OPTS_USER, &sdap_attrs);
-    if (ret != EOK) {
-        return ret;
-    }
+
+    /* Only pull down username and originalDN */
+    sdap_attrs = talloc_array(state, const char *, 3);
+    if (!sdap_attrs) return ENOMEM;
+    sdap_attrs[0] = "objectClass";
+    sdap_attrs[1] = state->opts->user_map[SDAP_AT_USER_NAME].name;
+    sdap_attrs[2] = NULL;
 
     filter = talloc_asprintf(
             sdap_attrs, "(objectclass=%s)",
-- 
1.7.6.2



More information about the sssd-devel mailing list