Rework linked_attributes to use seperate callbacks per operation type
authorAndrew Bartlett <abartlet@samba.org>
Mon, 1 Dec 2008 03:35:57 +0000 (14:35 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 1 Dec 2008 03:35:57 +0000 (14:35 +1100)
Andrew Bartlett

source4/dsdb/samdb/ldb_modules/linked_attributes.c

index 61743eaa6b124285a898167145818d3a18835bc6..46a1aec4859a03dcfc94f90c5df9f4d7c2820be6 100644 (file)
@@ -57,6 +57,8 @@ struct la_context {
        struct replace_context *rc;
        struct la_op_store *ops;
        struct la_op_store *cur;
+       struct ldb_extended *op_response;
+       struct ldb_control **op_controls;
 };
 
 static struct la_context *linked_attributes_init(struct ldb_module *module,
@@ -125,8 +127,6 @@ static int la_do_mod_request(struct la_context *ac);
 static int la_mod_callback(struct ldb_request *req,
                           struct ldb_reply *ares);
 static int la_down_req(struct la_context *ac);
-static int la_down_callback(struct ldb_request *req,
-                           struct ldb_reply *ares);
 
 
 
@@ -719,8 +719,15 @@ static int la_op_search_callback(struct ldb_request *req,
                        }
                        break;
                case LDB_RENAME:
-                       /* If we have modfies to make, then run them */
-                       return la_do_mod_request(ac);
+                       
+                       ret = la_do_mod_request(ac);
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req, NULL, NULL,
+                                                      ret);
+                       }
+       
+                       return ret;
+                       
                default:
                        talloc_free(ares);
                        return ldb_module_done(ac->req, NULL, NULL,
@@ -742,6 +749,12 @@ static int la_do_mod_request(struct la_context *ac)
        struct ldb_context *ldb;
        int ret;
 
+       /* If we have no modifies in the queue, we are done! */
+       if (!ac->ops) {
+               return ldb_module_done(ac->req, ac->op_controls,
+                                      ac->op_response, LDB_SUCCESS);
+       }
+
        ldb = ac->module->ldb;
 
        /* Create the modify request */
@@ -801,7 +814,6 @@ static int la_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct la_context *ac;
        struct la_op_store *os;
-       int ret;
 
        ac = talloc_get_type(req->context, struct la_context);
 
@@ -833,68 +845,115 @@ static int la_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
                talloc_free(os);
        }
 
-       /* If we still have modifies in the queue, then run them */
-       if (ac->ops) {
-               ret = la_do_mod_request(ac);
-       } else {
-               /* Otherwise, we are done! */
-               ret = ldb_module_done(ac->req, ares->controls,
-                                     ares->response, ares->error);
+       return la_do_mod_request(ac);
+}
+
+/* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
+static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       int ret;
+       struct la_context *ac;
+       ac = talloc_get_type(req->context, struct la_context);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
        }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(ac->module->ldb,
+                                 "invalid ldb_reply_type in callback");
+               talloc_free(ares);
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       
+       ac->op_controls = talloc_steal(ac, ares->controls);
+       ac->op_response = talloc_steal(ac, ares->response);
 
+       /* If we have modfies to make, this is the time to do them for modify and delete */
+       ret = la_do_mod_request(ac);
+       
        if (ret != LDB_SUCCESS) {
                return ldb_module_done(ac->req, NULL, NULL, ret);
        }
+       talloc_free(ares);
+
+       /* la_do_mod_request has already sent the callbacks */
        return LDB_SUCCESS;
+
 }
 
-static int la_down_req(struct la_context *ac)
+/* Having done the original rename try to fix up all the linked attributes */
+static int la_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
-       struct ldb_request *down_req;
        int ret;
+       struct la_context *ac;
+       struct ldb_request *search_req;
+       const char **attrs;
+       WERROR werr;
+       ac = talloc_get_type(req->context, struct la_context);
 
-       switch (ac->req->operation) {
-       case LDB_ADD:
-               ret = ldb_build_add_req(&down_req, ac->module->ldb, ac,
-                                       ac->req->op.add.message,
-                                       ac->req->controls,
-                                       ac, la_down_callback,
-                                       ac->req);
-               break;
-       case LDB_MODIFY:
-               ret = ldb_build_mod_req(&down_req, ac->module->ldb, ac,
-                                       ac->req->op.mod.message,
-                                       ac->req->controls,
-                                       ac, la_down_callback,
-                                       ac->req);
-               break;
-       case LDB_DELETE:
-               ret = ldb_build_del_req(&down_req, ac->module->ldb, ac,
-                                       ac->req->op.del.dn,
-                                       ac->req->controls,
-                                       ac, la_down_callback,
-                                       ac->req);
-               break;
-       case LDB_RENAME:
-               ret = ldb_build_rename_req(&down_req, ac->module->ldb, ac,
-                                          ac->req->op.rename.olddn,
-                                          ac->req->op.rename.newdn,
-                                          ac->req->controls,
-                                          ac, la_down_callback,
-                                          ac->req);
-               break;
-       default:
-               ret = LDB_ERR_OPERATIONS_ERROR;
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
        }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(ac->module->ldb,
+                                 "invalid ldb_reply_type in callback");
+               talloc_free(ares);
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       
+       werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
+       if (!W_ERROR_IS_OK(werr)) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       ret = ldb_build_search_req(&search_req, ac->module->ldb, req,
+                                  ac->req->op.rename.newdn, LDB_SCOPE_BASE,
+                                  "(objectClass=*)", attrs,
+                                  NULL,
+                                  ac, la_op_search_callback,
+                                  req);
+       
        if (ret != LDB_SUCCESS) {
                return ret;
        }
