>From 3010259bd9282fb06c2323ed890832fc4f2e8595 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 14 Aug 2009 13:51:02 -0400
Subject: [PATCH 1/3] Always save using member/memberOf

First pass to remove the legacy option and make it just a property of the
provider
---
 server/db/sysdb.c                  |   24 ++++
 server/db/sysdb.h                  |   14 +-
 server/db/sysdb_ops.c              |  261 ++++++++++++++++--------------------
 server/db/sysdb_search.c           |   63 +---------
 server/providers/ldap/sdap_async.c |    5 +
 5 files changed, 151 insertions(+), 216 deletions(-)

diff --git a/server/db/sysdb.c b/server/db/sysdb.c
index 0cac339..00657f0 100644
--- a/server/db/sysdb.c
+++ b/server/db/sysdb.c
@@ -121,6 +121,30 @@ int sysdb_attrs_add_string(struct sysdb_attrs *attrs,
     return sysdb_attrs_add_val(attrs, name, &v);
 }
 
+int sysdb_attrs_steal_string(struct sysdb_attrs *attrs,
+                             const char *name, char *str)
+{
+    struct ldb_message_element *el = NULL;
+    struct ldb_val *vals;
+    int ret;
+
+    ret = sysdb_attrs_get_el(attrs, name, &el);
+
+    vals = talloc_realloc(attrs->a, el->values,
+                          struct ldb_val, el->num_values+1);
+    if (!vals) return ENOMEM;
+    el->values = vals;
+
+    /* now steal and assign the string */
+    talloc_steal(el->values, str);
+
+    el->values[el->num_values].data = (uint8_t *)str;
+    el->values[el->num_values].length = strlen(str);
+    el->num_values++;
+
+    return EOK;
+}
+
 int sysdb_attrs_add_long(struct sysdb_attrs *attrs,
                          const char *name, long value)
 {
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index 64a07fe..70231f8 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -51,7 +51,7 @@
 #define SYSDB_DISABLED "disabled"
 
 #define SYSDB_MEMBER "member"
-#define SYSDB_LEGACY_MEMBER "memberUid"
+#define SYSDB_MEMBERUID "memberUid"
 
 #define SYSDB_DEFAULTGROUP "defaultGroup"
 #define SYSDB_GECOS "gecos"
@@ -65,9 +65,11 @@
 
 #define SYSDB_CACHEDPWD "cachedPassword"
 
-#define SYSDB_ORIG_DN "originalDN"
 #define SYSDB_UUID "uniqueID"
-#define SYSDB_UPN "UserPrincipalName"
+#define SYSDB_UPN "userPrincipalName"
+
+#define SYSDB_ORIG_DN "originalDN"
+#define SYSDB_ORIG_MODSTAMP "originalModifyTimestamp"
 
 #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)"
 
@@ -89,8 +91,6 @@
 
 #define SYSDB_INITGR_FILTER "(&("SYSDB_GC")("SYSDB_GIDNUM"=*))"
 
-#define SYSDB_INITGR_LEGACY_FILTER "(&("SYSDB_GC")("SYSDB_LEGACY_MEMBER"=%s))"
-
 #define SYSDB_GETCACHED_FILTER "(&"SYSDB_UC")("SYSDB_LAST_LOGIN">=%lu))"
 
 #define SYSDB_PW_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \
@@ -112,7 +112,7 @@
                           SYSDB_LAST_UPDATE, \
                           NULL}
 #define SYSDB_GRSRC_ATTRS {SYSDB_NAME, SYSDB_GIDNUM, \
-                           SYSDB_LAST_UPDATE, SYSDB_LEGACY_MEMBER, \
+                           SYSDB_LAST_UPDATE, \
                            "objectClass", \
                            NULL}
 #define SYSDB_GRPW_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \
@@ -157,6 +157,8 @@ int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs,
                            const char *name, time_t value);
 int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
                        struct ldb_message_element **el);
