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

Hi,
these two patches add the same functionality we have in the 1.2 branch
into master. I think they read much better b/c of the synchronous sysdb
interface. Both must be applied on top of Ralf's patches in the
"Behaviour of getgrnam/getgrgid" thread.

        Jakub
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAkyy+pAACgkQHsardTLnvCXwFACfYqJBydSwz/K7PD1hBu7Nh/OM
aokAn0qlwTlezT4DLTFqp/e8fkkIRYUu
=rqOw
-----END PGP SIGNATURE-----
From 484ecb2b221225544303eee82f05362ef0f64da4 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Wed, 29 Sep 2010 22:15:39 +0200
Subject: [PATCH 1/2] sysdb interface for adding fake users

---
 src/db/sysdb.h                       |    4 ++
 src/db/sysdb_ops.c                   |   61 ++++++++++++++++++++++++++++++++++
 src/providers/ldap/ldap_id_cleanup.c |    7 ++--
 src/responder/nss/nsssrv_cmd.c       |    2 +-
 4 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index aaea1ea..0c8a7c6 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -402,6 +402,10 @@ int sysdb_add_user(TALLOC_CTX *mem_ctx,
                    struct sysdb_attrs *attrs,
                    int cache_timeout);
 
+int sysdb_add_fake_user(struct sysdb_ctx *ctx,
+                        struct sss_domain_info *domain,
+                        const char *name);
+
 /* Add group (only basic attrs and w/o checks) */
 int sysdb_add_basic_group(TALLOC_CTX *mem_ctx,
                           struct sysdb_ctx *ctx,
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index b3be055..a625d20 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -844,6 +844,67 @@ done:
     return ret;
 }
 
+int sysdb_add_fake_user(struct sysdb_ctx *ctx,
+                        struct sss_domain_info *domain,
+                        const char *name)
+{
+    TALLOC_CTX *tmpctx;
+    struct ldb_message *msg;
+    time_t now;
+    int ret;
+
+    tmpctx = talloc_new(NULL);
+    if (!tmpctx) {
+        return ENOMEM;
+    }
+
+    msg = ldb_msg_new(tmpctx);
+    if (!msg) {
+        ERROR_OUT(ret, ENOMEM, done);
+    }
+
+    /* user dn */
+    msg->dn = sysdb_user_dn(ctx, msg, domain->name, name);
+    if (!msg->dn) {
+        ERROR_OUT(ret, ENOMEM, done);
+    }
+
+    ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS);
+    if (ret) goto done;
+
+    ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name);
+    if (ret) goto done;
+
+    now = time(NULL);
+
+    ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,
+                    (unsigned long) now);
+    if (ret) goto done;
+
+    /* set last login so that the fake entry does not get cleaned up
+     * immediately */
+    ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_LAST_LOGIN,
+                    (unsigned long) now);
+    if (ret) return ret;
+
+    ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_LAST_UPDATE,
+                    (unsigned long) now);
+    if (ret) goto done;
+
+    ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CACHE_EXPIRE,
+                    (unsigned long) now-1);
+    if (ret) goto done;
+
+    ret = ldb_add(ctx->ldb, msg);
+    ret = sysdb_error_to_errno(ret);
+
+done:
+    if (ret != EOK) {
+        DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
+    }
+    talloc_zfree(tmpctx);
+    return ret;
+}
 
 /* =Add-Basic-Group-NO-CHECKS============================================= */
 
diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index 60bc171..6357708 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -306,7 +306,8 @@ static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx)
             ret = cleanup_users_logged_in(uid_table, msgs[i]);
             if (ret == EOK) {
                 /* If the user is logged in, proceed to the next one */
-                DEBUG(5, ("User %s is still logged in, keeping data\n", name));
+                DEBUG(5, ("User %s is still logged in or a dummy entry, "
+                          "keeping data\n", name));
                 continue;
             } else if (ret != ENOENT) {
                 goto done;
@@ -337,9 +338,9 @@ static int cleanup_users_logged_in(hash_table_t *table,
     uid = ldb_msg_find_attr_as_uint64(msg,
                                       SYSDB_UIDNUM, 0);
     if (!uid) {
-        DEBUG(2, ("Entry %s has no UID Attribute ?!?\n",
+        DEBUG(2, ("Entry %s has no UID Attribute, fake user perhaps?\n",
                   ldb_dn_get_linearized(msg->dn)));
-        return EFAULT;
+        return ENOENT;
     }
 
     key.type = HASH_KEY_ULONG;
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index b093da0..078a52f 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -274,7 +274,7 @@ static int fill_pwent(struct sss_packet *packet,
         gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
 
         if (!name || !uid || !gid) {
-            DEBUG(1, ("Incomplete user object for %s[%llu]! Skipping\n",
+            DEBUG(2, ("Incomplete or fake user object for %s[%llu]! Skipping\n",
                       name?name:"<NULL>", (unsigned long long int)uid));
             continue;
         }
-- 
1.7.2.3

From 07a4c76c40d2df2afd05cf7719cc802eab508787 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Sat, 2 Oct 2010 12:43:07 +0200
Subject: [PATCH 2/2] Save dummy member users during RFC2307 getgr{nam,uid}

---
 src/providers/ldap/sdap_async_accounts.c |  361 +++++++++++++++++++++++-------
 1 files changed, 279 insertions(+), 82 deletions(-)

diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 1ff3e9e..8845cce 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -931,6 +931,7 @@ struct sdap_process_group_state {
     struct sysdb_attrs **new_members;
     struct ldb_message_element* sysdb_dns;
     char **queued_members;
+    int queue_len;
     const char **attrs;
     const char *filter;
     size_t member_idx;
@@ -942,6 +943,12 @@ struct sdap_process_group_state {
 #define GROUPMEMBER_REQ_PARALLEL 50
 static void sdap_process_group_members(struct tevent_req *subreq);
 
+static int sdap_process_group_members_2307bis(struct tevent_req *req,
+                                   struct sdap_process_group_state *state,
+                                   struct ldb_message_element *memberel);
+static int sdap_process_group_members_2307(struct sdap_process_group_state *state,
+                                   struct ldb_message_element *memberel);
+
 struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,
                                            struct tevent_context *ev,
                                            struct sss_domain_info *dom,
@@ -955,9 +962,7 @@ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,
     struct tevent_req *req = NULL;
     const char **attrs;
     char* filter;
-    int queue_len;
     int ret;
-    int i;
 
     req = tevent_req_create(memctx, &grp_state,
                             struct sdap_process_group_state);
@@ -987,6 +992,7 @@ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,
     grp_state->member_idx = 0;
     grp_state->queue_idx = 0;
     grp_state->queued_members = NULL;
+    grp_state->queue_len = 0;
     grp_state->filter = filter;
     grp_state->attrs = attrs;
 
@@ -1016,112 +1022,303 @@ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,
         return NULL;
     }
     grp_state->sysdb_dns->num_values = 0;
-    queue_len = 0;
 
-    /*
-     * For each member check if it is already present in sysdb,
-     * if it isn't read it from LDAP
-     */
-    for (i = 0; i < el->num_values; i++) {
-        char *sysdb_dn;
-        DEBUG(7, ("checking member: %s\n", (const char*)el->values[i].data));
-        ret = sdap_find_entry_by_origDN(grp_state->sysdb_dns->values, sysdb,
-                                        dom, (const char *)el->values[i].data,
-                                        &sysdb_dn);
-        if (ret == ENOENT) {
-            if (opts->schema_type != SDAP_SCHEMA_RFC2307BIS) {
-                continue;
-            }
+    switch (opts->schema_type) {
+        case SDAP_SCHEMA_RFC2307:
+            ret = sdap_process_group_members_2307(grp_state, el);
+            break;
 
-            DEBUG(7, ("member #%d (%s): not found in sysdb, searching LDAP\n",
-                    i, (char *)el->values[i].data));
+        case SDAP_SCHEMA_IPA_V1:
+        case SDAP_SCHEMA_AD:
+        case SDAP_SCHEMA_RFC2307BIS:
+            ret = sdap_process_group_members_2307bis(req, grp_state, el);
+            break;
 
-            /*
-             * Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once.
-             * The rest is sent while the results are being processed.
-             * We limit the number as of request here, as the Server might
-             * enforce limits on the number of pending operations per
-             * connection.
-             */
-            if (grp_state->check_count > GROUPMEMBER_REQ_PARALLEL) {
-                DEBUG(7, (" queueing search for: %s\n",
-                         (char*)el->values[i].data));
-                if (!grp_state->queued_members) {
-                    DEBUG(7,("Allocating queue for %d members\n",
-                            el->num_values - grp_state->check_count));
-                    grp_state->queued_members = talloc_array(grp_state, char *,
-                            el->num_values - grp_state->check_count + 1);
-                    if (!grp_state->queued_members) {
-                        ret = ENOMEM;
-                        goto done;
-                    }
-                }
-                grp_state->queued_members[queue_len] = (char*)el->values[i].data;
-                queue_len++;
-            } else {
-                struct tevent_req *subreq =
-                            sdap_get_generic_send(grp_state,
-                                                  ev, opts, sh,
-                                                  (char *)el->values[i].data,
-                                                  LDAP_SCOPE_BASE,
-                                                  filter, attrs,
-                                                  opts->user_map,
-                                                  SDAP_OPTS_USER);
-                if (!subreq) {
-                    ret = ENOMEM;
-                    goto done;
-                }
-                tevent_req_set_callback(subreq, sdap_process_group_members, req);
-            }
-            grp_state->check_count++;
-        } else {
+        default:
+            DEBUG(1, ("Unknown schema type %d\n", opts->schema_type));
+            ret = EINVAL;
+            break;
+    }
+
+done:
+    /* We managed to process all the entries */
+    /* EBUSY means we need to wait for entries in LDAP */
+    if (ret == EOK) {
+        DEBUG(7, ("All group members processed\n"));
+        tevent_req_done(req);
+        tevent_req_post(req, ev);
+    }
+
+    if (ret != EOK && ret != EBUSY) {
+        tevent_req_error(req, ret);
+        tevent_req_post(req, ev);
+    }
+    return req;
+}
+
+static int
+sdap_process_missing_member_2307bis(struct tevent_req *req,
+                                    char *user_dn,
+                                    int num_users);
+
+static int
+sdap_process_group_members_2307bis(struct tevent_req *req,
+                                   struct sdap_process_group_state *state,
+                                   struct ldb_message_element *memberel)
+{
+    char *member_dn;
+    char *strdn;
+    int ret;
+    int i;
+
+    for (i=0; i < memberel->num_values; i++) {
+        member_dn = (char *)memberel->values[i].data;
+
+        ret = sdap_find_entry_by_origDN(state->sysdb_dns->values,
+                                        state->sysdb,
+                                        state->dom,
+                                        member_dn,
+                                        &strdn);
+        if (ret == EOK) {
             /*
              * User already cached in sysdb. Remember the sysdb DN for later
              * use by sdap_save_groups()
              */
-            DEBUG(7, ("sysdbdn: %s\n", sysdb_dn));
-            grp_state->sysdb_dns->values[grp_state->sysdb_dns->num_values].data =
-                    (uint8_t*)sysdb_dn;
-            grp_state->sysdb_dns->values[grp_state->sysdb_dns->num_values].length =
-                    strlen(sysdb_dn);
-            grp_state->sysdb_dns->num_values++;
+            DEBUG(7, ("sysdbdn: %s\n", strdn));
+            state->sysdb_dns->values[state->sysdb_dns->num_values].data =
+                (uint8_t*) strdn;
+            state->sysdb_dns->values[state->sysdb_dns->num_values].length =
+                strlen(strdn);
+            state->sysdb_dns->num_values++;
+        } else if (ret == ENOENT) {
+            /* The user is not in sysdb, need to add it */
+            DEBUG(7, ("Searching LDAP for missing user entry\n"));
+            ret = sdap_process_missing_member_2307bis(req,
+                                                      member_dn,
+                                                      memberel->num_values);
+            if (ret != EOK) {
+                DEBUG(1, ("Error processing missing member #%d (%s):\n",
+                          i, member_dn));
+                return ret;
+            }
+        } else {
+            DEBUG(1, ("Error checking cache for member #%d (%s):\n",
+                       i, (char *)memberel->values[i].data));
+            return ret;
         }
     }
-    if (queue_len > 0) {
-        grp_state->queued_members[queue_len] = NULL;
+
+    if (state->queue_len > 0) {
+        state->queued_members[state->queue_len]=NULL;
     }
 
-    if (grp_state->check_count == 0) {
+    if (state->check_count == 0) {
         /*
          * All group members are already cached in sysdb, we are done
          * with this group. To avoid redundant sysdb lookups, populate the
          * "member" attribute of the group entry with the sysdb DNs of
          * the members.
          */
-        el->values = grp_state->sysdb_dns->values;
-        el->num_values = grp_state->sysdb_dns->num_values;
         ret = EOK;
-        goto done;
+        memberel->values = state->sysdb_dns->values;
+        memberel->num_values = state->sysdb_dns->num_values;
     } else {
-        grp_state->count = grp_state->check_count;
-        grp_state->new_members = talloc_zero_array(grp_state,
-                                                   struct sysdb_attrs *,
-                                                   grp_state->count + 1);
-        if (!grp_state->new_members) {
-            ret = ENOMEM;
+        state->count = state->check_count;
+        state->new_members = talloc_zero_array(state,
+                struct sysdb_attrs *,
+                state->count + 1);
+        if (!state->new_members) {
+            return ENOMEM;
+        }
+        ret = EBUSY;
+    }
+
+    return ret;
+}
+
+static int
+sdap_process_missing_member_2307(struct sdap_process_group_state *state,
+                                 char *username, bool *in_transaction);
+
+static int
+sdap_process_group_members_2307(struct sdap_process_group_state *state,
+                                struct ldb_message_element *memberel)
+{
+    struct ldb_message *msg;
+    bool in_transaction;
+    char *member_name;
+    char *strdn;
+    int ret;
+    int i;
+
+    for (i=0; i < memberel->num_values; i++) {
+        member_name = (char *)memberel->values[i].data;
+        ret = sysdb_search_user_by_name(state, state->sysdb,
+                                        state->dom, member_name,
+                                        NULL, &msg);
+        if (ret == EOK) {
+            strdn = sysdb_user_strdn(state->sysdb_dns->values,
+                                     state->dom->name,
+                                     member_name);
+            if (!strdn) {
+                ret = ENOMEM;
+                goto done;
+            }
+            /*
+            * User already cached in sysdb. Remember the sysdb DN for later
+            * use by sdap_save_groups()
+            */
+            DEBUG(7,("Member already cached in sysdb: %s\n", strdn));
+            state->sysdb_dns->values[state->sysdb_dns->num_values].data =
+                    (uint8_t *) strdn;
+            state->sysdb_dns->values[state->sysdb_dns->num_values].length =
+                    strlen(strdn);
+            state->sysdb_dns->num_values++;
+        } else if (ret == ENOENT) {
+            /* The user is not in sysdb, need to add it */
+            DEBUG(7, ("member #%d (%s): not found in sysdb\n",
+                       i, member_name));
+
+            ret = sdap_process_missing_member_2307(state, member_name,
+                                                   &in_transaction);
+            if (ret != EOK) {
+                DEBUG(1, ("Error processing missing member #%d (%s):\n",
+                          i, member_name));
+                goto done;
+            }
+        } else {
+            DEBUG(1, ("Error checking cache for member #%d (%s):\n",
+                       i, (char *) memberel->values[i].data));
+            goto done;
+        }
+    }
+
+    /* sdap_process_missing_member_2307 starts transaction */
+    if (in_transaction) {
+        ret = sysdb_transaction_commit(state->sysdb);
+        if (ret) {
+            DEBUG(2, ("Cannot commit sysdb transaction\n"));
             goto done;
         }
     }
-    return req;
 
+    ret = EOK;
+    memberel->values = state->sysdb_dns->values;
+    memberel->num_values = state->sysdb_dns->num_values;
 done:
-    if (ret) {
-        tevent_req_error(req, ret);
+    return ret;
+}
+
+
+static int
+sdap_process_missing_member_2307bis(struct tevent_req *req,
+                                    char *user_dn,
+                                    int num_users)
+{
+    struct sdap_process_group_state *grp_state =
+        tevent_req_data(req, struct sdap_process_group_state);
+    struct tevent_req *subreq;
+
+    /*
+     * Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once.
+     * The rest is sent while the results are being processed.
+     * We limit the number as of request here, as the Server might
+     * enforce limits on the number of pending operations per
+     * connection.
+     */
+    if (grp_state->check_count > GROUPMEMBER_REQ_PARALLEL) {
+        DEBUG(7, (" queueing search for: %s\n", user_dn));
+        if (!grp_state->queued_members) {
+            DEBUG(7, ("Allocating queue for %d members\n",
+                      num_users - grp_state->check_count));
+
+            grp_state->queued_members = talloc_array(grp_state, char *,
+                    num_users - grp_state->check_count + 1);
+            if (!grp_state->queued_members) {
+                return ENOMEM;
+            }
+        }
+        grp_state->queued_members[grp_state->queue_len] = user_dn;
+        grp_state->queue_len++;
     } else {
-        tevent_req_done(req);
+        subreq = sdap_get_generic_send(grp_state,
+                                       grp_state->ev,
+                                       grp_state->opts,
+                                       grp_state->sh,
+                                       user_dn,
+                                       LDAP_SCOPE_BASE,
+                                       grp_state->filter,
+                                       grp_state->attrs,
+                                       grp_state->opts->user_map,
+                                       SDAP_OPTS_USER);
+        if (!subreq) {
+            return ENOMEM;
+        }
+        tevent_req_set_callback(subreq, sdap_process_group_members, req);
     }
-    tevent_req_post(req,ev);
-    return req;
+
+    grp_state->check_count++;
+    return EOK;
+}
+
+static int
+sdap_process_missing_member_2307(struct sdap_process_group_state *state,
+                                 char *username, bool *in_transaction)
+{
+    int ret;
+    struct ldb_dn *dn;
+    char* dn_string;
+
+    DEBUG(7, ("Adding a dummy entry\n"));
+
+    if (!in_transaction) return EINVAL;
+
+    if (!*in_transaction) {
+        ret = sysdb_transaction_start(state->sysdb);
+        if (ret != EOK) {
+            DEBUG(1, ("Cannot start sysdb transaction: [%d]: %s\n",
+                       ret, strerror(ret)));
+            return ret;
+        }
+        *in_transaction = true;
+    }
+
+    ret = sysdb_add_fake_user(state->sysdb, state->dom, username);
+    if (ret != EOK) {
+        DEBUG(1, ("Cannot store fake user entry: [%d]: %s\n",
+                  ret, strerror(ret)));
+        goto fail;
+    }
+
+    /*
+     * Convert the just received DN into the corresponding sysdb DN
+     * for saving into member attribute of the group
+     */
+    dn = sysdb_user_dn(state->sysdb, state, state->dom->name,
+                       (char*) username);
+    if (!dn) {
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    dn_string = ldb_dn_alloc_linearized(state->sysdb_dns->values, dn);
+    if (!dn_string) {
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    state->sysdb_dns->values[state->sysdb_dns->num_values].data =
+            (uint8_t *) dn_string;
+    state->sysdb_dns->values[state->sysdb_dns->num_values].length =
+            strlen(dn_string);
+    state->sysdb_dns->num_values++;
+
+    return EOK;
+fail:
+    if (*in_transaction) {
+        sysdb_transaction_cancel(state->sysdb);
+    }
+    return ret;
 }
 
 static void sdap_process_group_members(struct tevent_req *subreq)
-- 
1.7.2.3

Attachment: 0001-sysdb-interface-for-adding-fake-users.patch.sig
Description: PGP signature

Attachment: 0002-Save-dummy-member-users-during-RFC2307-getgr-nam-uid.patch.sig
Description: PGP signature

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

Reply via email to