r12658: Couple of fixes related to shared module builds.
[abartlet/samba.git/.git] / source4 / lib / ldb / modules / schema.c
index 2921bdc68bed6d15d02b37c15fe91f0eb8da064e..9fb2efee30c7d96f093f26beac56ebf1c598aa6e 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    ldb database library
 
-   Copyright (C) Simo Sorce  2004
+   Copyright (C) Simo Sorce  2004-2005
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -34,6 +34,7 @@
 
 #include "includes.h"
 #include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
 #include "ldb/include/ldb_private.h"
 
 #define SCHEMA_FLAG_RESET      0
         check there's only one structrual class (or a chain of structural classes)
 */
 
-struct private_data {
-       const char *error_string;
-};
-
 struct schema_attribute {
        int flags;
        char *name;
@@ -72,28 +69,6 @@ struct schema_structures {
        struct schema_attribute_list optional_attrs;
 };
 
-/* This function embedds the knowledge of aliased names.
-   Currently it handles only dn vs distinguishedNAme as a special case as AD
-   only have this special alias case, in future we should read the schema
-   to find out which names have an alias and check for them */
-static int schema_attr_cmp(const char *attr1, const char *attr2)
-{
-       int ret;
-
-       ret = ldb_attr_cmp(attr1, attr2);
-       if (ret != 0) {
-               if ((ldb_attr_cmp("dn", attr1) == 0) &&
-                   (ldb_attr_cmp("distinguishedName", attr2) == 0)) {
-                       return 0;
-               }
-               if ((ldb_attr_cmp("dn", attr2) == 0) &&
-                   (ldb_attr_cmp("distinguishedName", attr1) == 0)) {
-                       return 0;
-               }
-       }
-       return ret;
-}
-
 static struct schema_attribute *schema_find_attribute(struct schema_attribute_list *list, const char *attr_name)
 {
        unsigned int i;
@@ -108,9 +83,9 @@ static struct schema_attribute *schema_find_attribute(struct schema_attribute_li
 /* get all the attributes and objectclasses found in msg and put them in schema_structure
    attributes go in the entry_attrs structure for later checking
    objectclasses go in the objectclasses structure */
-static int get_msg_attributes(struct schema_structures *ss, const struct ldb_message *msg)
+static int get_msg_attributes(struct schema_structures *ss, const struct ldb_message *msg, int flag_mask)
 {
-       int i, j, k, l;
+       int i, j, anum, cnum;
 
        ss->entry_attrs.attr = talloc_realloc(ss, ss->entry_attrs.attr,
                                              struct schema_attribute,
@@ -119,9 +94,9 @@ static int get_msg_attributes(struct schema_structures *ss, const struct ldb_mes
                return -1;
        }
 
-       for (i = 0, j = ss->entry_attrs.num; i < msg->num_elements; i++) {
+       for (i = 0, anum = ss->entry_attrs.num; i < msg->num_elements; i++) {
 
-               if (schema_attr_cmp(msg->elements[i].name, "objectclass") == 0) {
+               if (ldb_attr_cmp(msg->elements[i].name, "objectclass") == 0) {
 
                        ss->objectclasses.attr = talloc_realloc(ss, ss->objectclasses.attr,
                                                                struct schema_attribute,
@@ -130,42 +105,42 @@ static int get_msg_attributes(struct schema_structures *ss, const struct ldb_mes
                                return -1;
                        }
 
-                       for (k = 0, l = ss->objectclasses.num; k < msg->elements[i].num_values; k++) {
-                               ss->objectclasses.attr[l].name = msg->elements[i].values[k].data;
-                               ss->objectclasses.attr[l].flags = msg->elements[i].flags;
-                               l++;
+                       for (j = 0, cnum = ss->objectclasses.num; j < msg->elements[i].num_values; j++) {
+                               ss->objectclasses.attr[cnum+j].name = (char *)msg->elements[i].values[j].data;
+                               ss->objectclasses.attr[cnum+j].flags = msg->elements[i].flags & flag_mask;
                        }
                        ss->objectclasses.num += msg->elements[i].num_values;
                }
 
-               ss->entry_attrs.attr[j].flags = msg->elements[i].flags;
-               ss->entry_attrs.attr[j].name = talloc_reference(ss->entry_attrs.attr,
+               /* TODO: Check for proper attribute Syntax ! */
+
+               ss->entry_attrs.attr[anum+i].flags = msg->elements[i].flags & flag_mask;
+               ss->entry_attrs.attr[anum+i].name = talloc_reference(ss->entry_attrs.attr,
                                                            msg->elements[i].name);
-               if (ss->entry_attrs.attr[j].name == NULL) {
+               if (ss->entry_attrs.attr[anum+i].name == NULL) {
                        return -1;
                }
-               j++;
        }
        ss->entry_attrs.num += msg->num_elements;
 
        return 0;
 }
 
-static int get_entry_attributes(struct ldb_context *ldb, const char *dn, struct schema_structures *ss)
+static int get_entry_attributes(struct ldb_context *ldb, const struct ldb_dn *dn, struct schema_structures *ss)
 {
-       char *filter = talloc_asprintf(ss, "dn=%s", dn);
-       struct ldb_message **srch;
+       struct ldb_result *srch;
        int ret;
 
-       ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
+       ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &srch);
        if (ret != 1) {
                return ret;
        }
        talloc_steal(ss, srch);
 
-       ret = get_msg_attributes(ss, *srch);
+       /* set flags to 0 as flags on search have undefined values */
+       ret = get_msg_attributes(ss, *(srch->msgs), 0);
        if (ret != 0) {
-               ldb_search_free(ldb, srch);
+               talloc_free(srch);
                return ret;
        }
 
@@ -189,14 +164,15 @@ static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list,
                for (c = 0; c < list->num; c++) {
                        len = strlen(list->attr[c].name);
                        if (len == el->values[i].length) {
-                               if (schema_attr_cmp(list->attr[c].name, el->values[i].data) == 0) {
+                               if (ldb_attr_cmp(list->attr[c].name, 
+                                                (char *)el->values[i].data) == 0) {
                                        found = 1;
                                        break;
                                }
                        }
                }
                if (!found) {
-                       list->attr[j + list->num].name = el->values[i].data;
+                       list->attr[j + list->num].name = (char *)el->values[i].data;
                        list->attr[j + list->num].flags = flags;
                        j++;
                }
@@ -211,8 +187,7 @@ static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list,
    recursively get parent objectlasses attributes */
 static int get_attr_list_recursive(struct ldb_module *module, struct schema_structures *schema_struct)
 {
-       struct private_data *data = (struct private_data *)module->private_data;
-       struct ldb_message **srch;
+       struct ldb_result *srch;
        int i, j;
        int ret;
 
@@ -234,30 +209,37 @@ static int get_attr_list_recursive(struct ldb_module *module, struct schema_stru
                talloc_steal(schema_struct, srch);
 
                if (ret <= 0) {
-                       /* Schema DB Error: Error occurred retrieving Object Class Description */
-                       ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
-                       data->error_string = "Internal error. Error retrieving schema objectclass";
+                       /* Schema DB Error: Error occurred retrieving
+                          Object Class Description */
+                       ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, 
+                                     "Error retrieving Objectclass %s.\n", 
+                                     schema_struct->objectclasses.attr[i].name);
                        return -1;
                }
                if (ret > 1) {
                        /* Schema DB Error: Too Many Records */
-                       ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Too many records found retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
-                       data->error_string = "Internal error. Too many records searching for schema objectclass";
+                       ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, 
+                                     "Too many records found retrieving Objectclass %s.\n", 
+                                     schema_struct->objectclasses.attr[i].name);
                        return -1;
                }
 
                /* Add inherited classes eliminating duplicates */
                /* fill in required_attrs and optional_attrs attribute lists */
-               for (j = 0; j < (*srch)->num_elements; j++) {
+               for (j = 0; j < srch->msgs[0]->num_elements; j++) {
                        int is_aux, is_class;
 
                        is_aux = 0;
                        is_class = 0;
-                       if (schema_attr_cmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
+                       if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "systemAuxiliaryclass") == 0) {
+                               is_aux = SCHEMA_FLAG_AUXILIARY;
+                               is_class = 1;
+                       }
+                       if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "auxiliaryClass") == 0) {
                                is_aux = SCHEMA_FLAG_AUXILIARY;
                                is_class = 1;
                        }
-                       if (schema_attr_cmp((*srch)->elements[j].name, "subClassOf") == 0) {
+                       if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "subClassOf") == 0) {
                                is_class = 1;
                        }
 
@@ -265,28 +247,28 @@ static int get_attr_list_recursive(struct ldb_module *module, struct schema_stru
                                if (add_attribute_uniq(schema_struct,
                                                        &schema_struct->objectclasses,
                                                        is_aux,
-                                                       &(*srch)->elements[j]) != 0) {
+                                                       &srch->msgs[0]->elements[j]) != 0) {
                                        return -1;
                                }
                        } else {
 
-                               if (schema_attr_cmp((*srch)->elements[j].name, "mustContain") == 0 ||
-                                       schema_attr_cmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
+                               if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "mustContain") == 0 ||
+                                       ldb_attr_cmp(srch->msgs[0]->elements[j].name, "SystemMustContain") == 0) {
                                        if (add_attribute_uniq(schema_struct,
                                                                &schema_struct->required_attrs,
                                                                SCHEMA_FLAG_RESET,
-                                                               &(*srch)->elements[j]) != 0) {
+                                                               &srch->msgs[0]->elements[j]) != 0) {
                                                return -1;
                                        }
                                }
 
-                               if (schema_attr_cmp((*srch)->elements[j].name, "mayContain") == 0 ||
-                                   schema_attr_cmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
+                               if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "mayContain") == 0 ||
+                                   ldb_attr_cmp(srch->msgs[0]->elements[j].name, "SystemMayContain") == 0) {
 
                                        if (add_attribute_uniq(schema_struct,
                                                                &schema_struct->optional_attrs,
                                                                SCHEMA_FLAG_RESET,
-                                                               &(*srch)->elements[j]) != 0) {
+                                                               &srch->msgs[0]->elements[j]) != 0) {
                                                return -1;
                                        }
                                }
@@ -297,30 +279,10 @@ static int get_attr_list_recursive(struct ldb_module *module, struct schema_stru
        return 0;
 }
 
-/* close */
-static int schema_close(struct ldb_module *module)
-{
-       return ldb_next_close(module);
-}
-
-/* search */
-static int schema_search(struct ldb_module *module, const char *base,
-                      enum ldb_scope scope, const char *expression,
-                      const char * const *attrs, struct ldb_message ***res)
-{
-       return ldb_next_search(module, base, scope, expression, attrs, res); 
-}
-
-/* search_free */
-static int schema_search_free(struct ldb_module *module, struct ldb_message **res)
-{
-       return ldb_next_search_free(module, res);
-}
-
 /* add_record */
-static int schema_add_record(struct ldb_module *module, const struct ldb_message *msg)
+static int schema_add(struct ldb_module *module, struct ldb_request *req)
 {
-       struct private_data *data = (struct private_data *)module->private_data;
+       const struct ldb_message *msg = req->op.add.message;
        struct schema_structures *entry_structs;
        unsigned int i;
        int ret;
@@ -333,16 +295,19 @@ static int schema_add_record(struct ldb_module *module, const struct ldb_message
                Free all structures and commit the change
        */
 
-       if (msg->dn[0] == '@') { /* do not check on our control entries */
-               return ldb_next_add_record(module, msg);
+       /* do not check on our control entries */
+       if (ldb_dn_is_special(msg->dn)) {
+               return ldb_next_request(module, req);
        }
 
+       /* TODO: check parent exists */
+
        entry_structs = talloc_zero(module, struct schema_structures);
        if (!entry_structs) {
                return -1;
        }
 
-       ret = get_msg_attributes(entry_structs, msg);
+       ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
        if (ret != 0) {
                talloc_free(entry_structs);
                return ret;
@@ -362,25 +327,11 @@ static int schema_add_record(struct ldb_module *module, const struct ldb_message
                                             entry_structs->required_attrs.attr[i].name);
 
                if (attr == NULL) { /* not found */
-                       ldb_debug(module->ldb, LDB_DEBUG_ERROR,
-                                 "The required_attrs attribute %s is missing.\n",
-                                 entry_structs->required_attrs.attr[i].name);
-
-                       data->error_string = "Objectclass violation, a required attribute is missing";
+                       ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, 
+                                     "The required_attrs attribute %s is missing.\n",
+                                     entry_structs->required_attrs.attr[i].name);
                        talloc_free(entry_structs);
-                       return -1;
-               }
-
-               /* check we are not trying to delete a required attribute */
-               /* TODO: consider multivalued attrs */
-               if ((attr->flags & SCHEMA_FLAG_MOD_DELETE) != 0) {
-                       ldb_debug(module->ldb, LDB_DEBUG_ERROR,
-                                 "Trying to delete the required attribute %s.\n",
-                                 attr->name);
-
-                       data->error_string = "Objectclass violation, a required attribute cannot be removed";
-                       talloc_free(entry_structs);
-                       return -1;
+                       return LDB_ERR_OBJECT_CLASS_VIOLATION;
                }
 
                /* mark the attribute as checked */
@@ -397,26 +348,24 @@ static int schema_add_record(struct ldb_module *module, const struct ldb_message
                                                     entry_structs->entry_attrs.attr[i].name);
 
                        if (attr == NULL) { /* not found */
-                               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
-                                         "The attribute %s is not referenced by any objectclass.\n",
-                                         entry_structs->entry_attrs.attr[i].name);
-
-                               data->error_string = "Objectclass violation, an invalid attribute name was found";
+                               ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, 
+                                             "The attribute %s is not referenced by any objectclass.\n",
+                                             entry_structs->entry_attrs.attr[i].name);
                                talloc_free(entry_structs);
-                               return -1;
+                               return LDB_ERR_OBJECT_CLASS_VIOLATION;
                        }
                }
        }
 
        talloc_free(entry_structs);
 
-       return ldb_next_add_record(module, msg);
+       return ldb_next_request(module, req);
 }
 
 /* modify_record */
-static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
+static int schema_modify(struct ldb_module *module, struct ldb_request *req)
 {
-       struct private_data *data = (struct private_data *)module->private_data;
+       const struct ldb_message *msg = req->op.mod.message;
        struct schema_structures *entry_structs;
        unsigned int i;
        int ret;
@@ -430,8 +379,9 @@ static int schema_modify_record(struct ldb_module *module, const struct ldb_mess
                Free all structures and commit the change.
        */
 
-       if (msg->dn[0] == '@') { /* do not check on our control entries */
-               return ldb_next_modify_record(module, msg);
+       /* do not check on our control entries */
+       if (ldb_dn_is_special(msg->dn)) {
+               return ldb_next_request(module, req);
        }
 
        /* allocate object structs */
@@ -448,7 +398,7 @@ static int schema_modify_record(struct ldb_module *module, const struct ldb_mess
        }
 
        /* get list of values to modify */
-       ret = get_msg_attributes(entry_structs, msg);
+       ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
        if (ret != 0) {
                talloc_free(entry_structs);
                return ret;
@@ -468,13 +418,21 @@ static int schema_modify_record(struct ldb_module *module, const struct ldb_mess
                                             entry_structs->required_attrs.attr[i].name);
 
                if (attr == NULL) { /* not found */
-                       ldb_debug(module->ldb, LDB_DEBUG_ERROR,
-                                 "The required_attrs attribute %s is missing.\n",
-                                 entry_structs->required_attrs.attr[i].name);
+                       ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, 
+                                     "The required_attrs attribute %s is missing.\n",
+                                     entry_structs->required_attrs.attr[i].name);
+                       talloc_free(entry_structs);
+                       return LDB_ERR_OBJECT_CLASS_VIOLATION;
+               }
 
-                       data->error_string = "Objectclass violation, a required attribute is missing";
+               /* check we are not trying to delete a required attribute */
+               /* TODO: consider multivalued attrs */
+               if ((attr->flags & SCHEMA_FLAG_MOD_DELETE) != 0) {
+                       ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, 
+                                     "Trying to delete the required attribute %s.\n",
+                                     attr->name);
                        talloc_free(entry_structs);
-                       return -1;
+                       return LDB_ERR_OBJECT_CLASS_VIOLATION;
                }
 
                /* mark the attribute as checked */
@@ -491,95 +449,51 @@ static int schema_modify_record(struct ldb_module *module, const struct ldb_mess
                                                     entry_structs->entry_attrs.attr[i].name);
 
                        if (attr == NULL) { /* not found */
-                               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
-                                         "The attribute %s is not referenced by any objectclass.\n",
-                                         entry_structs->entry_attrs.attr[i].name);
-
-                               data->error_string = "Objectclass violation, an invalid attribute name was found";
+                               ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, 
+                                             "The attribute %s is not referenced by any objectclass.\n",
+                                             entry_structs->entry_attrs.attr[i].name);
                                talloc_free(entry_structs);
-                               return -1;
+                               return LDB_ERR_OBJECT_CLASS_VIOLATION;
                        }
                }
        }
 
        talloc_free(entry_structs);
 
-       return ldb_next_modify_record(module, msg);
+       return ldb_next_request(module, req);
 }
 
