From ec906111d4e85c9f040fb3dee156ddf69685cfd5 Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Mon, 23 Apr 2012 04:50:36 -0400
Subject: [PATCH 05/10] Ghost members - modifications in memberof plugin

---
 src/ldb_modules/memberof.c |  126 +++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
index 4fc46fa84529ac1850cdb588ddf69be0f60e8238..63666ca648502b18d03382b655a1650504112c44 100644
--- a/src/ldb_modules/memberof.c
+++ b/src/ldb_modules/memberof.c
@@ -28,6 +28,7 @@
 #include "dhash.h"
 
 #define DB_MEMBER "member"
+#define DB_GHOST "ghost"
 #define DB_MEMBEROF "memberof"
 #define DB_MEMBERUID "memberuid"
 #define DB_NAME "name"
@@ -534,7 +535,8 @@ static int mbof_add_callback(struct ldb_request *req,
 static int mbof_next_add(struct mbof_add_operation *addop)
 {
     static const char *attrs[] = { DB_OC, DB_NAME,
-                                   DB_MEMBER, DB_MEMBEROF, NULL };
+                                   DB_MEMBER, DB_GHOST,
+                                   DB_MEMBEROF, NULL };
     struct ldb_context *ldb;
     struct ldb_request *req;
     struct mbof_add_ctx *add_ctx;
@@ -806,6 +808,22 @@ static int mbof_add_operation(struct mbof_add_operation *addop)
         return ret;
     }
 
+    el = ldb_msg_find_element(addop->entry, DB_GHOST);
+    if (el) {
+        for (i = 0; i < el->num_values; i++) {
+            for (j = 0; j < parents->num; j++) {
+                ret = mbof_append_muop(add_ctx, &add_ctx->muops,
+                                       &add_ctx->num_muops,
+                                       LDB_FLAG_MOD_ADD,
+                                       parents->dns[j],
+                                       (char *)el->values[i].data);
+                if (ret != LDB_SUCCESS) {
+                    return ret;
+                }
+            }
+        }
+    }
+
     /* we are done with the entry now */
     talloc_free(addop->entry);
     addop->entry = NULL;
@@ -1158,6 +1176,9 @@ static int mbof_del_get_next(struct mbof_del_operation *delop,
                              struct mbof_del_operation **nextop);
 static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
                               struct ldb_message *entry);
+static int mbof_del_fill_muop_ghosts(struct mbof_del_ctx *del_ctx,
+                                     struct ldb_message_element *memberof_el,
+                                     struct ldb_message_element *ghost_el);
 static int mbof_del_muop(struct mbof_del_ctx *ctx);
 static int mbof_del_muop_callback(struct ldb_request *req,
                                   struct ldb_reply *ares);
@@ -1604,7 +1625,7 @@ static int mbof_del_execute_op(struct mbof_del_operation *delop)
     const char *dn;
     char *clean_dn;
     static const char *attrs[] = { DB_OC, DB_NAME,
-                                   DB_MEMBER, DB_MEMBEROF, NULL };
+                                   DB_MEMBER, DB_GHOST, DB_MEMBEROF, NULL };
     int ret;
 
     del_ctx = delop->del_ctx;
@@ -1942,6 +1963,7 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
     struct ldb_request *mod_req;
     struct ldb_message *msg;
     struct ldb_message_element *el;
+    struct ldb_message_element *ghost_el;
     struct ldb_dn **diff = NULL;
     const char *name;
     const char *val;
@@ -1954,9 +1976,11 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
     ldb = ldb_module_get_ctx(ctx->module);
     new_list = delop->anc_ctx->new_list;
 
-    /* if this is a user we need to find out which entries have been
+    /* if this is a user or a group with some some ghost members
+     * we need to find out which entries have been
      * removed so that we can later schedule removal of memberuid
      * attributes from these entries */
+    ghost_el = ldb_msg_find_element(delop->entry, DB_GHOST);
     ret = entry_is_user_object(delop->entry);
     switch (ret) {
     case LDB_SUCCESS:
@@ -1972,7 +1996,7 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
         return ret;
     }
 
-    if (is_user) {
+    if (is_user || ghost_el) {
         /* prepare memberuid delete list */
         /* copy all original memberof entries, and then later remove
          * the ones that will survive in the entry */
@@ -2032,7 +2056,7 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
             }
             j++;
 
-            if (is_user) {
+            if (is_user || ghost_el) {
                 /* compare the entry's original memberof list with the new
                  * one and for each missing entry add a memberuid removal
                  * operation */
@@ -2076,6 +2100,19 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
                 return ret;
             }
         }
+    } else if (ghost_el && diff[0]) {
+        for (i = 0; i < ghost_el->num_values; i++) {
+            for (j = 0; diff[j]; j++) {
+                ret = mbof_append_muop(del_ctx, &del_ctx->muops,
+                                       &del_ctx->num_muops,
+                                       LDB_FLAG_MOD_DELETE,
+                                       diff[j],
+                                       (char *)ghost_el->values[j].data);
+                if (ret != LDB_SUCCESS) {
+                    return ret;
+                }
+            }
+        }
     }
 
     ret = ldb_build_mod_req(&mod_req, ldb, delop,
@@ -2264,6 +2301,7 @@ static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
                               struct ldb_message *entry)
 {
     struct ldb_message_element *el;
+    struct ldb_message_element *ghost_el;
     char *name;
     int ret;
     int i;
@@ -2282,6 +2320,13 @@ static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
 
     case LDB_ERR_NO_SUCH_ATTRIBUTE:
         /* it is not a user object, just return */
+        ghost_el = ldb_msg_find_element(entry, DB_GHOST);
+        if (ghost_el) {
+            ret = mbof_del_fill_muop_ghosts(del_ctx, el, ghost_el);
+            if (ret != LDB_SUCCESS) {
+                return ret;
+            }
+        }
         return LDB_SUCCESS;
 
     default:
@@ -2320,6 +2365,43 @@ static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
     return LDB_SUCCESS;
 }
 
