s4:samldb LDB module - rework the group change code to be again synchronous
authorMatthias Dieter Wallnöfer <mdw@samba.org>
Sun, 30 May 2010 19:08:05 +0000 (21:08 +0200)
committerMatthias Dieter Wallnöfer <mdw@samba.org>
Sun, 30 May 2010 21:13:08 +0000 (23:13 +0200)
source4/dsdb/samdb/ldb_modules/samldb.c

index 4d1659df0b1f4823a72c41e1950af9f28468f6f4..a07dec961cd3d5ee3ff9ff94f0f161f333248202 100644 (file)
@@ -68,20 +68,6 @@ struct samldb_ctx {
        /* used in conjunction with "sid" in "samldb_dn_from_sid" */
        struct ldb_dn *res_dn;
 
-       /* used in conjunction with "dn" in "samldb_sid_from_dn" */
-       struct dom_sid *res_sid;
-
-       /* used in "samldb_user_dn_to_prim_group_rid" */
-       uint32_t prim_group_rid;
-
-       /* used in "samldb_group_add_member" and "samldb_group_del_member" */
-       struct ldb_dn *group_dn;
-       struct ldb_dn *member_dn;
-
-       /* used in "samldb_primary_group_change" */
-       struct ldb_dn *user_dn;
-       struct ldb_dn *old_prim_group_dn, *new_prim_group_dn;
-
        /* all the async steps necessary to complete the operation */
        struct samldb_step *steps;
        struct samldb_step *curstep;
@@ -1133,339 +1119,115 @@ static int samldb_schema_info_update(struct samldb_ctx *ac)
        return LDB_SUCCESS;
 }
 
-/*
- * samldb_user_dn_to_prim_group_rid (async)
- */
-
-static int samldb_user_dn_to_prim_group_rid(struct samldb_ctx *ac);
 