+int sysdb_attrs_steal_string(struct sysdb_attrs *attrs,
+                             const char *name, char *str);
 
 /* convert an ldb error into an errno error */
 int sysdb_error_to_errno(int ldberr);
diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c
index 56e2777..a36b22f 100644
--- a/server/db/sysdb_ops.c
+++ b/server/db/sysdb_ops.c
@@ -154,9 +154,9 @@ static int sldb_request_callback(struct ldb_request *ldbreq,
     state->ldbreply = talloc_steal(state, ldbreply);
 
     if (ldbreply->error != LDB_SUCCESS) {
-        err = sysdb_error_to_errno(ldbreply->error);
-        DEBUG(6, ("Error: %d (%s)\n", err, strerror(err)));
-        ERROR_OUT(err, err, fail);
+        DEBUG(6, ("LDB Error: %d (%s)\n",
+                  ldbreply->error, ldb_errstring(state->ldbctx)));
+        ERROR_OUT(err, sysdb_error_to_errno(ldbreply->error), fail);
     }
 
     if (ldbreply->type == LDB_REPLY_DONE) {
@@ -2811,7 +2811,9 @@ struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx,
 {
     struct tevent_req *req, *subreq;
     struct sysdb_store_group_state *state;
-    int ret, i;
+    static const char *src_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM,
+                                       SYSDB_ORIG_MODSTAMP, NULL };
+    int ret;
 
     req = tevent_req_create(mem_ctx, &state, struct sysdb_store_group_state);
     if (!req) return NULL;
@@ -2824,38 +2826,8 @@ struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx,
     state->members = members;
     state->attrs = NULL;
 
-    if (state->members) {
-        state->attrs = sysdb_new_attrs(state);
-        if (!state->attrs) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
-
-        for (i = 0; state->members[i]; i++) {
-            if (domain->legacy) {
-/*
-                const char *member;
-
-                member = talloc_asprintf(state, SYSDB_TMPL_USER,
-                                         domain->name, state->members[i]);
-                if (!member) {
-                    ERROR_OUT(ret, ENOMEM, fail);
-                }
-*/
-                ret = sysdb_attrs_add_string(state->attrs, SYSDB_LEGACY_MEMBER,
-                                             state->members[i]);
-                if (ret) goto fail;
-            } else {
-                ret = sysdb_attrs_add_string(state->attrs, SYSDB_MEMBER,
-                                             state->members[i]);
-                if (ret) goto fail;
-            }
-        }
-
-        state->members = NULL;
-    }
-
     subreq = sysdb_search_group_by_name_send(state, ev, NULL, handle,
-                                             domain, name, NULL);
+                                             domain, name, src_attrs);
     if (!subreq) {
         ERROR_OUT(ret, ENOMEM, fail);
     }
@@ -2877,7 +2849,8 @@ static void sysdb_store_group_check(struct tevent_req *subreq)
     struct sysdb_store_group_state *state = tevent_req_data(req,
                                                struct sysdb_store_group_state);
     struct ldb_message *msg;
-    int ret;
+    bool new_group = false;
+    int ret, i;
 
     ret = sysdb_search_group_recv(subreq, state, &msg);
     talloc_zfree(subreq);
@@ -2885,22 +2858,92 @@ static void sysdb_store_group_check(struct tevent_req *subreq)
         tevent_req_error(req, ret);
         return;
     }
