4 Copyright (C) Simo Sorce 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb schema module
30 * Description: add schema check functionality
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
39 #define SCHEMA_FLAG_RESET 0
40 #define SCHEMA_FLAG_MOD_MASK 0x003
41 #define SCHEMA_FLAG_MOD_ADD 0x001
42 #define SCHEMA_FLAG_MOD_REPLACE 0x002
43 #define SCHEMA_FLAG_MOD_DELETE 0x003
44 #define SCHEMA_FLAG_AUXILIARY 0x010
45 #define SCHEMA_FLAG_ABSTRACT 0x020
46 #define SCHEMA_FLAG_STRUCTURAL 0x040
47 #define SCHEMA_FLAG_CHECKED 0x100
50 /* TODO: check attributes syntaxes
51 check there's only one structrual class (or a chain of structural classes)
55 const char *error_string;
58 struct schema_attribute {
63 struct schema_attribute_list {
64 struct schema_attribute *attr;
68 struct schema_structures {
69 struct schema_attribute_list entry_attrs;
70 struct schema_attribute_list objectclasses;
71 struct schema_attribute_list required_attrs;
72 struct schema_attribute_list optional_attrs;
75 /* This function embedds the knowledge of aliased names.
76 Currently it handles only dn vs distinguishedNAme as a special case as AD
77 only have this special alias case, in future we should read the schema
78 to find out which names have an alias and check for them */
79 static int schema_attr_cmp(const char *attr1, const char *attr2)
83 ret = ldb_attr_cmp(attr1, attr2);
85 if ((ldb_attr_cmp("dn", attr1) == 0) &&
86 (ldb_attr_cmp("distinguishedName", attr2) == 0)) {
89 if ((ldb_attr_cmp("dn", attr2) == 0) &&
90 (ldb_attr_cmp("distinguishedName", attr1) == 0)) {
97 static struct schema_attribute *schema_find_attribute(struct schema_attribute_list *list, const char *attr_name)
100 for (i = 0; i < list->num; i++) {
101 if (ldb_attr_cmp(list->attr[i].name, attr_name) == 0) {
102 return &(list->attr[i]);
108 /* get all the attributes and objectclasses found in msg and put them in schema_structure
109 attributes go in the entry_attrs structure for later checking
110 objectclasses go in the objectclasses structure */
111 static int get_msg_attributes(struct schema_structures *ss, const struct ldb_message *msg)
115 ss->entry_attrs.attr = talloc_realloc(ss, ss->entry_attrs.attr,
116 struct schema_attribute,
117 ss->entry_attrs.num + msg->num_elements);
118 if (ss->entry_attrs.attr == NULL) {
122 for (i = 0, j = ss->entry_attrs.num; i < msg->num_elements; i++) {
124 if (schema_attr_cmp(msg->elements[i].name, "objectclass") == 0) {
126 ss->objectclasses.attr = talloc_realloc(ss, ss->objectclasses.attr,
127 struct schema_attribute,
128 ss->objectclasses.num + msg->elements[i].num_values);
129 if (ss->objectclasses.attr == NULL) {
133 for (k = 0, l = ss->objectclasses.num; k < msg->elements[i].num_values; k++) {
134 ss->objectclasses.attr[l].name = msg->elements[i].values[k].data;
135 ss->objectclasses.attr[l].flags = msg->elements[i].flags;
138 ss->objectclasses.num += msg->elements[i].num_values;
141 ss->entry_attrs.attr[j].flags = msg->elements[i].flags;
142 ss->entry_attrs.attr[j].name = talloc_reference(ss->entry_attrs.attr,
143 msg->elements[i].name);
144 if (ss->entry_attrs.attr[j].name == NULL) {
149 ss->entry_attrs.num += msg->num_elements;
154 static int get_entry_attributes(struct ldb_context *ldb, const char *dn, struct schema_structures *ss)
156 char *filter = talloc_asprintf(ss, "dn=%s", dn);
157 struct ldb_message **srch;
160 ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
164 talloc_steal(ss, srch);
166 ret = get_msg_attributes(ss, *srch);
168 ldb_search_free(ldb, srch);
175 /* add all attributes in el avoiding duplicates in schema_attribute_list */
176 static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list, int flags, struct ldb_message_element *el)
180 vals = el->num_values;
181 list->attr = talloc_realloc(mem_ctx, list->attr, struct schema_attribute, list->num + vals);
182 if (list->attr == NULL) {
185 for (i = 0, j = 0; i < vals; i++) {
189 for (c = 0; c < list->num; c++) {
190 len = strlen(list->attr[c].name);
191 if (len == el->values[i].length) {
192 if (schema_attr_cmp(list->attr[c].name, el->values[i].data) == 0) {
199 list->attr[j + list->num].name = el->values[i].data;
200 list->attr[j + list->num].flags = flags;
210 /* we need to get all attributes referenced by the entry objectclasses,
211 recursively get parent objectlasses attributes */
212 static int get_attr_list_recursive(struct ldb_module *module, struct schema_structures *schema_struct)
214 struct private_data *data = (struct private_data *)module->private_data;
215 struct ldb_message **srch;
219 for (i = 0; i < schema_struct->objectclasses.num; i++) {
222 if ((schema_struct->objectclasses.attr[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
225 filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclasses.attr[i].name);
226 if (filter == NULL) {
230 ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
234 talloc_steal(schema_struct, srch);
237 /* Schema DB Error: Error occurred retrieving Object Class Description */
238 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
239 data->error_string = "Internal error. Error retrieving schema objectclass";
243 /* Schema DB Error: Too Many Records */
244 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Too many records found retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
245 data->error_string = "Internal error. Too many records searching for schema objectclass";
249 /* Add inherited classes eliminating duplicates */
250 /* fill in required_attrs and optional_attrs attribute lists */
251 for (j = 0; j < (*srch)->num_elements; j++) {
252 int is_aux, is_class;
256 if (schema_attr_cmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
257 is_aux = SCHEMA_FLAG_AUXILIARY;
260 if (schema_attr_cmp((*srch)->elements[j].name, "subClassOf") == 0) {
265 if (add_attribute_uniq(schema_struct,
266 &schema_struct->objectclasses,
268 &(*srch)->elements[j]) != 0) {
273 if (schema_attr_cmp((*srch)->elements[j].name, "mustContain") == 0 ||
274 schema_attr_cmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
275 if (add_attribute_uniq(schema_struct,
276 &schema_struct->required_attrs,
278 &(*srch)->elements[j]) != 0) {
283 if (schema_attr_cmp((*srch)->elements[j].name, "mayContain") == 0 ||
284 schema_attr_cmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
286 if (add_attribute_uniq(schema_struct,
287 &schema_struct->optional_attrs,
289 &(*srch)->elements[j]) != 0) {
301 static int schema_close(struct ldb_module *module)
303 return ldb_next_close(module);
307 static int schema_search(struct ldb_module *module, const char *base,
308 enum ldb_scope scope, const char *expression,
309 const char * const *attrs, struct ldb_message ***res)
311 return ldb_next_search(module, base, scope, expression, attrs, res);
315 static int schema_search_free(struct ldb_module *module, struct ldb_message **res)
317 return ldb_next_search_free(module, res);
321 static int schema_add_record(struct ldb_module *module, const struct ldb_message *msg)
323 struct private_data *data = (struct private_data *)module->private_data;
324 struct schema_structures *entry_structs;
328 /* First implementation:
329 Build up a list of required_attrs and optional_attrs attributes from each objectclass
330 Check all the required_attrs attributes are present and all the other attributes
331 are optional_attrs attributes
332 Throw an error in case a check fail
333 Free all structures and commit the change
336 if (msg->dn[0] == '@') { /* do not check on our control entries */
337 return ldb_next_add_record(module, msg);
340 entry_structs = talloc_zero(module, struct schema_structures);
341 if (!entry_structs) {
345 ret = get_msg_attributes(entry_structs, msg);
347 talloc_free(entry_structs);
351 ret = get_attr_list_recursive(module, entry_structs);
353 talloc_free(entry_structs);
357 /* now check all required_attrs attributes are present */
358 for (i = 0; i < entry_structs->required_attrs.num; i++) {
359 struct schema_attribute *attr;
361 attr = schema_find_attribute(&entry_structs->entry_attrs,
362 entry_structs->required_attrs.attr[i].name);
364 if (attr == NULL) { /* not found */
365 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
366 "The required_attrs attribute %s is missing.\n",
367 entry_structs->required_attrs.attr[i].name);
369 data->error_string = "Objectclass violation, a required attribute is missing";
370 talloc_free(entry_structs);
374 /* check we are not trying to delete a required attribute */
375 /* TODO: consider multivalued attrs */
376 if ((attr->flags & SCHEMA_FLAG_MOD_DELETE) != 0) {
377 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
378 "Trying to delete the required attribute %s.\n",
381 data->error_string = "Objectclass violation, a required attribute cannot be removed";
382 talloc_free(entry_structs);
386 /* mark the attribute as checked */
387 attr->flags = SCHEMA_FLAG_CHECKED;
390 /* now check all others atribs are at least optional_attrs */
391 for (i = 0; i < entry_structs->entry_attrs.num; i++) {
393 if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
394 struct schema_attribute *attr;
396 attr = schema_find_attribute(&entry_structs->optional_attrs,
397 entry_structs->entry_attrs.attr[i].name);
399 if (attr == NULL) { /* not found */
400 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
401 "The attribute %s is not referenced by any objectclass.\n",
402 entry_structs->entry_attrs.attr[i].name);
404 data->error_string = "Objectclass violation, an invalid attribute name was found";
405 talloc_free(entry_structs);
411 talloc_free(entry_structs);
413 return ldb_next_add_record(module, msg);
417 static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
419 struct private_data *data = (struct private_data *)module->private_data;
420 struct schema_structures *entry_structs;
424 /* First implementation:
425 Retrieve the ldap entry and get the objectclasses,
426 add msg contained objectclasses if any.
427 Build up a list of required_attrs and optional_attrs attributes from each objectclass
428 Check all the attributes are optional_attrs or required_attrs.
429 Throw an error in case a check fail.
430 Free all structures and commit the change.
433 if (msg->dn[0] == '@') { /* do not check on our control entries */
434 return ldb_next_modify_record(module, msg);
437 /* allocate object structs */
438 entry_structs = talloc_zero(module, struct schema_structures);
439 if (!entry_structs) {
443 /* now search for the stored entry objectclasses and attributes*/
444 ret = get_entry_attributes(module->ldb, msg->dn, entry_structs);
446 talloc_free(entry_structs);
450 /* get list of values to modify */
451 ret = get_msg_attributes(entry_structs, msg);
453 talloc_free(entry_structs);
457 ret = get_attr_list_recursive(module, entry_structs);
459 talloc_free(entry_structs);
463 /* now check all required_attrs attributes are present */
464 for (i = 0; i < entry_structs->required_attrs.num; i++) {
465 struct schema_attribute *attr;
467 attr = schema_find_attribute(&entry_structs->entry_attrs,
468 entry_structs->required_attrs.attr[i].name);
470 if (attr == NULL) { /* not found */
471 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
472 "The required_attrs attribute %s is missing.\n",
473 entry_structs->required_attrs.attr[i].name);
475 data->error_string = "Objectclass violation, a required attribute is missing";
476 talloc_free(entry_structs);
480 /* mark the attribute as checked */
481 attr->flags = SCHEMA_FLAG_CHECKED;
484 /* now check all others atribs are at least optional_attrs */
485 for (i = 0; i < entry_structs->entry_attrs.num; i++) {
487 if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
488 struct schema_attribute *attr;
490 attr = schema_find_attribute(&entry_structs->optional_attrs,
491 entry_structs->entry_attrs.attr[i].name);
493 if (attr == NULL) { /* not found */
494 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
495 "The attribute %s is not referenced by any objectclass.\n",
496 entry_structs->entry_attrs.attr[i].name);
498 data->error_string = "Objectclass violation, an invalid attribute name was found";
499 talloc_free(entry_structs);
505 talloc_free(entry_structs);
507 return ldb_next_modify_record(module, msg);
511 static int schema_delete_record(struct ldb_module *module, const char *dn)
513 /* struct private_data *data = (struct private_data *)module->private_data; */
514 return ldb_next_delete_record(module, dn);
518 static int schema_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
520 return ldb_next_rename_record(module, olddn, newdn);
523 static int schema_named_lock(struct ldb_module *module, const char *name) {
524 return ldb_next_named_lock(module, name);
527 static int schema_named_unlock(struct ldb_module *module, const char *name) {
528 return ldb_next_named_unlock(module, name);
531 /* return extended error information */
532 static const char *schema_errstring(struct ldb_module *module)
534 struct private_data *data = (struct private_data *)module->private_data;
536 if (data->error_string) {
539 error = data->error_string;
540 data->error_string = NULL;
544 return ldb_next_errstring(module);
547 static const struct ldb_module_ops schema_ops = {
553 schema_modify_record,
554 schema_delete_record,
555 schema_rename_record,
561 #ifdef HAVE_DLOPEN_DISABLED
562 struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
564 struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
567 struct ldb_module *ctx;
568 struct private_data *data;
570 ctx = talloc(ldb, struct ldb_module);
575 data = talloc(ctx, struct private_data);
581 data->error_string = NULL;
582 ctx->private_data = data;
584 ctx->prev = ctx->next = NULL;
585 ctx->ops = &schema_ops;