r26638: libndr: Require explicitly specifying iconv_convenience for ndr_struct_push_b...
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
index 12a63590376d6f0e834b55b51b0550bdd632af85..d3beedc689ccb488d1c81f2ef921c19206de0ca9 100644 (file)
@@ -43,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 {
 
@@ -68,6 +69,8 @@ struct class_list {
        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;
@@ -250,7 +253,7 @@ static int objectclass_sort(struct ldb_module *module,
 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");
@@ -271,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;
        }
        
@@ -348,7 +352,7 @@ static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *sch
        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, "objectclass %s is not a valid objectClass in schema", msg->elements[i].name);
+                       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;
@@ -389,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, 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=*)",
@@ -444,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));
@@ -462,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;
                }
 
@@ -602,7 +615,9 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
 
        switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
        case LDB_FLAG_MOD_DELETE:
-               return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
+               if (objectclass_element->num_values == 0) {
+                       return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
+               }
                break;
        case LDB_FLAG_MOD_REPLACE:
        {
@@ -865,6 +880,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) {
@@ -1019,11 +1042,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;
                }
@@ -1056,11 +1080,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;
                }