-
     if (ret == ENOENT) {
+        new_group = true;
+    }
+
+    /* FIXME: use the remote modification timestamp to know if the
+     * group needs any update */
+
+    if (state->members) {
+        state->attrs = sysdb_new_attrs(state);
+        if (!state->attrs) {
+            DEBUG(6, ("Error: Out of memory\n"));
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+
+        for (i = 0; state->members[i]; i++) {
+            struct ldb_dn *tmp = NULL;
+            const struct ldb_val *val;
+            const char *mname;
+            char *member;
+
+            if (state->domain->legacy) {
+                mname = state->members[i];
+            } else {
+
+                tmp = ldb_dn_new(state, state->handle->ctx->ldb,
+                                 state->members[i]);
+                if (!tmp) {
+                    DEBUG(2, ("Out of memory, converting DN [%s]!\n",
+                              state->members[i]));
+                    continue;
+                }
+                val = ldb_dn_get_rdn_val(tmp);
+                if (!val) {
+                    DEBUG(2, ("Out of memory, converting DN [%s]!\n",
+                              state->members[i]));
+                    continue;
+                }
+                mname = talloc_strndup(tmp,
+                                       (const char *)val->data, val->length);
+                if (!mname) {
+                    DEBUG(2, ("Out of memory, converting DN [%s]!\n",
+                              state->members[i]));
+                    continue;
+                }
+            }
+
+            member = talloc_asprintf(state, SYSDB_TMPL_USER,
+                                     mname, state->domain->name);
+            if (!member) {
+                DEBUG(6, ("Error: Out of memory\n"));
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+            DEBUG(9, ("adding member: %s [orig: %s] to group %s\n",
+                      member, state->members[i], state->name));
+
+            talloc_zfree(tmp);
+
+            ret = sysdb_attrs_steal_string(state->attrs,
+                                           SYSDB_MEMBER, member);
+            if (ret) {
+                DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
+                tevent_req_error(req, ret);
+                return;
+            }
+        }
+    }
+
+    if (new_group) {
         /* groups doesn't exist, turn into adding a group */
         subreq = sysdb_add_group_send(state, state->ev, state->handle,
-                                     state->domain, state->name,
-                                     state->gid, state->attrs);
+                                      state->domain, state->name,
+                                      state->gid, state->attrs);
         if (!subreq) {
             DEBUG(6, ("Error: Out of memory\n"));
             tevent_req_error(req, ENOMEM);
             return;
         }
         tevent_req_set_callback(subreq, sysdb_store_group_add_done, req);
+
         return;
     }
 
     /* the group exists, let's just replace attributes when set */
+
     if (!state->attrs) {
         state->attrs = sysdb_new_attrs(state);
         if (!state->attrs) {
@@ -2919,8 +2962,6 @@ static void sysdb_store_group_check(struct tevent_req *subreq)
         }
     }
 
-    /* FIXME: handle non legacy groups */
-
     ret = sysdb_attrs_add_time_t(state->attrs, SYSDB_LAST_UPDATE, time(NULL));
     if (ret) {
         DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
@@ -2929,9 +2970,9 @@ static void sysdb_store_group_check(struct tevent_req *subreq)
     }
 
     subreq = sysdb_set_group_attr_send(state, state->ev,
-                                      state->handle, state->domain,
-                                      state->name, state->attrs,
-                                      SYSDB_MOD_REP);
+                                       state->handle, state->domain,
+                                       state->name, state->attrs,
+                                       SYSDB_MOD_REP);
     if (!subreq) {
         DEBUG(6, ("Error: Out of memory\n"));
         tevent_req_error(req, ENOMEM);
@@ -2983,7 +3024,6 @@ int sysdb_store_group_recv(struct tevent_req *req)
 /* =Add-User-to-Group(Native/Legacy)====================================== */
 
 static void sysdb_add_group_member_done(struct tevent_req *subreq);
-static void sysdb_add_group_member_l_done(struct tevent_req *subreq);
 
 struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx,
                                                struct tevent_context *ev,
@@ -2995,7 +3035,6 @@ struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx,
     struct tevent_req *req, *subreq;
     struct sysdb_op_state *state;
     struct ldb_dn *group_dn, *user_dn;
-    struct sysdb_attrs *attrs;
     int ret;
 
     req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state);
@@ -3006,42 +3045,23 @@ struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx,
     state->ignore_not_found = false;
     state->ldbreply = NULL;
 