-static int samldb_user_dn_to_prim_group_rid_callback(struct ldb_request *req,
-       struct ldb_reply *ares)
+static int samldb_prim_group_change(struct samldb_ctx *ac)
 {
        struct ldb_context *ldb;
-       struct samldb_ctx *ac;
+       const char * attrs[] = { "primaryGroupID", "memberOf", NULL };
+       struct ldb_result *res;
+       struct ldb_message_element *el;
+       struct ldb_message *msg;
+       uint32_t rid;
+       struct dom_sid *sid;
+       struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
        int ret;
 
-       ac = talloc_get_type(req->context, struct samldb_ctx);
        ldb = ldb_module_get_ctx(ac->module);
 
-       if (!ares) {
-               ret = LDB_ERR_OPERATIONS_ERROR;
-               goto done;
-       }
-       if (ares->error != LDB_SUCCESS) {
-               return ldb_module_done(ac->req, ares->controls,
-                                       ares->response, ares->error);
-       }
+       /* Fetch informations from the existing object */
 
-       switch (ares->type) {
-       case LDB_REPLY_ENTRY:
-               /* save entry */
-               if (ac->prim_group_rid != 0) {
-                       /* one too many! */
-                       ldb_set_errstring(ldb,
-                               "Invalid number of results while searching "
-                               "for domain objects!");
-                       ret = LDB_ERR_OPERATIONS_ERROR;
-                       break;
-               }
-               ac->prim_group_rid = samdb_result_uint(ares->message,
-                       "primaryGroupID", ~0);
-
-               talloc_free(ares);
-               ret = LDB_SUCCESS;
-               break;
-
-       case LDB_REPLY_REFERRAL:
-               /* ignore */
-               talloc_free(ares);
-               ret = LDB_SUCCESS;
-               break;
-
-       case LDB_REPLY_DONE:
-               talloc_free(ares);
-               if (ac->prim_group_rid == 0) {
-                       ldb_asprintf_errstring(ldb,
-                               "Unable to get the primary group RID!");
-                       ret = LDB_ERR_OPERATIONS_ERROR;
-                       break;
-               }
-
-               /* found, go on */
-               ret = samldb_next_step(ac);
-               break;
-       }
-
-done:
+       ret = ldb_search(ldb, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
+                        NULL);
        if (ret != LDB_SUCCESS) {
-               return ldb_module_done(ac->req, NULL, NULL, ret);
-       }
-
-       return LDB_SUCCESS;
-}
-
-/* Locates the "primaryGroupID" attribute from a certain user specified as
- * "user_dn". Saves the result in "prim_group_rid". */
-static int samldb_user_dn_to_prim_group_rid(struct samldb_ctx *ac)
-{
-       struct ldb_context *ldb;
-       static const char * const attrs[] = { "primaryGroupID", NULL };
-       struct ldb_request *req;
-       int ret;
-
-       ldb = ldb_module_get_ctx(ac->module);
-
-       if (ac->user_dn == NULL)
-               return LDB_ERR_OPERATIONS_ERROR;
-
-       ret = ldb_build_search_req(&req, ldb, ac,
-                               ac->user_dn,
-                               LDB_SCOPE_BASE,
-                               NULL, attrs,
-                               NULL,
-                               ac, samldb_user_dn_to_prim_group_rid_callback,
-                               ac->req);
-       if (ret != LDB_SUCCESS)
                return ret;
-
-       return ldb_next_request(ac->module, req);
-}
-
-/*
- * samldb_group_add_member (async)
- * samldb_group_del_member (async)
- */
-
-static int samldb_group_add_del_member_callback(struct ldb_request *req,
-       struct ldb_reply *ares)
-{
-       struct ldb_context *ldb;
-       struct samldb_ctx *ac;
-       int ret;
-
-       ac = talloc_get_type(req->context, struct samldb_ctx);
-       ldb = ldb_module_get_ctx(ac->module);
-
-       if (!ares) {
-               ret = LDB_ERR_OPERATIONS_ERROR;
-               goto done;
        }
 
-       if (ares->type == LDB_REPLY_REFERRAL) {
-               return ldb_module_send_referral(ac->req, ares->referral);
-       }
-
-       if (ares->error != LDB_SUCCESS) {
-               if (ares->error == LDB_ERR_NO_SUCH_ATTRIBUTE) {
-                       /* On error "NO_SUCH_ATTRIBUTE" (delete of an invalid
-                        * "member" attribute) return "UNWILLING_TO_PERFORM" */
-                       ares->error = LDB_ERR_UNWILLING_TO_PERFORM;
-               }
-               return ldb_module_done(ac->req, ares->controls,
-                                       ares->response, ares->error);
-       }
-       if (ares->type != LDB_REPLY_DONE) {
-               ldb_set_errstring(ldb,
-                       "Invalid reply type!");
-               ret = LDB_ERR_OPERATIONS_ERROR;
-               goto done;
-       }
-
-       ret = samldb_next_step(ac);
+       /* Finds out the DN of the old primary group */
 
-done:
-       if (ret != LDB_SUCCESS) {
-               return ldb_module_done(ac->req, NULL, NULL, ret);
+       rid = samdb_result_uint(res->msgs[0], "primaryGroupID", (uint32_t) -1);
+       if (rid == (uint32_t) -1) {
+               /* User objects do always have a mandatory "primaryGroupID"
+                * attribute. If this doesn't exist then the object is of the
+                * wrong type. This is the exact Windows error code */
+               return LDB_ERR_OBJECT_CLASS_VIOLATION;
        }
 
-       return LDB_SUCCESS;
-}
-
-/* Adds a member with DN "member_dn" to a group with DN "group_dn" */
-static int samldb_group_add_member(struct samldb_ctx *ac)
-{
-       struct ldb_context *ldb;
-       struct ldb_request *req;
-       struct ldb_message *msg;
-       int ret;
-
-       ldb = ldb_module_get_ctx(ac->module);
-
-       if ((ac->group_dn == NULL) || (ac->member_dn == NULL))
+       sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
+       if (sid == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       msg = ldb_msg_new(ac);
-       msg->dn = ac->group_dn;
-       samdb_msg_add_addval(ldb, ac, msg, "member",
-               ldb_dn_get_linearized(ac->member_dn));
-
-       ret = ldb_build_mod_req(&req, ldb, ac,
-                               msg, NULL,
-                               ac, samldb_group_add_del_member_callback,
-                               ac->req);
-       if (ret != LDB_SUCCESS)
-               return ret;
-
-       return ldb_next_request(ac->module, req);
-}
-
-/* Removes a member with DN "member_dn" from a group with DN "group_dn" */
-static int samldb_group_del_member(struct samldb_ctx *ac)
-{
-       struct ldb_context *ldb;
-       struct ldb_request *req;
-       struct ldb_message *msg;
-       int ret;
-
-       ldb = ldb_module_get_ctx(ac->module);
-
-       if ((ac->group_dn == NULL) || (ac->member_dn == NULL))
+       prev_prim_group_dn = samdb_search_dn(ldb, ac, NULL, "(objectSID=%s)",
+                                            dom_sid_string(ac, sid));
+       if (prev_prim_group_dn == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       msg = ldb_msg_new(ac);
-       msg->dn = ac->group_dn;
-       samdb_msg_add_delval(ldb, ac, msg, "member",
-               ldb_dn_get_linearized(ac->member_dn));
-
-       ret = ldb_build_mod_req(&req, ldb, ac,
-                               msg, NULL,
-                               ac, samldb_group_add_del_member_callback,
-                               ac->req);
-       if (ret != LDB_SUCCESS)
-               return ret;
-
-       return ldb_next_request(ac->module, req);
-}
-
-
-static int samldb_prim_group_change_1(struct samldb_ctx *ac)
-{
-       struct ldb_context *ldb;
-       uint32_t rid;
-
-       ldb = ldb_module_get_ctx(ac->module);
+       /* Finds out the DN of the new primary group */
 
-       ac->user_dn = ac->msg->dn;
+       rid = samdb_result_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
+       if (rid == (uint32_t) -1) {
+               /* we aren't affected of any primary group change */
+               return ldb_next_request(ac->module, ac->req);
+       }
 
-       rid = samdb_result_uint(ac->msg, "primaryGroupID", ~0);
-       ac->sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
-       if (ac->sid == NULL)
+       sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
+       if (sid == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
-       ac->res_dn = NULL;
-
-       ac->prim_group_rid = 0;
-
-       return samldb_next_step(ac);
-}
-
-static int samldb_prim_group_change_2(struct samldb_ctx *ac)
-{
-       struct ldb_context *ldb;
-
-       ldb = ldb_module_get_ctx(ac->module);
+       }
 
-       if (ac->res_dn != NULL)
-               ac->new_prim_group_dn = ac->res_dn;
-       else
+       new_prim_group_dn = samdb_search_dn(ldb, ac, NULL, "(objectSID=%s)",
+                                           dom_sid_string(ac, sid));
+       if (new_prim_group_dn == NULL) {
+               /* Here we know if the specified new primary group candidate is
+                * valid or not. */
                return LDB_ERR_UNWILLING_TO_PERFORM;
+       }
 
-       ac->sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
-               ac->prim_group_rid);
-       if (ac->sid == NULL)
-               return LDB_ERR_OPERATIONS_ERROR;
-       ac->res_dn = NULL;
-
-       return samldb_next_step(ac);
-}
-
-static int samldb_prim_group_change_4(struct samldb_ctx *ac);
-static int samldb_prim_group_change_5(struct samldb_ctx *ac);
-static int samldb_prim_group_change_6(struct samldb_ctx *ac);
-
-static int samldb_prim_group_change_3(struct samldb_ctx *ac)
-{
-       int ret;
-
-       if (ac->res_dn != NULL)
-               ac->old_prim_group_dn = ac->res_dn;
-       else
+       el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
+                                 ldb_dn_get_linearized(new_prim_group_dn));
+       if (el == NULL) {
+               /* We need to be already a normal member of the new primary
+                * group in order to be successful. */
                return LDB_ERR_UNWILLING_TO_PERFORM;
+       }
 
-       /* Only update when the primary group changed */
-       if (ldb_dn_compare(ac->old_prim_group_dn, ac->new_prim_group_dn) != 0) {
-               ac->member_dn = ac->user_dn;
-               /* Remove the "member" attribute of the actual (new) primary
-                * group */
+       /* Only update the "member" attributes when we really do have a change */
+       if (ldb_dn_compare(new_prim_group_dn, prev_prim_group_dn) != 0) {
+               /* Remove the "member" attribute on the new primary group */
+               msg = talloc_zero(ac, struct ldb_message);
+               msg->dn = new_prim_group_dn;
 
-               ret = samldb_add_step(ac, samldb_prim_group_change_4);
-               if (ret != LDB_SUCCESS) return ret;
+               ret = samdb_msg_add_delval(ldb, ac, msg, "member",
+                                          ldb_dn_get_linearized(ac->msg->dn));
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
 
-               ret = samldb_add_step(ac, samldb_group_del_member);
-               if (ret != LDB_SUCCESS) return ret;
+               ret = dsdb_module_modify(ac->module, msg, 0);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
 
                /* Add a "member" attribute for the previous primary group */
+               msg = talloc_zero(ac, struct ldb_message);
+               msg->dn = prev_prim_group_dn;
 
-               ret = samldb_add_step(ac, samldb_prim_group_change_5);
-               if (ret != LDB_SUCCESS) return ret;
+               ret = samdb_msg_add_addval(ldb, ac, msg, "member",
+                                          ldb_dn_get_linearized(ac->msg->dn));
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
 
-               ret = samldb_add_step(ac, samldb_group_add_member);
-               if (ret != LDB_SUCCESS) return ret;
+               ret = dsdb_module_modify(ac->module, msg, 0);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
        }
 
-       ret = samldb_add_step(ac, samldb_prim_group_change_6);
-       if (ret != LDB_SUCCESS) return ret;
-
-       return samldb_next_step(ac);
-}
-
-static int samldb_prim_group_change_4(struct samldb_ctx *ac)
-{
-       ac->group_dn = ac->new_prim_group_dn;
-
-       return samldb_next_step(ac);
-}
-
-static int samldb_prim_group_change_5(struct samldb_ctx *ac)
-{
-       ac->group_dn = ac->old_prim_group_dn;
-
-       return samldb_next_step(ac);
-}
-
-static int samldb_prim_group_change_6(struct samldb_ctx *ac)
-{
        return ldb_next_request(ac->module, ac->req);
 }
 
-static int samldb_prim_group_change(struct samldb_ctx *ac)
-{
-       int ret;
-
-       /* Finds out the DN of the new primary group */
-
-       ret = samldb_add_step(ac, samldb_prim_group_change_1);
-       if (ret != LDB_SUCCESS) return ret;
-
-       ret = samldb_add_step(ac, samldb_dn_from_sid);
-       if (ret != LDB_SUCCESS) return ret;
-
-       ret = samldb_add_step(ac, samldb_user_dn_to_prim_group_rid);
-       if (ret != LDB_SUCCESS) return ret;
-
-       /* Finds out the DN of the old primary group */
-
-       ret = samldb_add_step(ac, samldb_prim_group_change_2);
-       if (ret != LDB_SUCCESS) return ret;
-
-       ret = samldb_add_step(ac, samldb_dn_from_sid);
-       if (ret != LDB_SUCCESS) return ret;
-
-       ret = samldb_add_step(ac, samldb_prim_group_change_3);
-       if (ret != LDB_SUCCESS) return ret;
-
-       return samldb_first_step(ac);
-}
-
 
 static int samldb_member_check(struct samldb_ctx *ac)
 {