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, int flag_mask)
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 & flag_mask;
138 ss->objectclasses.num += msg->elements[i].num_values;
141 ss->entry_attrs.attr[j].flags = msg->elements[i].flags & flag_mask;
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 /* set flags to 0 as flags on search have undefined values */
167 ret = get_msg_attributes(ss, *srch, 0);
176 /* add all attributes in el avoiding duplicates in schema_attribute_list */
177 static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list, int flags, struct ldb_message_element *el)
181 vals = el->num_values;
182 list->attr = talloc_realloc(mem_ctx, list->attr, struct schema_attribute, list->num + vals);
183 if (list->attr == NULL) {
186 for (i = 0, j = 0; i < vals; i++) {
190 for (c = 0; c < list->num; c++) {
191 len = strlen(list->attr[c].name);
192 if (len == el->values[i].length) {
193 if (schema_attr_cmp(list->attr[c].name, el->values[i].data) == 0) {
200 list->attr[j + list->num].name = el->values[i].data;
201 list->attr[j + list->num].flags = flags;
211 /* we need to get all attributes referenced by the entry objectclasses,
212 recursively get parent objectlasses attributes */
213 static int get_attr_list_recursive(struct ldb_module *module, struct schema_structures *schema_struct)
215 struct private_data *data = (struct private_data *)module->private_data;
216 struct ldb_message **srch;
220 for (i = 0; i < schema_struct->objectclasses.num; i++) {
223 if ((schema_struct->objectclasses.attr[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
226 filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclasses.attr[i].name);
227 if (filter == NULL) {
231 ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
235 talloc_steal(schema_struct, srch);
238 /* Schema DB Error: Error occurred retrieving Object Class Description */
239 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
240 data->error_string = "Internal error. Error retrieving schema objectclass";
244 /* Schema DB Error: Too Many Records */
245 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Too many records found retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
246 data->error_string = "Internal error. Too many records searching for schema objectclass";
250 /* Add inherited classes eliminating duplicates */
251 /* fill in required_attrs and optional_attrs attribute lists */
252 for (j = 0; j < (*srch)->num_elements; j++) {
253 int is_aux, is_class;
257 if (schema_attr_cmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
258 is_aux = SCHEMA_FLAG_AUXILIARY;
261 if (schema_attr_cmp((*srch)->elements[j].name, "subClassOf") == 0) {
266 if (add_attribute_uniq(schema_struct,
267 &schema_struct->objectclasses,
269 &(*srch)->elements[j]) != 0) {
274 if (schema_attr_cmp((*srch)->elements[j].name, "mustContain") == 0 ||
275 schema_attr_cmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
276 if (add_attribute_uniq(schema_struct,
277 &schema_struct->required_attrs,
279 &(*srch)->elements[j]) != 0) {
284 if (schema_attr_cmp((*srch)->elements[j].name, "mayContain") == 0 ||
285 schema_attr_cmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
287 if (add_attribute_uniq(schema_struct,
288 &schema_struct->optional_attrs,
290 &(*srch)->elements[j]) != 0) {
302 static int schema_search(struct ldb_module *module, const char *base,
303 enum ldb_scope scope, const char *expression,
304 const char * const *attrs, struct ldb_message ***res)
306 return ldb_next_search(module, base, scope, expression, attrs, res);
310 static int schema_add_record(struct ldb_module *module, const struct ldb_message *msg)
312 struct private_data *data = (struct private_data *)module->private_data;
313 struct schema_structures *entry_structs;
317 /* First implementation:
318 Build up a list of required_attrs and optional_attrs attributes from each objectclass
319 Check all the required_attrs attributes are present and all the other attributes
320 are optional_attrs attributes
321 Throw an error in case a check fail
322 Free all structures and commit the change
325 if (msg->dn[0] == '@') { /* do not check on our control entries */
326 return ldb_next_add_record(module, msg);
329 entry_structs = talloc_zero(module, struct schema_structures);
330 if (!entry_structs) {
334 ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
336 talloc_free(entry_structs);
340 ret = get_attr_list_recursive(module, entry_structs);
342 talloc_free(entry_structs);
346 /* now check all required_attrs attributes are present */
347 for (i = 0; i < entry_structs->required_attrs.num; i++) {
348 struct schema_attribute *attr;
350 attr = schema_find_attribute(&entry_structs->entry_attrs,
351 entry_structs->required_attrs.attr[i].name);
353 if (attr == NULL) { /* not found */
354 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
355 "The required_attrs attribute %s is missing.\n",
356 entry_structs->required_attrs.attr[i].name);
358 data->error_string = "Objectclass violation, a required attribute is missing";
359 talloc_free(entry_structs);
363 /* mark the attribute as checked */
364 attr->flags = SCHEMA_FLAG_CHECKED;
367 /* now check all others atribs are at least optional_attrs */
368 for (i = 0; i < entry_structs->entry_attrs.num; i++) {
370 if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
371 struct schema_attribute *attr;
373 attr = schema_find_attribute(&entry_structs->optional_attrs,
374 entry_structs->entry_attrs.attr[i].name);
376 if (attr == NULL) { /* not found */
377 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
378 "The attribute %s is not referenced by any objectclass.\n",
379 entry_structs->entry_attrs.attr[i].name);
381 data->error_string = "Objectclass violation, an invalid attribute name was found";
382 talloc_free(entry_structs);
388 talloc_free(entry_structs);
390 return ldb_next_add_record(module, msg);
394 static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
396 struct private_data *data = (struct private_data *)module->private_data;
397 struct schema_structures *entry_structs;
401 /* First implementation:
402 Retrieve the ldap entry and get the objectclasses,
403 add msg contained objectclasses if any.
404 Build up a list of required_attrs and optional_attrs attributes from each objectclass
405 Check all the attributes are optional_attrs or required_attrs.
406 Throw an error in case a check fail.
407 Free all structures and commit the change.
410 if (msg->dn[0] == '@') { /* do not check on our control entries */
411 return ldb_next_modify_record(module, msg);
414 /* allocate object structs */
415 entry_structs = talloc_zero(module, struct schema_structures);
416 if (!entry_structs) {
420 /* now search for the stored entry objectclasses and attributes*/
421 ret = get_entry_attributes(module->ldb, msg->dn, entry_structs);
423 talloc_free(entry_structs);
427 /* get list of values to modify */
428 ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
430 talloc_free(entry_structs);
434 ret = get_attr_list_recursive(module, entry_structs);
436 talloc_free(entry_structs);
440 /* now check all required_attrs attributes are present */
441 for (i = 0; i < entry_structs->required_attrs.num; i++) {
442 struct schema_attribute *attr;
444 attr = schema_find_attribute(&entry_structs->entry_attrs,
445 entry_structs->required_attrs.attr[i].name);
447 if (attr == NULL) { /* not found */
448 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
449 "The required_attrs attribute %s is missing.\n",
450 entry_structs->required_attrs.attr[i].name);
452 data->error_string = "Objectclass violation, a required attribute is missing";
453 talloc_free(entry_structs);
457 /* check we are not trying to delete a required attribute */
458 /* TODO: consider multivalued attrs */
459 if ((attr->flags & SCHEMA_FLAG_MOD_DELETE) != 0) {
460 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
461 "Trying to delete the required attribute %s.\n",
464 data->error_string = "Objectclass violation, a required attribute cannot be removed";
465 talloc_free(entry_structs);
469 /* mark the attribute as checked */
470 attr->flags = SCHEMA_FLAG_CHECKED;
473 /* now check all others atribs are at least optional_attrs */
474 for (i = 0; i < entry_structs->entry_attrs.num; i++) {
476 if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
477 struct schema_attribute *attr;
479 attr = schema_find_attribute(&entry_structs->optional_attrs,
480 entry_structs->entry_attrs.attr[i].name);
482 if (attr == NULL) { /* not found */
483 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
484 "The attribute %s is not referenced by any objectclass.\n",
485 entry_structs->entry_attrs.attr[i].name);
487 data->error_string = "Objectclass violation, an invalid attribute name was found";
488 talloc_free(entry_structs);
494 talloc_free(entry_structs);
496 return ldb_next_modify_record(module, msg);
500 static int schema_delete_record(struct ldb_module *module, const char *dn)
502 /* struct private_data *data = (struct private_data *)module->private_data; */
503 return ldb_next_delete_record(module, dn);
507 static int schema_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
509 return ldb_next_rename_record(module, olddn, newdn);
512 static int schema_named_lock(struct ldb_module *module, const char *name) {
513 return ldb_next_named_lock(module, name);
516 static int schema_named_unlock(struct ldb_module *module, const char *name) {
517 return ldb_next_named_unlock(module, name);
520 /* return extended error information */
521 static const char *schema_errstring(struct ldb_module *module)
523 struct private_data *data = (struct private_data *)module->private_data;
525 if (data->error_string) {
528 error = data->error_string;
529 data->error_string = NULL;
533 return ldb_next_errstring(module);
536 static int schema_destructor(void *module_ctx)
538 /* struct ldb_module *ctx = module_ctx; */
539 /* put your clean-up functions here */
543 static const struct ldb_module_ops schema_ops = {
547 schema_modify_record,
548 schema_delete_record,
549 schema_rename_record,
555 #ifdef HAVE_DLOPEN_DISABLED
556 struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
558 struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
561 struct ldb_module *ctx;
562 struct private_data *data;
564 ctx = talloc(ldb, struct ldb_module);
569 data = talloc(ctx, struct private_data);
575 data->error_string = NULL;
576 ctx->private_data = data;
578 ctx->prev = ctx->next = NULL;
579 ctx->ops = &schema_ops;
581 talloc_set_destructor (ctx, schema_destructor);