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 struct attribute_syntax {
41 const char *syntax_id;
44 static struct attribute_syntax attrsyn[] = {
45 { "Object(DS-DN)", "2.5.5.1"},
46 { "String(Object-Identifier)", "2.5.5.2"},
48 { "String(Teletex)", "2.5.5.4"},
49 { "String(IA5)", "2.5.5.5"}, /* Also String(Printable) */
50 { "String(Numeric)", "2.5.5.6"},
51 { "Object(DN-Binary)", "2.5.5.7"}, /* Also Object(OR-Name) */
52 { "Boolean", "2.5.5.8"},
53 { "Integer", "2.5.5.9"}, /* Also Enumeration (3 types ?) ... */
54 { "String(Octet)", "2.5.5.10"}, /* Also Object(Replica-Link) */
55 { "String(UTC-Time)", "2.5.5.11"}, /* Also String(Generalized-Time) */
56 { "String(Unicode)", "2.5.5.12"},
57 { "Object(Presentation-Address)", "2.5.5.13"},
58 { "Object(DN-String)", "2.5.5.14"}, /* Also Object(Access-Point) */
59 { "String(NT-Sec-Desc))", "2.5.5.15"},
60 { "LargeInteger", "2.5.5.16"}, /* Also Interval ... */
61 { "String(Sid)", "2.5.5.17"}
64 #define SCHEMA_TALLOC_CHECK(root, mem, ret) do { if (!mem) { talloc_free(root); return ret;} } while(0);
66 #define SCHEMA_FLAG_RESET 0
67 #define SCHEMA_FLAG_MOD_MASK 0x03
68 #define SCHEMA_FLAG_MOD_ADD 0x01
69 #define SCHEMA_FLAG_MOD_REPLACE 0x02
70 #define SCHEMA_FLAG_MOD_DELETE 0x03
71 #define SCHEMA_FLAG_AUXCLASS 0x10
72 #define SCHEMA_FLAG_CHECKED 0x20
76 struct ldb_context *schema_db;
77 const char *error_string;
81 static int schema_close(struct ldb_module *module)
83 return ldb_next_close(module);
87 static int schema_search(struct ldb_module *module, const char *base,
88 enum ldb_scope scope, const char *expression,
89 const char * const *attrs, struct ldb_message ***res)
91 return ldb_next_search(module, base, scope, expression, attrs, res);
95 static int schema_search_free(struct ldb_module *module, struct ldb_message **res)
97 return ldb_next_search_free(module, res);
100 struct attribute_list {
105 struct schema_structures {
106 struct attribute_list *check_list;
107 struct attribute_list *objectclass_list;
108 struct attribute_list *must;
109 struct attribute_list *may;
111 int objectclass_list_num;
116 static int get_object_objectclasses(struct ldb_context *ldb, const char *dn, struct schema_structures *schema_struct)
118 char *filter = talloc_asprintf(schema_struct, "dn=%s", dn);
119 const char *attrs[] = {"objectClass", NULL};
120 struct ldb_message **srch;
123 schema_struct->objectclass_list = NULL;
124 schema_struct->objectclass_list_num = 0;
125 ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, attrs, &srch);
127 for (i = 0; i < (*srch)->num_elements; i++) {
128 schema_struct->objectclass_list_num = (*srch)->elements[i].num_values;
129 schema_struct->objectclass_list = talloc_array(schema_struct,
130 struct attribute_list,
131 schema_struct->objectclass_list_num);
132 if (schema_struct->objectclass_list == 0) {
133 ldb_search_free(ldb, srch);
136 for (j = 0; j < schema_struct->objectclass_list_num; j++) {
137 schema_struct->objectclass_list[j].name = talloc_strndup(schema_struct->objectclass_list,
138 (*srch)->elements[i].values[j].data,
139 (*srch)->elements[i].values[j].length);
140 if (schema_struct->objectclass_list[j].name == 0) {
141 ldb_search_free(ldb, srch);
144 schema_struct->objectclass_list[j].flags = SCHEMA_FLAG_RESET;
147 ldb_search_free(ldb, srch);
149 ldb_search_free(ldb, srch);
156 static int get_check_list(struct ldb_module *module, struct schema_structures *schema_struct, const struct ldb_message *msg)
160 schema_struct->objectclass_list = NULL;
161 schema_struct->objectclass_list_num = 0;
162 schema_struct->check_list_num = msg->num_elements;
163 schema_struct->check_list = talloc_array(schema_struct,
164 struct attribute_list,
165 schema_struct->check_list_num);
166 if (schema_struct->check_list == 0) {
169 for (i = 0, j = 0; i < msg->num_elements; i++) {
170 if (ldb_attr_cmp(msg->elements[i].name, "objectclass") == 0) {
171 schema_struct->objectclass_list_num = msg->elements[i].num_values;
172 schema_struct->objectclass_list = talloc_array(schema_struct,
173 struct attribute_list,
174 schema_struct->objectclass_list_num);
175 if (schema_struct->objectclass_list == 0) {
178 for (k = 0; k < schema_struct->objectclass_list_num; k++) {
179 schema_struct->objectclass_list[k].name = talloc_strndup(schema_struct->objectclass_list,
180 msg->elements[i].values[k].data,
181 msg->elements[i].values[k].length);
182 if (schema_struct->objectclass_list[k].name == 0) {
185 schema_struct->objectclass_list[k].flags = msg->elements[i].flags;
189 schema_struct->check_list[j].flags = msg->elements[i].flags;
190 schema_struct->check_list[j].name = talloc_strdup(schema_struct->check_list,
191 msg->elements[i].name);
192 if (schema_struct->check_list[j].name == 0) {
201 static int add_attribute_uniq(struct attribute_list **list, int *list_num, int flags, struct ldb_message_element *el, void *mem_ctx)
205 vals = el->num_values;
206 *list = talloc_realloc(mem_ctx, *list, struct attribute_list, *list_num + vals);
210 for (i = 0, j = 0; i < vals; i++) {
214 for (c = 0; c < *list_num; c++) {
215 len = strlen((*list)[c].name);
216 if (len == el->values[i].length) {
217 if (strncasecmp((*list)[c].name, el->values[i].data, len) == 0) {
224 (*list)[j + *list_num].name = talloc_strndup(*list, el->values[i].data, el->values[i].length);
225 if ((*list)[j + *list_num].name == 0) {
228 (*list)[j + *list_num].flags = flags;
237 static int get_attr_list_recursive(struct ldb_module *module, struct ldb_context *ldb, struct schema_structures *schema_struct)
239 struct private_data *data = (struct private_data *)module->private_data;
240 struct ldb_message **srch;
244 schema_struct->must = NULL;
245 schema_struct->may = NULL;
246 schema_struct->must_num = 0;
247 schema_struct->may_num = 0;
248 for (i = 0; i < schema_struct->objectclass_list_num; i++) {
251 if ((schema_struct->objectclass_list[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
254 filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclass_list[i].name);
255 SCHEMA_TALLOC_CHECK(schema_struct, filter, -1);
256 ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
261 /* suppose auxiliary classeschema_struct are not required */
262 if (schema_struct->objectclass_list[i].flags & SCHEMA_FLAG_AUXCLASS) {
265 schema_struct->objectclass_list_num -= 1;
266 for (d = i; d < schema_struct->objectclass_list_num; d++) {
267 schema_struct->objectclass_list[d] = schema_struct->objectclass_list[d + 1];
272 /* Schema Violation: Object Class Description Not Found */
273 data->error_string = "ObjectClass not found";
279 /* Schema DB Error: Error occurred retrieving Object Class Description */
280 data->error_string = "Internal error. Error retrieving schema objectclass";
284 /* Schema DB Error: Too Many Records */
285 data->error_string = "Internal error. Too many records searching for schema objectclass";
290 /* Add inherited classes eliminating duplicates */
291 /* fill in kust and may attribute lists */
292 for (j = 0; j < (*srch)->num_elements; j++) {
293 int is_aux, is_class;
297 if (ldb_attr_cmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
298 is_aux = SCHEMA_FLAG_AUXCLASS;
301 if (ldb_attr_cmp((*srch)->elements[j].name, "subClassOf") == 0) {
306 if (add_attribute_uniq(&schema_struct->objectclass_list,
307 &schema_struct->objectclass_list_num,
309 &(*srch)->elements[j],
310 schema_struct) != 0) {
315 if (ldb_attr_cmp((*srch)->elements[j].name, "mustContain") == 0 ||
316 ldb_attr_cmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
317 if (add_attribute_uniq(&schema_struct->must,
318 &schema_struct->must_num,
320 &(*srch)->elements[j],
321 schema_struct) != 0) {
326 if (ldb_attr_cmp((*srch)->elements[j].name, "mayContain") == 0 ||
327 ldb_attr_cmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
329 if (add_attribute_uniq(&schema_struct->may,
330 &schema_struct->may_num,
332 &(*srch)->elements[j],
333 schema_struct) != 0) {
340 ldb_search_free(ldb, srch);
347 static int schema_add_record(struct ldb_module *module, const struct ldb_message *msg)
349 struct private_data *data = (struct private_data *)module->private_data;
350 struct schema_structures *entry_structs;
354 /* First implementation:
355 Build up a list of must and mays from each objectclass
356 Check all the musts are there and all the other attributes are mays
357 Throw an error in case a check fail
358 Free all structures and commit the change
361 entry_structs = talloc(module, struct schema_structures);
362 if (!entry_structs) {
366 ret = get_check_list(module, entry_structs, msg);
368 talloc_free(entry_structs);
372 /* find all other objectclasses recursively */
373 ret = get_attr_list_recursive(module, data->schema_db, entry_structs);
375 talloc_free(entry_structs);
379 /* now check all musts are present */
380 for (i = 0; i < entry_structs->must_num; i++) {
384 for (j = 0; j < entry_structs->check_list_num; j++) {
385 if (ldb_attr_cmp(entry_structs->must[i].name, entry_structs->check_list[j].name) == 0) {
386 entry_structs->check_list[j].flags = SCHEMA_FLAG_CHECKED;
393 /* TODO: set the error string */
394 data->error_string = "Objectclass violation, a required attribute is mischema_structing";
395 talloc_free(entry_structs);
400 /* now check all others atribs are found in mays */
401 for (i = 0; i < entry_structs->check_list_num; i++) {
403 if (entry_structs->check_list[i].flags != SCHEMA_FLAG_CHECKED) {
407 for (j = 0; j < entry_structs->may_num; j++) {
408 if (ldb_attr_cmp(entry_structs->may[j].name, entry_structs->check_list[i].name) == 0) {
409 entry_structs->check_list[i].flags = SCHEMA_FLAG_CHECKED;
416 data->error_string = "Objectclass violation, an invalid attribute name was found";
417 talloc_free(entry_structs);
423 talloc_free(entry_structs);
425 return ldb_next_add_record(module, msg);
429 static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
431 struct private_data *data = (struct private_data *)module->private_data;
432 struct schema_structures *entry_structs, *modify_structs;
436 /* First implementation:
437 Retrieve the ldap entry and get the objectclasses,
438 add msg contained objectclasses if any.
439 Build up a list of must and mays from each objectclass
440 Check all musts for the defined objectclass and it's specific
441 inheritance are there.
442 Check all other the attributes are mays or musts.
443 Throw an error in case a check fail.
444 Free all structures and commit the change.
447 /* allocate object structs */
448 entry_structs = talloc(module, struct schema_structures);
449 if (!entry_structs) {
453 /* allocate modification entry structs */
454 modify_structs = talloc(entry_structs, struct schema_structures);
455 if (!modify_structs) {
456 talloc_free(entry_structs);
460 /* get list of values to modify */
461 ret = get_check_list(module, modify_structs, msg);
463 talloc_free(entry_structs);
467 /* find all modify objectclasses recursively if any objectclass is being added */
468 ret = get_attr_list_recursive(module, data->schema_db, modify_structs);
470 talloc_free(entry_structs);
474 /* now search for the original object objectclasses */
475 ret = get_object_objectclasses(module->ldb, msg->dn, entry_structs);
477 talloc_free(entry_structs);
481 /* find all other objectclasses recursively */
482 ret = get_attr_list_recursive(module, data->schema_db, entry_structs);
484 talloc_free(entry_structs);
488 /* now check all entries are present either as musts or mays of curent objectclasses */
489 /* do not return errors there may be attirbutes defined in new objectclasses */
490 /* just mark them as being proved valid attribs */
491 for (i = 0; i < modify_structs->check_list_num; i++) {
495 for (j = 0; j < entry_structs->must_num; j++) {
496 if (ldb_attr_cmp(entry_structs->must[j].name, modify_structs->check_list[i].name) == 0) {
497 if ((modify_structs->check_list[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
498 data->error_string = "Objectclass violation: trying to delete a required attribute";
499 talloc_free(entry_structs);
502 modify_structs->check_list[i].flags |= SCHEMA_FLAG_CHECKED;
508 for (j = 0; j < entry_structs->may_num; j++) {
509 if (ldb_attr_cmp(entry_structs->may[j].name, modify_structs->check_list[i].name) == 0) {
510 modify_structs->check_list[i].flags |= SCHEMA_FLAG_CHECKED;
517 /* now check all new objectclasses musts are present */
518 for (i = 0; i < modify_structs->must_num; i++) {
522 for (j = 0; j < modify_structs->check_list_num; j++) {
523 if (ldb_attr_cmp(modify_structs->must[i].name, modify_structs->check_list[j].name) == 0) {
524 if ((modify_structs->check_list[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
525 data->error_string = "Objectclass violation: trying to delete a required attribute";
526 talloc_free(entry_structs);
529 modify_structs->check_list[j].flags |= SCHEMA_FLAG_CHECKED;
536 /* TODO: set the error string */
537 data->error_string = "Objectclass violation, a required attribute is missing";
538 talloc_free(entry_structs);
543 /* now check all others atribs are found in mays */
544 for (i = 0; i < modify_structs->check_list_num; i++) {
546 if ((modify_structs->check_list[i].flags & SCHEMA_FLAG_CHECKED) == 0 &&
547 (modify_structs->check_list[i].flags & SCHEMA_FLAG_MOD_MASK) != SCHEMA_FLAG_MOD_DELETE) {
551 for (j = 0; j < modify_structs->may_num; j++) {
552 if (ldb_attr_cmp(modify_structs->may[j].name, modify_structs->check_list[i].name) == 0) {
553 modify_structs->check_list[i].flags |= SCHEMA_FLAG_CHECKED;
560 data->error_string = "Objectclass violation, an invalid attribute name was found";
561 talloc_free(entry_structs);
567 talloc_free(entry_structs);
569 return ldb_next_modify_record(module, msg);
573 static int schema_delete_record(struct ldb_module *module, const char *dn)
575 /* struct private_data *data = (struct private_data *)module->private_data; */
576 return ldb_next_delete_record(module, dn);
580 static int schema_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
582 return ldb_next_rename_record(module, olddn, newdn);
585 static int schema_named_lock(struct ldb_module *module, const char *name) {
586 return ldb_next_named_lock(module, name);
589 static int schema_named_unlock(struct ldb_module *module, const char *name) {
590 return ldb_next_named_unlock(module, name);
593 /* return extended error information */
594 static const char *schema_errstring(struct ldb_module *module)
596 struct private_data *data = (struct private_data *)module->private_data;
598 if (data->error_string) {
601 error = data->error_string;
602 data->error_string = NULL;
606 return ldb_next_errstring(module);
609 static const struct ldb_module_ops schema_ops = {
615 schema_modify_record,
616 schema_delete_record,
617 schema_rename_record,
623 #define SCHEMA_PREFIX "schema:"
624 #define SCHEMA_PREFIX_LEN 7
626 #ifdef HAVE_DLOPEN_DISABLED
627 struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
629 struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
632 struct ldb_module *ctx;
633 struct private_data *data;
637 ctx = talloc(ldb, struct ldb_module);
643 for (i = 0; options[i] != NULL; i++) {
644 if (strncmp(options[i], SCHEMA_PREFIX, SCHEMA_PREFIX_LEN) == 0) {
645 db_url = talloc_strdup(ctx, &options[i][SCHEMA_PREFIX_LEN]);
646 SCHEMA_TALLOC_CHECK(ctx, db_url, NULL);
651 if (!db_url) { /* search if it is defined in the calling ldb */
653 const char * attrs[] = { "@SCHEMADB", NULL };
654 struct ldb_message **msgs;
656 ret = ldb_search(ldb, "", LDB_SCOPE_BASE, "dn=@MODULES", (const char * const *)attrs, &msgs);
658 ldb_debug(ldb, LDB_DEBUG_TRACE, "Schema DB not found\n");
659 ldb_search_free(ldb, msgs);
663 ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for schema db, bailing out!\n", ldb_errstring(ldb));
664 ldb_search_free(ldb, msgs);
668 ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found, bailing out\n");
669 ldb_search_free(ldb, msgs);
673 db_url = talloc_strndup(ctx, msgs[0]->elements[0].values[0].data, msgs[0]->elements[0].values[0].length);
674 SCHEMA_TALLOC_CHECK(ctx, db_url, NULL);
677 ldb_search_free(ldb, msgs);
680 data = talloc(ctx, struct private_data);
681 SCHEMA_TALLOC_CHECK(ctx, data, NULL);
683 data->schema_db = ldb_connect(db_url, 0, NULL);
684 SCHEMA_TALLOC_CHECK(ctx, data->schema_db, NULL);
686 data->error_string = NULL;
687 ctx->private_data = data;
689 ctx->prev = ctx->next = NULL;
690 ctx->ops = &schema_ops;