-    if (domain->legacy) {
-        attrs = sysdb_new_attrs(state);
-        if (!attrs) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
-
-        ret = sysdb_attrs_add_string(attrs, SYSDB_LEGACY_MEMBER, user);
-        if (ret) goto fail;
-
-        subreq = sysdb_set_group_attr_send(state, ev, handle,
-                                           domain, group, attrs,
-                                           SYSDB_MOD_ADD);
-        if (!subreq) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
-        tevent_req_set_callback(subreq, sysdb_add_group_member_l_done, req);
-
-    } else {
-        group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group);
-        if (!group_dn) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
+    group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group);
+    if (!group_dn) {
+        ERROR_OUT(ret, ENOMEM, fail);
+    }
 
-        user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user);
-        if (!user_dn) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
+    user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user);
+    if (!user_dn) {
+        ERROR_OUT(ret, ENOMEM, fail);
+    }
 
-        subreq = sysdb_mod_group_member_send(state, ev, handle,
-                                             user_dn, group_dn,
-                                             SYSDB_MOD_ADD);
-        if (!subreq) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
-        tevent_req_set_callback(subreq, sysdb_add_group_member_done, req);
+    subreq = sysdb_mod_group_member_send(state, ev, handle,
+                                         user_dn, group_dn,
+                                         SYSDB_MOD_ADD);
+    if (!subreq) {
+        ERROR_OUT(ret, ENOMEM, fail);
     }
+    tevent_req_set_callback(subreq, sysdb_add_group_member_done, req);
 
     return req;
 
@@ -3069,23 +3089,6 @@ static void sysdb_add_group_member_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
-static void sysdb_add_group_member_l_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                  struct tevent_req);
-    int ret;
-
-    ret = sysdb_set_group_attr_recv(subreq);
-    talloc_zfree(subreq);
-    if (ret) {
-        DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    tevent_req_done(req);
-}
-
 int sysdb_add_group_member_recv(struct tevent_req *req)
 {
     return sysdb_op_default_recv(req);
@@ -3095,7 +3098,6 @@ int sysdb_add_group_member_recv(struct tevent_req *req)
 /* =Remove-member-from-Group(Native/Legacy)=============================== */
 
 static void sysdb_remove_group_member_done(struct tevent_req *subreq);
-static void sysdb_remove_group_member_l_done(struct tevent_req *subreq);
 
 struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx,
                                                   struct tevent_context *ev,
@@ -3107,7 +3109,6 @@ struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx,
     struct tevent_req *req, *subreq;
     struct sysdb_op_state *state;
     struct ldb_dn *group_dn, *user_dn;
-    struct sysdb_attrs *attrs;
     int ret;
 
     req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state);
@@ -3118,42 +3119,23 @@ struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx,
     state->ignore_not_found = false;
     state->ldbreply = NULL;
 
-    if (domain->legacy) {
-        attrs = sysdb_new_attrs(state);
-        if (!attrs) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
-
-        ret = sysdb_attrs_add_string(attrs, SYSDB_LEGACY_MEMBER, user);
-        if (ret) goto fail;
-
-        subreq = sysdb_set_group_attr_send(state, ev, handle,
-                                           domain, group, attrs,
-                                           SYSDB_MOD_DEL);
-        if (!subreq) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
-        tevent_req_set_callback(subreq, sysdb_remove_group_member_l_done, req);
-
-    } else {
-        group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group);
-        if (!group_dn) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
+    group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group);
+    if (!group_dn) {
+        ERROR_OUT(ret, ENOMEM, fail);
+    }
 
-        user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user);
-        if (!user_dn) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
+    user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user);
+    if (!user_dn) {
+        ERROR_OUT(ret, ENOMEM, fail);
+    }
 
-        subreq = sysdb_mod_group_member_send(state, ev, handle,
-                                             user_dn, group_dn,
-                                             SYSDB_MOD_DEL);
-        if (!subreq) {
-            ERROR_OUT(ret, ENOMEM, fail);
-        }
-        tevent_req_set_callback(subreq, sysdb_remove_group_member_done, req);
+    subreq = sysdb_mod_group_member_send(state, ev, handle,
+                                         user_dn, group_dn,
+                                         SYSDB_MOD_DEL);
+    if (!subreq) {
+        ERROR_OUT(ret, ENOMEM, fail);
     }