+               
+       talloc_steal(search_req, attrs);
 
-       return ldb_next_request(ac->module, down_req);
+       if (ret == LDB_SUCCESS) {
+               ret = ldb_request_add_control(search_req,
+                                             LDB_CONTROL_EXTENDED_DN_OID,
+                                             false, NULL);
+       }
+       if (ret != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                      ret);
+       }
+       
+       ac->op_controls = talloc_steal(ac, ares->controls);
+       ac->op_response = talloc_steal(ac, ares->response);
+
+       return ldb_next_request(ac->module, search_req);
 }
 
-/* Having done the original operation, then try to fix up all the linked attributes */
-static int la_down_callback(struct ldb_request *req, struct ldb_reply *ares)
+/* Having done the original add, then try to fix up all the linked attributes
+
+  This is done after the add so the links can get the extended DNs correctly.
+ */
+static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        int ret;
        struct la_context *ac;
@@ -919,51 +978,18 @@ static int la_down_callback(struct ldb_request *req, struct ldb_reply *ares)
        
        if (ac->ops) {
                struct ldb_request *search_req;
-               if (ac->req->operation == LDB_ADD) {
-                       static const char *attrs[] = { NULL };
-                       
-                       /* The callback does all the hard work here - we need
-                        * the objectGUID and SID of the added record */
-                       ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
-                                                  ac->req->op.add.message->dn,
-                                                  LDB_SCOPE_BASE,
-                                                  "(objectClass=*)", attrs,
-                                                  NULL,
-                                                  ac, la_mod_search_callback,
-                                                  ac->req);
-                       
-               } else if (ac->req->operation == LDB_RENAME) {
-                       const char **attrs;
-                       WERROR werr;
-                       werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
-                       if (!W_ERROR_IS_OK(werr)) {
-                               return LDB_ERR_OPERATIONS_ERROR;
-                       }
-                       
-                       ret = ldb_build_search_req(&search_req, ac->module->ldb, req,
-                                                  ac->req->op.rename.newdn, LDB_SCOPE_BASE,
-                                                  "(objectClass=*)", attrs,
-                                                  NULL,
-                                                  ac, la_op_search_callback,
-                                                  req);
-                       
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
-                       
-                       talloc_steal(search_req, attrs);
-                       
-                       
-               } else {
-                       /* If we have modfies to make, this is the time to do them for modify and delete */
-                       ret = la_do_mod_request(ac);
-
-                       if (ret != LDB_SUCCESS) {
-                               return ldb_module_done(ac->req, NULL, NULL,
-                                                      ret);
-                       }
-                       return LDB_SUCCESS;
-               }
+               static const char *attrs[] = { NULL };
+               
+               /* The callback does all the hard work here - we need
+                * the objectGUID and SID of the added record */
+               ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
+                                          ac->req->op.add.message->dn,
+                                          LDB_SCOPE_BASE,
+                                          "(objectClass=*)", attrs,
+                                          NULL,
+                                          ac, la_mod_search_callback,
+                                          ac->req);
+               
                if (ret == LDB_SUCCESS) {
                        ret = ldb_request_add_control(search_req,
                                                      LDB_CONTROL_EXTENDED_DN_OID,
@@ -973,13 +999,65 @@ static int la_down_callback(struct ldb_request *req, struct ldb_reply *ares)
                        return ldb_module_done(ac->req, NULL, NULL,
                                               ret);
                }
+
+               ac->op_controls = talloc_steal(ac, ares->controls);
+               ac->op_response = talloc_steal(ac, ares->response);
+
                return ldb_next_request(ac->module, search_req);
+               
        } else {
                return ldb_module_done(ac->req, ares->controls,
                                       ares->response, ares->error);
        }
 }
 
+/* Reconstruct the original request, but pointing at our local callback to finish things off */
+static int la_down_req(struct la_context *ac)
+{
+       struct ldb_request *down_req;
+       int ret;
+
+       switch (ac->req->operation) {
+       case LDB_ADD:
+               ret = ldb_build_add_req(&down_req, ac->module->ldb, ac,
+                                       ac->req->op.add.message,
+                                       ac->req->controls,
+                                       ac, la_add_callback,
+                                       ac->req);
+               break;
+       case LDB_MODIFY:
+               ret = ldb_build_mod_req(&down_req, ac->module->ldb, ac,
+                                       ac->req->op.mod.message,
+                                       ac->req->controls,
+                                       ac, la_mod_del_callback,
+                                       ac->req);
+               break;
+       case LDB_DELETE:
+               ret = ldb_build_del_req(&down_req, ac->module->ldb, ac,
+                                       ac->req->op.del.dn,
+                                       ac->req->controls,
+                                       ac, la_mod_del_callback,
+                                       ac->req);
+               break;
+       case LDB_RENAME:
+               ret = ldb_build_rename_req(&down_req, ac->module->ldb, ac,
+                                          ac->req->op.rename.olddn,
+                                          ac->req->op.rename.newdn,
+                                          ac->req->controls,
+                                          ac, la_rename_callback,
+                                          ac->req);
+               break;
+       default:
+               ret = LDB_ERR_OPERATIONS_ERROR;
+       }
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       return ldb_next_request(ac->module, down_req);
+}
+
+
 _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = {
        .name              = "linked_attributes",
        .add               = linked_attributes_add,