/*
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
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_private.h"
-struct attribute_syntax {
- const char *name;
- const char *syntax_id;
-};
-
-static struct attribute_syntax attrsyn[] = {
- { "Object(DS-DN)", "2.5.5.1"},
- { "String(Object-Identifier)", "2.5.5.2"},
- { "", "2.5.5.3"},
- { "String(Teletex)", "2.5.5.4"},
- { "String(IA5)", "2.5.5.5"}, /* Also String(Printable) */
- { "String(Numeric)", "2.5.5.6"},
- { "Object(DN-Binary)", "2.5.5.7"}, /* Also Object(OR-Name) */
- { "Boolean", "2.5.5.8"},
- { "Integer", "2.5.5.9"}, /* Also Enumeration (3 types ?) ... */
- { "String(Octet)", "2.5.5.10"}, /* Also Object(Replica-Link) */
- { "String(UTC-Time)", "2.5.5.11"}, /* Also String(Generalized-Time) */
- { "String(Unicode)", "2.5.5.12"},
- { "Object(Presentation-Address)", "2.5.5.13"},
- { "Object(DN-String)", "2.5.5.14"}, /* Also Object(Access-Point) */
- { "String(NT-Sec-Desc))", "2.5.5.15"},
- { "LargeInteger", "2.5.5.16"}, /* Also Interval ... */
- { "String(Sid)", "2.5.5.17"}
- };
-
-#define SCHEMA_TALLOC_CHECK(root, mem, ret) do { if (!mem) { talloc_free(root); return ret;} } while(0);
-
#define SCHEMA_FLAG_RESET 0
-#define SCHEMA_FLAG_MOD_MASK 0x03
-#define SCHEMA_FLAG_MOD_ADD 0x01
-#define SCHEMA_FLAG_MOD_REPLACE 0x02
-#define SCHEMA_FLAG_MOD_DELETE 0x03
-#define SCHEMA_FLAG_AUXCLASS 0x10
-#define SCHEMA_FLAG_CHECKED 0x20
-
+#define SCHEMA_FLAG_MOD_MASK 0x003
+#define SCHEMA_FLAG_MOD_ADD 0x001
+#define SCHEMA_FLAG_MOD_REPLACE 0x002
+#define SCHEMA_FLAG_MOD_DELETE 0x003
+#define SCHEMA_FLAG_AUXILIARY 0x010
+#define SCHEMA_FLAG_ABSTRACT 0x020
+#define SCHEMA_FLAG_STRUCTURAL 0x040
+#define SCHEMA_FLAG_CHECKED 0x100
+
+
+/* TODO: check attributes syntaxes
+ check there's only one structrual class (or a chain of structural classes)
+*/
struct private_data {
const char *error_string;
};
-struct attribute_list {
+struct schema_attribute {
int flags;
char *name;
};
+struct schema_attribute_list {
+ struct schema_attribute *attr;
+ int num;
+};
+
struct schema_structures {
- struct attribute_list *check_list;
- struct attribute_list *objectclass_list;
- struct attribute_list *must;
- struct attribute_list *may;
- int check_list_num;
- int objectclass_list_num;
- int must_num;
- int may_num;
+ struct schema_attribute_list entry_attrs;
+ struct schema_attribute_list objectclasses;
+ struct schema_attribute_list required_attrs;
+ 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)
+static struct schema_attribute *schema_find_attribute(struct schema_attribute_list *list, const char *attr_name)
{
- 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;
+ unsigned int i;
+ for (i = 0; i < list->num; i++) {
+ if (ldb_attr_cmp(list->attr[i].name, attr_name) == 0) {
+ return &(list->attr[i]);
}
}
- return ret;
+ return NULL;
}
-static int get_object_objectclasses(struct ldb_context *ldb, const char *dn, struct schema_structures *schema_struct)
+/* 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, int flag_mask)
{
- char *filter = talloc_asprintf(schema_struct, "dn=%s", dn);
- const char *attrs[] = {"objectClass", NULL};
- struct ldb_message **srch;
- int i, j, ret;
-
- schema_struct->objectclass_list = NULL;
- schema_struct->objectclass_list_num = 0;
- ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, attrs, &srch);
- if (ret == 1) {
- for (i = 0; i < (*srch)->num_elements; i++) {
- schema_struct->objectclass_list_num = (*srch)->elements[i].num_values;
- schema_struct->objectclass_list = talloc_array(schema_struct,
- struct attribute_list,
- schema_struct->objectclass_list_num);
- if (schema_struct->objectclass_list == 0) {
- ldb_search_free(ldb, srch);
+ int i, j, anum, cnum;
+
+ ss->entry_attrs.attr = talloc_realloc(ss, ss->entry_attrs.attr,
+ struct schema_attribute,
+ ss->entry_attrs.num + msg->num_elements);
+ if (ss->entry_attrs.attr == NULL) {
+ return -1;
+ }
+
+ for (i = 0, anum = ss->entry_attrs.num; i < msg->num_elements; i++) {
+
+ if (ldb_attr_cmp(msg->elements[i].name, "objectclass") == 0) {
+
+ ss->objectclasses.attr = talloc_realloc(ss, ss->objectclasses.attr,
+ struct schema_attribute,
+ ss->objectclasses.num + msg->elements[i].num_values);
+ if (ss->objectclasses.attr == NULL) {
return -1;
}
- for (j = 0; j < schema_struct->objectclass_list_num; j++) {
- schema_struct->objectclass_list[j].name = talloc_strndup(schema_struct->objectclass_list,
- (*srch)->elements[i].values[j].data,
- (*srch)->elements[i].values[j].length);
- if (schema_struct->objectclass_list[j].name == 0) {
- ldb_search_free(ldb, srch);
- return -1;
- }
- schema_struct->objectclass_list[j].flags = SCHEMA_FLAG_RESET;
+
+ for (j = 0, cnum = ss->objectclasses.num; j < msg->elements[i].num_values; j++) {
+ ss->objectclasses.attr[cnum+j].name = 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;
+ }
+
+ /* 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[anum+i].name == NULL) {
+ return -1;
}
- ldb_search_free(ldb, srch);
- } else {
- ldb_search_free(ldb, srch);
- return -1;
}
+ ss->entry_attrs.num += msg->num_elements;
return 0;
}
-static int get_check_list(struct ldb_module *module, struct schema_structures *schema_struct, const struct ldb_message *msg)
+static int get_entry_attributes(struct ldb_context *ldb, const struct ldb_dn *dn, struct schema_structures *ss)
{
- int i, j, k;
-
- schema_struct->objectclass_list = NULL;
- schema_struct->objectclass_list_num = 0;
- schema_struct->check_list_num = msg->num_elements;
- schema_struct->check_list = talloc_array(schema_struct,
- struct attribute_list,
- schema_struct->check_list_num);
- if (schema_struct->check_list == 0) {
- return -1;
+ struct ldb_message **srch;
+ int ret;
+
+ ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &srch);
+ if (ret != 1) {
+ return ret;
}
- for (i = 0, j = 0; i < msg->num_elements; i++) {
- if (schema_attr_cmp(msg->elements[i].name, "objectclass") == 0) {
- schema_struct->objectclass_list_num = msg->elements[i].num_values;
- schema_struct->objectclass_list = talloc_array(schema_struct,
- struct attribute_list,
- schema_struct->objectclass_list_num);
- if (schema_struct->objectclass_list == 0) {
- return -1;
- }
- for (k = 0; k < schema_struct->objectclass_list_num; k++) {
- schema_struct->objectclass_list[k].name = talloc_strndup(schema_struct->objectclass_list,
- msg->elements[i].values[k].data,
- msg->elements[i].values[k].length);
- if (schema_struct->objectclass_list[k].name == 0) {
- return -1;
- }
- schema_struct->objectclass_list[k].flags = msg->elements[i].flags;
- }
- }
+ talloc_steal(ss, srch);
- schema_struct->check_list[j].flags = msg->elements[i].flags;
- schema_struct->check_list[j].name = talloc_strdup(schema_struct->check_list,
- msg->elements[i].name);
- if (schema_struct->check_list[j].name == 0) {
- return -1;
- }
- j++;
+ /* set flags to 0 as flags on search have undefined values */
+ ret = get_msg_attributes(ss, *srch, 0);
+ if (ret != 0) {
+ talloc_free(srch);
+ return ret;
}
return 0;
}
-static int add_attribute_uniq(struct attribute_list **list, int *list_num, int flags, struct ldb_message_element *el, void *mem_ctx)
+/* add all attributes in el avoiding duplicates in schema_attribute_list */
+static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list, int flags, struct ldb_message_element *el)
{
int i, j, vals;
vals = el->num_values;
- *list = talloc_realloc(mem_ctx, *list, struct attribute_list, *list_num + vals);
- if (list == 0) {
+ list->attr = talloc_realloc(mem_ctx, list->attr, struct schema_attribute, list->num + vals);
+ if (list->attr == NULL) {
return -1;
}
for (i = 0, j = 0; i < vals; i++) {
int c, found, len;
found = 0;
- for (c = 0; c < *list_num; c++) {
- len = strlen((*list)[c].name);
+ for (c = 0; c < list->num; c++) {
+ len = strlen(list->attr[c].name);
if (len == el->values[i].length) {
- if (strncasecmp((*list)[c].name, el->values[i].data, len) == 0) {
+ if (ldb_attr_cmp(list->attr[c].name, el->values[i].data) == 0) {
found = 1;
break;
}
}
}
if (!found) {
- (*list)[j + *list_num].name = talloc_strndup(*list, el->values[i].data, el->values[i].length);
- if ((*list)[j + *list_num].name == 0) {
- return -1;
- }
- (*list)[j + *list_num].flags = flags;
+ list->attr[j + list->num].name = el->values[i].data;
+ list->attr[j + list->num].flags = flags;
j++;
}
}
- *list_num += j;
+ list->num += j;
return 0;
}
-static int get_attr_list_recursive(struct ldb_module *module, struct ldb_context *ldb, struct schema_structures *schema_struct)
+
+/* we need to get all attributes referenced by the entry objectclasses,
+ 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;
int i, j;
int ret;
- schema_struct->must = NULL;
- schema_struct->may = NULL;
- schema_struct->must_num = 0;
- schema_struct->may_num = 0;
- for (i = 0; i < schema_struct->objectclass_list_num; i++) {
+ for (i = 0; i < schema_struct->objectclasses.num; i++) {
char *filter;
- if ((schema_struct->objectclass_list[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
+ if ((schema_struct->objectclasses.attr[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
continue;
}
- filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclass_list[i].name);
- SCHEMA_TALLOC_CHECK(schema_struct, filter, -1);
- ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
- if (ret == 0) {
- int ok;
-
- ok = 0;
- /* suppose auxiliary classeschema_struct are not required */
- if (schema_struct->objectclass_list[i].flags & SCHEMA_FLAG_AUXCLASS) {
- int d;
- ok = 1;
- schema_struct->objectclass_list_num -= 1;
- for (d = i; d < schema_struct->objectclass_list_num; d++) {
- schema_struct->objectclass_list[d] = schema_struct->objectclass_list[d + 1];
- }
- i -= 1;
- }
- if (!ok) {
- /* Schema Violation: Object Class Description Not Found */
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Objectclass %s not found.\n", schema_struct->objectclass_list[i].name);
- data->error_string = "ObjectClass not found";
- return -1;
- }
- continue;
- } else {
- 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->objectclass_list[i].name);
- data->error_string = "Internal error. Error retrieving schema objectclass";
- 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->objectclass_list[i].name);
- data->error_string = "Internal error. Too many records searching for schema objectclass";
- return -1;
- }
+ filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclasses.attr[i].name);
+ if (filter == NULL) {
+ return -1;
+ }
+
+ ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
+ if (ret != 1) {
+ return ret;
+ }
+ 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";
+ 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";
+ return -1;
}
/* Add inherited classes eliminating duplicates */
- /* fill in kust and may attribute lists */
+ /* fill in required_attrs and optional_attrs attribute lists */
for (j = 0; j < (*srch)->num_elements; j++) {
int is_aux, is_class;
is_aux = 0;
is_class = 0;
- if (schema_attr_cmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
- is_aux = SCHEMA_FLAG_AUXCLASS;
+ if (ldb_attr_cmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
+ is_aux = SCHEMA_FLAG_AUXILIARY;
+ is_class = 1;
+ }
+ if (ldb_attr_cmp((*srch)->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)->elements[j].name, "subClassOf") == 0) {
is_class = 1;
}
if (is_class) {
- if (add_attribute_uniq(&schema_struct->objectclass_list,
- &schema_struct->objectclass_list_num,
+ if (add_attribute_uniq(schema_struct,
+ &schema_struct->objectclasses,
is_aux,
- &(*srch)->elements[j],
- schema_struct) != 0) {
+ &(*srch)->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 (add_attribute_uniq(&schema_struct->must,
- &schema_struct->must_num,
+ if (ldb_attr_cmp((*srch)->elements[j].name, "mustContain") == 0 ||
+ ldb_attr_cmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
+ if (add_attribute_uniq(schema_struct,
+ &schema_struct->required_attrs,
SCHEMA_FLAG_RESET,
- &(*srch)->elements[j],
- schema_struct) != 0) {
+ &(*srch)->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)->elements[j].name, "mayContain") == 0 ||
+ ldb_attr_cmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
- if (add_attribute_uniq(&schema_struct->may,
- &schema_struct->may_num,
+ if (add_attribute_uniq(schema_struct,
+ &schema_struct->optional_attrs,
SCHEMA_FLAG_RESET,
- &(*srch)->elements[j],
- schema_struct) != 0) {
+ &(*srch)->elements[j]) != 0) {
return -1;
}
}
}
}
-
- ldb_search_free(ldb, srch);
}
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,
+static int schema_search(struct ldb_module *module, const struct ldb_dn *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)
+static int schema_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
+ enum ldb_scope scope, struct ldb_parse_tree *tree,
+ const char * const *attrs, struct ldb_message ***res)
{
- return ldb_next_search_free(module, res);
+ return ldb_next_search_bytree(module, base, scope, tree, attrs, res);
}
/* add_record */
{
struct private_data *data = (struct private_data *)module->private_data;
struct schema_structures *entry_structs;
- int i, j;
+ unsigned int i;
int ret;
/* First implementation:
- Build up a list of must and mays from each objectclass
- Check all the musts are there and all the other attributes are mays
+ Build up a list of required_attrs and optional_attrs attributes from each objectclass
+ Check all the required_attrs attributes are present and all the other attributes
+ are optional_attrs attributes
Throw an error in case a check fail
Free all structures and commit the change
*/
- if (msg->dn[0] == '@') { /* do not check on our control entries */
+ /* do not check on our control entries */
+ if (ldb_dn_is_special(msg->dn)) {
return ldb_next_add_record(module, msg);
}
- entry_structs = talloc(module, struct schema_structures);
+ /* TODO: check parent exists */
+
+ entry_structs = talloc_zero(module, struct schema_structures);
if (!entry_structs) {
return -1;
}
- ret = get_check_list(module, entry_structs, msg);
+ ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
if (ret != 0) {
talloc_free(entry_structs);
return ret;
}
- /* find all other objectclasses recursively */
- ret = get_attr_list_recursive(module, module->ldb, entry_structs);
+ ret = get_attr_list_recursive(module, entry_structs);
if (ret != 0) {
talloc_free(entry_structs);
return ret;
}
- /* now check all musts are present */
- for (i = 0; i < entry_structs->must_num; i++) {
- int found;
+ /* now check all required_attrs attributes are present */
+ for (i = 0; i < entry_structs->required_attrs.num; i++) {
+ struct schema_attribute *attr;
- found = 0;
- for (j = 0; j < entry_structs->check_list_num; j++) {
- if (schema_attr_cmp(entry_structs->must[i].name, entry_structs->check_list[j].name) == 0) {
- entry_structs->check_list[j].flags = SCHEMA_FLAG_CHECKED;
- found = 1;
- break;
- }
- }
+ attr = schema_find_attribute(&entry_structs->entry_attrs,
+ 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);
- if ( ! found ) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "The required attribute %s is missing.\n", entry_structs->must[i].name);
data->error_string = "Objectclass violation, a required attribute is missing";
talloc_free(entry_structs);
return -1;
}
+
+ /* mark the attribute as checked */
+ attr->flags = SCHEMA_FLAG_CHECKED;
}
- /* now check all others atribs are found in mays */
- for (i = 0; i < entry_structs->check_list_num; i++) {
+ /* now check all others atribs are at least optional_attrs */
+ for (i = 0; i < entry_structs->entry_attrs.num; i++) {
- if (entry_structs->check_list[i].flags != SCHEMA_FLAG_CHECKED) {
- int found;
+ if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
+ struct schema_attribute *attr;
- found = 0;
- for (j = 0; j < entry_structs->may_num; j++) {
- if (schema_attr_cmp(entry_structs->may[j].name, entry_structs->check_list[i].name) == 0) {
- entry_structs->check_list[i].flags = SCHEMA_FLAG_CHECKED;
- found = 1;
- break;
- }
- }
+ attr = schema_find_attribute(&entry_structs->optional_attrs,
+ 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);
- if ( ! found ) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "The attribute %s is not referenced by any objectclass.\n", entry_structs->check_list[i].name);
data->error_string = "Objectclass violation, an invalid attribute name was found";
talloc_free(entry_structs);
return -1;
static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
{
struct private_data *data = (struct private_data *)module->private_data;
- struct schema_structures *entry_structs, *modify_structs;
- int i, j;
+ struct schema_structures *entry_structs;
+ unsigned int i;
int ret;
/* First implementation:
Retrieve the ldap entry and get the objectclasses,
add msg contained objectclasses if any.
- Build up a list of must and mays from each objectclass
- Check all musts for the defined objectclass and it's specific
- inheritance are there.
- Check all other the attributes are mays or musts.
+ Build up a list of required_attrs and optional_attrs attributes from each objectclass
+ Check all the attributes are optional_attrs or required_attrs.
Throw an error in case a check fail.
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_add_record(module, msg);
}
/* allocate object structs */
- entry_structs = talloc(module, struct schema_structures);
+ entry_structs = talloc_zero(module, struct schema_structures);
if (!entry_structs) {
return -1;
}
- /* allocate modification entry structs */
- modify_structs = talloc(entry_structs, struct schema_structures);
- if (!modify_structs) {
- talloc_free(entry_structs);
- return -1;
- }
-
- /* get list of values to modify */
- ret = get_check_list(module, modify_structs, msg);
+ /* now search for the stored entry objectclasses and attributes*/
+ ret = get_entry_attributes(module->ldb, msg->dn, entry_structs);
if (ret != 0) {
talloc_free(entry_structs);
return ret;
}
- /* find all modify objectclasses recursively if any objectclass is being added */
- ret = get_attr_list_recursive(module, module->ldb, modify_structs);
- if (ret != 0) {
- talloc_free(entry_structs);
- return ret;
- }
-
- /* now search for the original object objectclasses */
- ret = get_object_objectclasses(module->ldb, msg->dn, entry_structs);
+ /* get list of values to modify */
+ ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
if (ret != 0) {
talloc_free(entry_structs);
return ret;
}
- /* find all other objectclasses recursively */
- ret = get_attr_list_recursive(module, module->ldb, entry_structs);
+ ret = get_attr_list_recursive(module, entry_structs);
if (ret != 0) {
talloc_free(entry_structs);
return ret;
}
- /* now check all entries are present either as musts or mays of curent objectclasses */
- /* do not return errors there may be attirbutes defined in new objectclasses */
- /* just mark them as being proved valid attribs */
- for (i = 0; i < modify_structs->check_list_num; i++) {
- int found;
+ /* now check all required_attrs attributes are present */
+ for (i = 0; i < entry_structs->required_attrs.num; i++) {
+ struct schema_attribute *attr;
- found = 0;
- for (j = 0; j < entry_structs->must_num; j++) {
- if (schema_attr_cmp(entry_structs->must[j].name, modify_structs->check_list[i].name) == 0) {
- if ((modify_structs->check_list[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Trying to delete the required attribute %s.\n", modify_structs->check_list[i].name);
- data->error_string = "Objectclass violation: trying to delete a required attribute";
- talloc_free(entry_structs);
- return -1;
- }
- modify_structs->check_list[i].flags |= SCHEMA_FLAG_CHECKED;
- found = 1;
- break;
- }
- }
- if ( ! found) {
- for (j = 0; j < entry_structs->may_num; j++) {
- if (schema_attr_cmp(entry_structs->may[j].name, modify_structs->check_list[i].name) == 0) {
- modify_structs->check_list[i].flags |= SCHEMA_FLAG_CHECKED;
- break;
- }
- }
- }
- }
+ attr = schema_find_attribute(&entry_structs->entry_attrs,
+ entry_structs->required_attrs.attr[i].name);
- /* now check all new objectclasses musts are present */
- for (i = 0; i < modify_structs->must_num; i++) {
- int found;
+ 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);
- found = 0;
- for (j = 0; j < modify_structs->check_list_num; j++) {
- if (schema_attr_cmp(modify_structs->must[i].name, modify_structs->check_list[j].name) == 0) {
- if ((modify_structs->check_list[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Trying to delete the required attribute %s.\n", modify_structs->must[i].name);
- data->error_string = "Objectclass violation: trying to delete a required attribute";
- talloc_free(entry_structs);
- return -1;
- }
- modify_structs->check_list[j].flags |= SCHEMA_FLAG_CHECKED;
- found = 1;
- break;
- }
+ data->error_string = "Objectclass violation, a required attribute is missing";
+ talloc_free(entry_structs);
+ return -1;
}
- if ( ! found ) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "The required attribute %s is missing.\n", modify_structs->must[i].name);
- 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(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;
}
+
+ /* mark the attribute as checked */
+ attr->flags = SCHEMA_FLAG_CHECKED;
}
- /* now check all others atribs are found in mays */
- for (i = 0; i < modify_structs->check_list_num; i++) {
+ /* now check all others atribs are at least optional_attrs */
+ for (i = 0; i < entry_structs->entry_attrs.num; i++) {
- if ((modify_structs->check_list[i].flags & SCHEMA_FLAG_CHECKED) == 0 &&
- (modify_structs->check_list[i].flags & SCHEMA_FLAG_MOD_MASK) != SCHEMA_FLAG_MOD_DELETE) {
- int found;
+ if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
+ struct schema_attribute *attr;
- found = 0;
- for (j = 0; j < modify_structs->may_num; j++) {
- if (schema_attr_cmp(modify_structs->may[j].name, modify_structs->check_list[i].name) == 0) {
- modify_structs->check_list[i].flags |= SCHEMA_FLAG_CHECKED;
- found = 1;
- break;
- }
- }
+ attr = schema_find_attribute(&entry_structs->optional_attrs,
+ 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);
- if ( ! found ) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "The attribute %s is not referenced by any objectclass.\n", modify_structs->check_list[i].name);
data->error_string = "Objectclass violation, an invalid attribute name was found";
talloc_free(entry_structs);
return -1;
}
/* delete_record */
-static int schema_delete_record(struct ldb_module *module, const char *dn)
+static int schema_delete_record(struct ldb_module *module, const struct ldb_dn *dn)
{
/* 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)
+static int schema_rename_record(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
{
return ldb_next_rename_record(module, olddn, newdn);
}
return ldb_next_errstring(module);
}
+static int schema_destructor(void *module_ctx)
+{
+/* struct ldb_module *ctx = module_ctx; */
+ /* put your clean-up functions here */
+ return 0;
+}
+
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",
+ .search = schema_search,
+ .search_bytree = schema_search_bytree,
+ .add_record = schema_add_record,
+ .modify_record = schema_modify_record,
+ .delete_record = schema_delete_record,
+ .rename_record = schema_rename_record,
+ .named_lock = schema_named_lock,
+ .named_unlock = schema_named_unlock,
+ .errstring = schema_errstring,
};
#ifdef HAVE_DLOPEN_DISABLED
}
data = talloc(ctx, struct private_data);
- SCHEMA_TALLOC_CHECK(ctx, data, NULL);
+ if (data == NULL) {
+ talloc_free(ctx);
+ return NULL;
+ }
data->error_string = NULL;
ctx->private_data = data;
ctx->prev = ctx->next = NULL;
ctx->ops = &schema_ops;
+ talloc_set_destructor (ctx, schema_destructor);
+
return ctx;
}