+    tevent_req_set_callback(subreq, sysdb_remove_group_member_done, req);
 
     return req;
 
@@ -3181,23 +3163,6 @@ static void sysdb_remove_group_member_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
-static void sysdb_remove_group_member_l_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                  struct tevent_req);
-    int ret;
-
-    ret = sysdb_set_group_attr_recv(subreq);
-    talloc_zfree(subreq);
-    if (ret) {
-        DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    tevent_req_done(req);
-}
-
 int sysdb_remove_group_member_recv(struct tevent_req *req)
 {
     return sysdb_op_default_recv(req);
diff --git a/server/db/sysdb_search.c b/server/db/sysdb_search.c
index 5ee9f8c..a3fdb16 100644
--- a/server/db/sysdb_search.c
+++ b/server/db/sysdb_search.c
@@ -482,11 +482,6 @@ static int get_grp_callback(struct ldb_request *req,
             return LDB_SUCCESS;
         }
 
-        if (sctx->domain->legacy) {
-            request_done(sctx);
-            return LDB_SUCCESS;
-        }
-
         if (res->count > 0) {
 
             sctx->gmctx = talloc_zero(req, struct get_mem_ctx);
@@ -670,58 +665,6 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-static void initgr_mem_legacy(struct sysdb_search_ctx *sctx)
-{
-    struct sysdb_ctx *ctx = sctx->ctx;
-    struct ldb_result *res = sctx->res;
-    struct ldb_request *req;
-    struct ldb_dn *base_dn;
-    static const char *attrs[] = SYSDB_INITGR_ATTRS;
-    const char *userid;
-    int ret;
-
-    if (res->count == 0) {
-        return request_done(sctx);
-    }
-    if (res->count > 1) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    /* make sure we don't loop with get_gen_callback() */
-    sctx->gen_aux_fn = NULL;
-
-    userid = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
-    if (!userid) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    sctx->expression = talloc_asprintf(sctx,
-                                       SYSDB_INITGR_LEGACY_FILTER, userid);
-    if (!sctx->expression) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    base_dn = ldb_dn_new_fmt(sctx, ctx->ldb,
-                             SYSDB_TMPL_GROUP_BASE, sctx->domain->name);
-    if (!base_dn) {
-        return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR);
-    }
-
-    ret = ldb_build_search_req(&req, ctx->ldb, sctx,
-                               base_dn, LDB_SCOPE_SUBTREE,
-                               sctx->expression, attrs, NULL,
-                               sctx, get_gen_callback,
-                               NULL);
-    if (ret != LDB_SUCCESS) {
-        return request_ldberror(sctx, ret);
-    }
-
-    ret = ldb_request(ctx->ldb, req);
-    if (ret != LDB_SUCCESS) {
-        return request_ldberror(sctx, ret);
-    }
-}
-
 static void initgr_mem_search(struct sysdb_search_ctx *sctx)
 {
     struct sysdb_ctx *ctx = sctx->ctx;
@@ -801,11 +744,7 @@ static void initgr_search(struct tevent_req *treq)
         return request_error(sctx, ret);
     }
 
-    if (sctx->domain->legacy) {
-        sctx->gen_aux_fn = initgr_mem_legacy;
-    } else {
-        sctx->gen_aux_fn = initgr_mem_search;
-    }
+    sctx->gen_aux_fn = initgr_mem_search;
 
     base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb,
                              SYSDB_TMPL_USER_BASE, sctx->domain->name);
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index 539a075..57ccd86 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -1488,6 +1488,11 @@ static void sdap_get_groups_done(struct sdap_op *op,
 
     case LDAP_RES_SEARCH_ENTRY:
 
+        /* FIXME: we should do this in 2 steps:
+         * first save groups, then add all memberships
+         * otherwise nested memberships may go missing
+         * if the member group is added only after the
+         * parent group is added */
         subreq = sdap_save_group_send(state, state->ev, state->handle,
                                       state->opts, state->dom,
                                       state->sh, reply);
-- 
1.6.2.5