+static int mbof_del_fill_muop_ghosts(struct mbof_del_ctx *del_ctx,
+                                     struct ldb_message_element *memberof_el,
+                                     struct ldb_message_element *ghost_el)
+{
+    int i, j;
+    int ret;
+    struct ldb_dn *valdn;
+
+    if (memberof_el->num_values == 0 || ghost_el->num_values == 0) {
+        return LDB_SUCCESS;
+    }
+
+    for (i = 0; i < memberof_el->num_values; i++) {
+        valdn = ldb_dn_from_ldb_val(del_ctx->muops,
+                                    ldb_module_get_ctx(del_ctx->ctx->module),
+                                    &memberof_el->values[i]);
+        if (!valdn || !ldb_dn_validate(valdn)) {
+            ldb_debug(ldb_module_get_ctx(del_ctx->ctx->module),
+                      LDB_DEBUG_ERROR,
+                      "Invalid dn value: [%s]",
+                      (const char *)memberof_el->values[i].data);
+        }
+
+        for (j = 0; j < ghost_el->num_values; j++) {
+            ret = mbof_append_muop(del_ctx, &del_ctx->muops,
+                                   &del_ctx->num_muops,
+                                   LDB_FLAG_MOD_DELETE,
+                                   valdn, (char *)ghost_el->values[j].data);
+            if (ret != LDB_SUCCESS) {
+                return ret;
+            }
+        }
+    }
+
+    return LDB_SUCCESS;
+}
+
 /* del memberuid attributes to parent groups */
 static int mbof_del_muop(struct mbof_del_ctx *del_ctx)
 {
@@ -2915,6 +2997,7 @@ struct mbof_member {
     bool orig_has_memberof;
     bool orig_has_memberuid;
     struct ldb_message_element *orig_members;
+    struct ldb_message_element *orig_ghosts;
 
     struct mbof_member **members;
 
@@ -3100,7 +3183,8 @@ static int mbof_rcmp_search_groups(struct mbof_rcmp_context *ctx)
 {
     struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
     static const char *attrs[] = { DB_MEMBEROF, DB_MEMBERUID,
-                                   DB_NAME, DB_MEMBER, NULL };
+                                   DB_NAME, DB_MEMBER, DB_GHOST,
+                                   NULL };
     static const char *filter = "(objectclass=group)";
     struct ldb_request *req;
     int ret;
@@ -3183,6 +3267,13 @@ static int mbof_rcmp_grp_callback(struct ldb_request *req,
                                    LDB_ERR_OPERATIONS_ERROR);
         }
 
+        ret = mbof_steal_msg_el(grp, DB_GHOST,
+                                ares->message, &grp->orig_ghosts);
+        if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
+            return ldb_module_done(ctx->req, NULL, NULL,
+                                   LDB_ERR_OPERATIONS_ERROR);
+        }
+
         DLIST_ADD(ctx->group_list, grp);
 
         key.type = HASH_KEY_STRING;
@@ -3310,6 +3401,7 @@ static int mbof_member_update(struct mbof_rcmp_context *ctx,
     hash_value_t value;
     hash_key_t key;
     int ret;
+    int i;
 
     /* ignore loops */
     if (parent == mem) return LDB_SUCCESS;
@@ -3356,6 +3448,16 @@ static int mbof_member_update(struct mbof_rcmp_context *ctx,
             }
         }
 
+        if (mem->orig_ghosts) {
+            for (i = 0; i < mem->orig_ghosts->num_values; i++) {
+                ret = mbof_add_memuid(parent,
+                                      (char *)mem->orig_ghosts->values[i].data);
+                if (ret != LDB_SUCCESS) {
+                    return ret;
+                }
+            }
+        }
+
         /* if we updated a group, mark it as TO DO again */
         if (mem->status == MBOF_GROUP_DONE) {
             mem->status = MBOF_GROUP_TO_DO;
@@ -3387,6 +3489,7 @@ static bool mbof_member_iter(hash_entry_t *item, void *user_data)
     struct mbof_member *mem;
     hash_value_t value;
     int ret;
+    int i;
 
     mem = talloc_get_type(user_data, struct mbof_member);
 
@@ -3423,6 +3526,17 @@ static bool mbof_member_iter(hash_entry_t *item, void *user_data)
                 return false;
             }
         }
+
+        if (mem->orig_ghosts) {
+            for (i = 0; i < mem->orig_ghosts->num_values; i++) {
+                ret = mbof_add_memuid(parent,
+                                      (char *)mem->orig_ghosts->values[i].data);
+                if (ret != LDB_SUCCESS) {
+                    mem->status = MBOF_ITER_ERROR;
+                    return false;
+                }
+            }
+        }
     }
 
     return true;
-- 
1.7.6.5

