ranged_results: fix use of uninitialised variable (end)
[jelmer/samba4-debian.git] / source / dsdb / samdb / ldb_modules / objectclass.c
index 14dbe3b3135f2f955f1033aa644b2e68dca1a2f1..737475ca78b24693bcfb7fd82e6a01b5a7fd9e40 100644 (file)
  *
  *  Component: objectClass sorting module
  *
- *  Description: sort the objectClass attribute into the class hierarchy
+ *  Description: 
+ *  - sort the objectClass attribute into the class
+ *    hierarchy, 
+ *  - fix DNs and attributes into 'standard' case
+ *  - Add objectCategory and ntSecurityDescriptor defaults
  *
  *  Author: Andrew Bartlett
  */
@@ -39,6 +43,7 @@
 #include "librpc/gen_ndr/ndr_security.h"
 #include "libcli/security/security.h"
 #include "auth/auth.h"
+#include "param/param.h"
 
 struct oc_context {
 
@@ -61,9 +66,11 @@ struct oc_context {
 
 struct class_list {
        struct class_list *prev, *next;
-       const char *objectclass;
+       const struct dsdb_class *objectclass;
 };
 
+static int objectclass_do_add(struct ldb_handle *h);
+
 static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
 {
        struct oc_context *ac;
@@ -95,7 +102,12 @@ static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_mod
        return h;
 }
 
+/* Sort objectClasses into correct order, and validate that all
+ * objectClasses specified actually exist in the schema
+ */
+
 static int objectclass_sort(struct ldb_module *module,
+                           const struct dsdb_schema *schema,
                            struct ldb_message *msg, /* so that when we create new elements, we put it on the right parent */
                            TALLOC_CTX *mem_ctx,
                            struct ldb_message_element *objectclass_element,
@@ -103,7 +115,6 @@ static int objectclass_sort(struct ldb_module *module,
 {
        int i;
        int layer;
-       const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
        struct class_list *sorted = NULL, *parent_class = NULL,
                *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent;
        /* DESIGN:
@@ -143,11 +154,15 @@ static int objectclass_sort(struct ldb_module *module,
                        talloc_free(mem_ctx);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
-               current->objectclass = (const char *)objectclass_element->values[i].data;
+               current->objectclass = dsdb_class_by_lDAPDisplayName(schema, (const char *)objectclass_element->values[i].data);
+               if (!current->objectclass) {
+                       ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in schema", (const char *)objectclass_element->values[i].data);
+                       return LDB_ERR_OBJECT_CLASS_VIOLATION;
+               }
 
                /* this is the root of the tree.  We will start
                 * looking for subclasses from here */
-               if (ldb_attr_cmp("top", current->objectclass) == 0) {
+               if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) {
                        DLIST_ADD_END(parent_class, current, struct class_list *);
                } else {
                        DLIST_ADD_END(unsorted, current, struct class_list *);
@@ -156,29 +171,24 @@ static int objectclass_sort(struct ldb_module *module,
 
        if (parent_class == NULL) {
                current = talloc(mem_ctx, struct class_list);
-               current->objectclass = talloc_strdup(msg, "top");
+               current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
                DLIST_ADD_END(parent_class, current, struct class_list *);
        }
 
        /* For each object:  find parent chain */
        for (current = unsorted; schema && current; current = current->next) {
-               const struct dsdb_class *class = dsdb_class_by_lDAPDisplayName(schema, current->objectclass);
-               if (!class) {
-                       ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in schema", current->objectclass);
-                       return LDB_ERR_OBJECT_CLASS_VIOLATION;
-               }
                for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
-                       if (ldb_attr_cmp(poss_parent->objectclassclass->subClassOf) == 0) {
+                       if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
                                break;
                        }
                }
                /* If we didn't get to the end of the list, we need to add this parent */
-               if (poss_parent || (ldb_attr_cmp("top", class->subClassOf) == 0)) {
+               if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
                        continue;
                }
 
                new_parent = talloc(mem_ctx, struct class_list);
-               new_parent->objectclass = talloc_strdup(msg, class->subClassOf);
+               new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
                DLIST_ADD_END(unsorted, new_parent, struct class_list *);
        }
 
@@ -193,13 +203,12 @@ static int objectclass_sort(struct ldb_module *module,
                for (current = parent_class; schema && unsorted && current; current = current->next) {
                        /* Walk the list of possible subclasses in unsorted */
                        for (poss_subclass = unsorted; poss_subclass; ) {
-                               const struct dsdb_class *class = dsdb_class_by_lDAPDisplayName(schema, poss_subclass->objectclass);
                                struct class_list *next;
                                
                                /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
                                next = poss_subclass->next;
 
-                               if (class && ldb_attr_cmp(class->subClassOf, current->objectclass) == 0) {
+                               if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) {
                                        DLIST_REMOVE(unsorted, poss_subclass);
                                        DLIST_ADD(subclass, poss_subclass);
                                        
@@ -237,14 +246,14 @@ static int objectclass_sort(struct ldb_module *module,
         * was no 'top', a conflict in the objectClasses or some other
         * schema error?
         */
-       ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass);
+       ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
        return LDB_ERR_OBJECT_CLASS_VIOLATION;
 }
 
 static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, 
                         const struct dsdb_class *objectclass) 
 {
-       NTSTATUS status;
+       enum ndr_err_code ndr_err;
        DATA_BLOB *linear_sd;
        struct auth_session_info *session_info
                = ldb_get_opaque(module->ldb, "sessionInfo");
@@ -265,10 +274,11 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       status = ndr_push_struct_blob(linear_sd, mem_ctx, sd, 
-                                     (ndr_push_flags_fn_t)ndr_push_security_descriptor);
-
-       if (!NT_STATUS_IS_OK(status)) {
+       ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, 
+                                       lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
+                                      sd,
+                                      (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                return NULL;
        }
        
@@ -335,6 +345,22 @@ static int fix_dn(TALLOC_CTX *mem_ctx,
                                    *ldb_dn_get_rdn_val(newdn));
 }
 
+/* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
+static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg) 
+{
+       int i;
+       for (i=0; i < msg->num_elements; i++) {
+               const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
+               if (!attribute) {
+                       ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
+                       return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
+               }
+               msg->elements[i].name = attribute->lDAPDisplayName;
+       }
+
+       return LDB_SUCCESS;
+}
+
 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
 {
 
@@ -367,11 +393,17 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
        /* return or own handle to deal with this call */
        req->handle = h;
 
-       parent_dn = ldb_dn_get_parent(ac->search_req, ac->orig_req->op.mod.message->dn);
+       /* If there isn't a parent, just go on to the add processing */
+       if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) == 1) {
+               return objectclass_do_add(h);
+       }
+
+       parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.add.message->dn);
        if (parent_dn == NULL) {
                ldb_oom(module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
+
        ret = ldb_build_search_req(&ac->search_req, module->ldb,
                                   ac, parent_dn, LDB_SCOPE_BASE,
                                   "(objectClass=*)",
@@ -381,6 +413,8 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
                return ret;
        }
 
+       talloc_steal(ac->search_req, parent_dn);
+
        ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
 
        ac->step = OC_SEARCH_ADD_PARENT;
@@ -420,10 +454,11 @@ static int objectclass_do_add(struct ldb_handle *h)
        
        /* Check we have a valid parent */
        if (ac->search_res == NULL) {
-               if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) <= 1) {
-                       /* Allow cn=rootdse and cn=templates for now... */
-               } else if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) {
+               if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) {
                        /* Allow the tree to be started */
+                       
+                       /* but don't keep any error string, it's meaningless */
+                       ldb_set_errstring(ac->module->ldb, NULL);
                } else {
                        ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!", 
                                               ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
@@ -438,6 +473,8 @@ static int objectclass_do_add(struct ldb_handle *h)
                             &msg->dn);
 
                if (ret != LDB_SUCCESS) {
+                       ldb_asprintf_errstring(ac->module->ldb, "Could not munge DN %s into normal form", 
+                                              ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
                        return ret;
                }
 
@@ -447,53 +484,60 @@ static int objectclass_do_add(struct ldb_handle *h)
 
        }
 
-       /* This is now the objectClass list from the database */
-       objectclass_element = ldb_msg_find_element(msg, "objectClass");
-
-       if (!objectclass_element) {
-               /* Where did it go?  bail now... */
-               talloc_free(mem_ctx);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       ret = objectclass_sort(ac->module, msg, mem_ctx, objectclass_element, &sorted);
-       if (ret != LDB_SUCCESS) {
-               talloc_free(mem_ctx);
-               return ret;
-       }
-
-       ldb_msg_remove_attr(msg, "objectClass");
-       ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
-       
-       if (ret != LDB_SUCCESS) {
-               talloc_free(mem_ctx);
-               return ret;
-       }
-
-       /* We must completely replace the existing objectClass entry,
-        * because we need it sorted */
+       if (schema) {
+               ret = fix_attributes(ac->module->ldb, schema, msg);
+               if (ret != LDB_SUCCESS) {
+                       talloc_free(mem_ctx);
+                       return ret;
+               }
 
-       /* Move from the linked list back into an ldb msg */
-       for (current = sorted; current; current = current->next) {
-               ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
+               /* This is now the objectClass list from the database */
+               objectclass_element = ldb_msg_find_element(msg, "objectClass");
+               
+               if (!objectclass_element) {
+                       /* Where did it go?  bail now... */
+                       talloc_free(mem_ctx);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
+               if (ret != LDB_SUCCESS) {
+                       talloc_free(mem_ctx);
+                       return ret;
+               }
+               
+               ldb_msg_remove_attr(msg, "objectClass");
+               ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
+               
                if (ret != LDB_SUCCESS) {
-                       ldb_set_errstring(ac->module->ldb, 
-                                         "objectclass: could not re-add sorted "
-                                         "objectclass to modify msg");
                        talloc_free(mem_ctx);
                        return ret;
                }
-               /* Last one is the critical one */
-               if (schema && !current->next) {
-                       const struct dsdb_class *objectclass
-                               = dsdb_class_by_lDAPDisplayName(schema, 
-                                                               current->objectclass);
-                       if (objectclass) {
+               
+               /* We must completely replace the existing objectClass entry,
+                * because we need it sorted */
+               
+               /* Move from the linked list back into an ldb msg */
+               for (current = sorted; current; current = current->next) {
+                       ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
+                       if (ret != LDB_SUCCESS) {
+                               ldb_set_errstring(ac->module->ldb, 
+                                                 "objectclass: could not re-add sorted "
+                                                 "objectclass to modify msg");
+                               talloc_free(mem_ctx);
+                               return ret;
+                       }
+                       /* Last one is the critical one */
+                       if (!current->next) {
                                if (!ldb_msg_find_element(msg, "objectCategory")) {
                                        ldb_msg_add_string(msg, "objectCategory", 
-                                                          objectclass->defaultObjectCategory);
+                                                          current->objectclass->defaultObjectCategory);
+                               }
+                               if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
+                                       ldb_msg_add_string(msg, "showInAdvancedViewOnly", 
+                                                          "TRUE");
                                }
                                if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) {
-                                       DATA_BLOB *sd = get_sd(ac->module, mem_ctx, objectclass);
+                                       DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass);
                                        ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd);
                                }
                        }
@@ -503,6 +547,7 @@ static int objectclass_do_add(struct ldb_handle *h)
        talloc_free(mem_ctx);
        ret = ldb_msg_sanity_check(ac->module->ldb, msg);
 
+
        if (ret != LDB_SUCCESS) {
                return ret;
        }
@@ -520,6 +565,9 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
 {
        struct ldb_message_element *objectclass_element;
        struct ldb_message *msg;
+       const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
+       int ret;
+
        ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
 
        /* do not manipulate our control entries */
@@ -527,21 +575,52 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
                return ldb_next_request(module, req);
        }
        
+       /* Without schema, there isn't much to do here */
+       if (!schema) {
+               return ldb_next_request(module, req);
+       }
        objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
 
        /* If no part of this touches the objectClass, then we don't
         * need to make any changes.  */
-       /* If the only operation is the deletion of the objectClass then go on */
+
+       /* If the only operation is the deletion of the objectClass
+        * then go on with just fixing the attribute case */
        if (!objectclass_element) {
-               return ldb_next_request(module, req);
+               struct ldb_request *down_req = talloc(req, struct ldb_request);
+               if (down_req == NULL) {
+                       ldb_set_errstring(module->ldb, "Out of memory!");
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               
+               *down_req = *req; /* copy the request */
+               
+               down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
+               
+               if (down_req->op.mod.message == NULL) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               
+               ret = fix_attributes(module->ldb, schema, msg);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+
+               /* go on with the call chain */
+               ret = ldb_next_request(module, down_req);
+               
+               /* do not free down_req as the call results may be linked to it,
+                * it will be freed when the upper level request get freed */
+               if (ret == LDB_SUCCESS) {
+                       req->handle = down_req->handle;
+               }
+               return ret;
        }
 
        switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
        case LDB_FLAG_MOD_DELETE:
-               /* Delete everything?  Probably totally illigal, but hey! */
                if (objectclass_element->num_values == 0) {
-                       
-                       return ldb_next_request(module, req);
+                       return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
                }
                break;
        case LDB_FLAG_MOD_REPLACE:
@@ -549,7 +628,6 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
                struct ldb_request *down_req;
                struct class_list *sorted, *current;
                TALLOC_CTX *mem_ctx;
-               int ret;
                mem_ctx = talloc_new(req);
                if (mem_ctx == NULL) {
                        return LDB_ERR_OPERATIONS_ERROR;
@@ -567,12 +645,18 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
                
                down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
                
-               if (down_req->op.add.message == NULL) {
+               if (down_req->op.mod.message == NULL) {
                        talloc_free(mem_ctx);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
                
-               ret = objectclass_sort(module, msg, mem_ctx, objectclass_element, &sorted);
+               ret = fix_attributes(module->ldb, schema, msg);
+               if (ret != LDB_SUCCESS) {
+                       talloc_free(mem_ctx);
+                       return ret;
+               }
+
+               ret = objectclass_sort(module, schema, msg, mem_ctx, objectclass_element, &sorted);
                if (ret != LDB_SUCCESS) {
                        return ret;
                }
@@ -590,7 +674,7 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
 
                /* Move from the linked list back into an ldb msg */
                for (current = sorted; current; current = current->next) {
-                       ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
+                       ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
                        if (ret != LDB_SUCCESS) {
                                ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
                                talloc_free(mem_ctx);
@@ -638,12 +722,25 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
                /* prepare the first operation */
                ac->down_req = talloc(ac, struct ldb_request);
                if (ac->down_req == NULL) {
-                       ldb_set_errstring(module->ldb, "Out of memory!");
+                       ldb_oom(ac->module->ldb);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
                
                *(ac->down_req) = *req; /* copy the request */
                
+               ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
+               
+               if (ac->down_req->op.mod.message == NULL) {
+                       ldb_oom(ac->module->ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               
+               ret = fix_attributes(ac->module->ldb, schema, msg);
+               if (ret != LDB_SUCCESS) {
+                       ldb_oom(ac->module->ldb);
+                       return ret;
+               }
+
                ac->down_req->context = NULL;
                ac->down_req->callback = NULL;
                ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
@@ -681,6 +778,7 @@ static int objectclass_search_self(struct ldb_handle *h)
 
 static int objectclass_do_mod(struct ldb_handle *h) {
 
+       const struct dsdb_schema *schema;
        struct oc_context *ac;
        struct ldb_message_element *objectclass_element;
        struct ldb_message *msg;
@@ -689,6 +787,7 @@ static int objectclass_do_mod(struct ldb_handle *h) {
        int ret;
       
        ac = talloc_get_type(h->private_data, struct oc_context);
+       schema = dsdb_get_schema(ac->module->ldb);
 
        mem_ctx = talloc_new(ac);
        if (mem_ctx == NULL) {
@@ -727,7 +826,7 @@ static int objectclass_do_mod(struct ldb_handle *h) {
        /* modify dn */
        msg->dn = ac->orig_req->op.mod.message->dn;
 
-       ret = objectclass_sort(ac->module, msg, mem_ctx, objectclass_element, &sorted);
+       ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
@@ -745,7 +844,7 @@ static int objectclass_do_mod(struct ldb_handle *h) {
        
        /* Move from the linked list back into an ldb msg */
        for (current = sorted; current; current = current->next) {
-               ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
+               ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
                if (ret != LDB_SUCCESS) {
                        ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
                        talloc_free(mem_ctx);
@@ -785,6 +884,14 @@ static int objectclass_rename(struct ldb_module *module, struct ldb_request *req
        if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
                return ldb_next_request(module, req);
        }
+       
+       /* Firstly ensure we are not trying to rename it to be a child of itself */
+       if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
+           && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
+               ldb_asprintf_errstring(module->ldb, "Cannot rename %s to be a child of itself",
+                                      ldb_dn_get_linearized(req->op.rename.olddn));
+               return LDB_ERR_UNWILLING_TO_PERFORM;
+       }
 
        h = oc_init_handle(req, module);
        if (!h) {
@@ -795,7 +902,7 @@ static int objectclass_rename(struct ldb_module *module, struct ldb_request *req
        /* return or own handle to deal with this call */
        req->handle = h;
 
-       parent_dn = ldb_dn_get_parent(ac->search_req, ac->orig_req->op.rename.newdn);
+       parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.rename.newdn);
        if (parent_dn == NULL) {
                ldb_oom(module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
@@ -808,7 +915,7 @@ static int objectclass_rename(struct ldb_module *module, struct ldb_request *req
        if (ret != LDB_SUCCESS) {
                return ret;
        }
-
+       talloc_steal(ac->search_req, parent_dn);
        ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
 
        ac->step = OC_SEARCH_RENAME_PARENT;
@@ -939,11 +1046,12 @@ static int oc_wait(struct ldb_handle *handle) {
        case OC_SEARCH_ADD_PARENT:
                ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
 
-               if (ret != LDB_SUCCESS) {
+               if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ret;
                        goto done;
                }
-               if (ac->search_req->handle->status != LDB_SUCCESS) {
+               if (ac->search_req->handle->status != LDB_SUCCESS
+                   && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ac->search_req->handle->status;
                        goto done;
                }
@@ -976,11 +1084,11 @@ static int oc_wait(struct ldb_handle *handle) {
        case OC_SEARCH_RENAME_PARENT:
                ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
 
-               if (ret != LDB_SUCCESS) {
+               if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ret;
                        goto done;
                }
-               if (ac->search_req->handle->status != LDB_SUCCESS) {
+               if (ac->search_req->handle->status != LDB_SUCCESS && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
                        handle->status = ac->search_req->handle->status;
                        goto done;
                }