-/* delete_record */
-static int schema_delete_record(struct ldb_module *module, const char *dn)
+static int schema_request(struct ldb_module *module, struct ldb_request *req)
 {
-/*     struct private_data *data = (struct private_data *)module->private_data; */
-       return ldb_next_delete_record(module, dn);
-}
-
-/* rename_record */
-static int schema_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
-{
-       return ldb_next_rename_record(module, olddn, newdn);
-}
-
-static int schema_named_lock(struct ldb_module *module, const char *name) {
-       return ldb_next_named_lock(module, name);
-}
+       switch (req->operation) {
 
-static int schema_named_unlock(struct ldb_module *module, const char *name) {
-       return ldb_next_named_unlock(module, name);
-}
+       case LDB_REQ_ADD:
+               return schema_add(module, req);
 
-/* return extended error information */
-static const char *schema_errstring(struct ldb_module *module)
-{
-       struct private_data *data = (struct private_data *)module->private_data;
+       case LDB_REQ_MODIFY:
+               return schema_modify(module, req);
 
-       if (data->error_string) {
-               const char *error;
+       default:
+               return ldb_next_request(module, req);
 
-               error = data->error_string;
-               data->error_string = NULL;
-               return error;
        }
-
-       return ldb_next_errstring(module);
 }
 
 static const struct ldb_module_ops schema_ops = {
-       "schema",
-       schema_close, 
-       schema_search,
-       schema_search_free,
-       schema_add_record,
-       schema_modify_record,
-       schema_delete_record,
-       schema_rename_record,
-       schema_named_lock,
-       schema_named_unlock,
-       schema_errstring,
+       .name              = "schema",
+       .request           = schema_request
 };
 
-#ifdef HAVE_DLOPEN_DISABLED
-struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
-#else
 struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
-#endif
 {
        struct ldb_module *ctx;
-       struct private_data *data;
 
        ctx = talloc(ldb, struct ldb_module);
        if (!ctx) {
                return NULL;
        }
 
-       data = talloc(ctx, struct private_data);
-       if (data == NULL) {
-               talloc_free(ctx);
-               return NULL;
-       }
-
-       data->error_string = NULL;
-       ctx->private_data = data;
+       ctx->private_data = NULL;
        ctx->ldb = ldb;
        ctx->prev = ctx->next = NULL;
        ctx->ops = &schema_ops;