4 Copyright (C) Simo Sorce 2004-2006
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Component: ldb schema module
25 * Description: add schema check functionality
29 * License: GNU GPL v2 or Later
33 #include "libcli/ldap/ldap.h"
34 #include "ldb/include/ldb_errors.h"
35 #include "ldb/include/ldb_private.h"
36 #include "lib/util/dlinklist.h"
37 #include "schema_syntax.h"
41 see ldap_server/devdocs/AD-syntaxes.txt
44 enum schema_class_type {
46 SCHEMA_CT_STRUCTURAL = 1,
47 SCHEMA_CT_ABSTRACT = 2,
48 SCHEMA_CT_AUXILIARY = 3
51 struct schema_attribute {
52 char *OID; /* attributeID */
53 char *name; /* lDAPDisplayName */
54 enum schema_internal_syntax syntax; /* generated from attributeSyntax, oMSyntax, oMObjectClass */
55 bool single; /* isSingleValued */
56 int min; /* rangeLower */
57 int max; /* rangeUpper */
58 int systemflag; /* systemFlag */
59 int searchflag; /* searchFlag */
60 bool isdefunct; /* isDefunct */
64 char *OID; /* governsID */
65 char *name; /* lDAPDisplayName */
66 enum schema_class_type type; /* objectClassCategory */
67 bool systemOnly; /* systemOnly */
68 bool isdefunct; /* isDefunct */
69 int systemflag; /* systemFlag */
70 char *defobjcat; /* defaultObjectCategory */
71 struct schema_class *parent; /* subClassOf */
72 struct schema_class **sysaux; /* systemAuxiliaryClass */
73 struct schema_class **aux; /* auxiliaryClass */
74 struct schema_class **sysposssup; /* systemPossSuperiors */
75 struct schema_class **posssup; /* possSuperiors */
76 struct schema_class **possinf; /* possibleInferiors */
77 struct schema_attribute **sysmust; /* systemMustContain */
78 struct schema_attribute **must; /* MustContain */
79 struct schema_attribute **sysmay; /* systemMayContain */
80 struct schema_attribute **may; /* MayContain */
83 /* TODO: ditcontentrules */
85 struct schema_private_data {
86 struct ldb_dn *schema_dn;
87 struct schema_attribute **attrs;
88 struct schema_store *attrs_store;
90 struct schema_class **class;
91 struct schema_store *class_store;
95 struct schema_class_dlist {
96 struct schema_class *class;
97 struct schema_class_dlist *prev;
98 struct schema_class_dlist *next;
99 enum schema_class_type role;
102 struct schema_context {
104 enum sc_op { SC_ADD, SC_MOD, SC_DEL, SC_RENAME } op;
105 enum sc_step { SC_INIT, SC_ADD_CHECK_PARENT, SC_ADD_TEMP, SC_DEL_CHECK_CHILDREN } step;
107 struct schema_private_data *data;
109 struct ldb_module *module;
110 struct ldb_request *orig_req;
111 struct ldb_request *down_req;
113 struct ldb_request *parent_req;
114 struct ldb_reply *parent_res;
116 struct schema_class_dlist *class_list;
117 struct schema_class **sup_list;
118 struct schema_class **aux_list;
121 /* FIXME: I'd really like to use an hash table here */
127 struct schema_store {
128 struct schema_link *store;
132 static struct schema_store *schema_store_new(TALLOC_CTX *mem_ctx)
134 struct schema_store *ht;
136 ht = talloc(mem_ctx, struct schema_store);
137 if (!ht) return NULL;
145 static int schema_store_add(struct schema_store *ht, const char *key, void *object)
147 ht->store = talloc_realloc(ht, ht->store, struct schema_link, ht->num_links + 1);
148 if (!ht->store) return LDB_ERR_OPERATIONS_ERROR;
150 ht->store[ht->num_links].name = key;
151 ht->store[ht->num_links].object = object;
158 static void *schema_store_find(struct schema_store *ht, const char *key)
162 for (i = 0; i < ht->num_links; i++) {
163 if (strcasecmp(ht->store[i].name, key) == 0) {
164 return ht->store[i].object;
171 #define SCHEMA_CHECK_VALUE(mem, val, mod) \
172 do { if (mem == val) { \
173 ret = LDB_ERR_OPERATIONS_ERROR; \
174 ldb_asprintf_errstring(mod->ldb, \
175 "schema module: Memory allocation or attribute error on %s", #mem); \
176 goto done; } } while(0)
178 struct schema_class **schema_get_class_list(struct ldb_module *module,
179 struct schema_private_data *data,
180 struct ldb_message_element *el)
182 struct schema_class **list;
185 list = talloc_array(data, struct schema_class *, el->num_values + 1);
187 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
191 for (i = 0; i < el->num_values; i++) {
192 list[i] = (struct schema_class *)schema_store_find(data->class_store,
193 (char *)el->values[i].data);
195 ldb_debug_set(module->ldb,
197 "Class %s referenced but not found in schema\n",
198 (char *)el->values[i].data);
207 struct schema_attribute **schema_get_attrs_list(struct ldb_module *module,
208 struct schema_private_data *data,
209 struct ldb_message_element *el)
211 struct schema_attribute **list;
214 list = talloc_array(data, struct schema_attribute *, el->num_values + 1);
216 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
220 for (i = 0; i < el->num_values; i++) {
221 list[i] = (struct schema_attribute *)schema_store_find(data->attrs_store,
222 (char *)el->values[i].data);
224 ldb_debug_set(module->ldb,
226 "Attriobute %s referenced but not found in schema\n",
227 (char *)el->values[i].data);
236 static int schema_init_attrs(struct ldb_module *module, struct schema_private_data *data)
238 static const char *schema_attrs[] = { "attributeID",
250 struct ldb_result *res;
253 ret = ldb_search(module->ldb,
256 "(objectClass=attributeSchema)",
260 if (ret != LDB_SUCCESS) {
264 data->num_attributes = res->count;
265 data->attrs = talloc_array(data, struct schema_attribute *, res->count);
266 SCHEMA_CHECK_VALUE(data->attrs, NULL, module);
268 data->attrs_store = schema_store_new(data);
269 SCHEMA_CHECK_VALUE(data->attrs_store, NULL, module);
271 for (i = 0; i < res->count; i++) {
272 const char *tmp_single;
273 const char *attr_syntax;
275 const struct ldb_val *om_class;
277 data->attrs[i] = talloc(data->attrs, struct schema_attribute);
278 SCHEMA_CHECK_VALUE(data->attrs[i], NULL, module);
280 data->attrs[i]->OID = talloc_strdup(data->attrs[i],
281 ldb_msg_find_attr_as_string(res->msgs[i], "attributeID", NULL));
282 SCHEMA_CHECK_VALUE(data->attrs[i]->OID, NULL, module);
284 data->attrs[i]->name = talloc_strdup(data->attrs[i],
285 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
286 SCHEMA_CHECK_VALUE(data->attrs[i]->name, NULL, module);
288 /* once we have both the OID and the attribute name, add the pointer to the store */
289 schema_store_add(data->attrs_store, data->attrs[i]->OID, data->attrs[i]);
290 schema_store_add(data->attrs_store, data->attrs[i]->name, data->attrs[i]);
292 attr_syntax = ldb_msg_find_attr_as_string(res->msgs[i], "attributeSyntax", NULL);
293 SCHEMA_CHECK_VALUE(attr_syntax, NULL, module);
295 om_syntax = ldb_msg_find_attr_as_uint(res->msgs[i], "oMSyntax", 0);
296 /* 0 is not a valid oMSyntax */
297 SCHEMA_CHECK_VALUE(om_syntax, 0, module);
299 om_class = ldb_msg_find_ldb_val(res->msgs[i], "oMObjectClass");
301 ret = map_schema_syntax(om_syntax, attr_syntax, om_class, &data->attrs[i]->syntax);
302 if (ret != LDB_SUCCESS) {
303 ldb_asprintf_errstring(module->ldb,
304 "schema module: invalid om syntax value on %s",
305 data->attrs[i]->name);
309 tmp_single = ldb_msg_find_attr_as_string(res->msgs[i], "isSingleValued", NULL);
310 SCHEMA_CHECK_VALUE(tmp_single, NULL, module);
311 if (strcmp(tmp_single, "TRUE") == 0) {
312 data->attrs[i]->single = 1;
314 data->attrs[i]->single = 0;
317 /* the following are optional */
318 data->attrs[i]->min = ldb_msg_find_attr_as_int(res->msgs[i], "rangeLower", INT_MIN);
319 data->attrs[i]->max = ldb_msg_find_attr_as_int(res->msgs[i], "rangeUpper", INT_MAX);
320 data->attrs[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
321 data->attrs[i]->searchflag = ldb_msg_find_attr_as_int(res->msgs[i], "searchFlag", 0);
322 data->attrs[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", false);
330 static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data)
332 const char *schema_attrs[] = { "governsID",
334 "objectClassCategory",
335 "defaultObjectCategory",
340 "systemAuxiliaryClass",
342 "systemPossSuperiors",
350 struct ldb_result *res;
353 ret = ldb_search(module->ldb,
356 "(objectClass=classSchema)",
360 if (ret != LDB_SUCCESS) {
364 data->num_classes = res->count;
365 data->class = talloc_array(data, struct schema_class *, res->count);
366 SCHEMA_CHECK_VALUE(data->class, NULL, module);
368 data->class_store = schema_store_new(data);
369 SCHEMA_CHECK_VALUE(data->class_store, NULL, module);
371 for (i = 0; i < res->count; i++) {
372 struct ldb_message_element *el;
374 data->class[i] = talloc(data->class, struct schema_class);
375 SCHEMA_CHECK_VALUE(data->class[i], NULL, module);
377 data->class[i]->OID = talloc_strdup(data->class[i],
378 ldb_msg_find_attr_as_string(res->msgs[i], "governsID", NULL));
379 SCHEMA_CHECK_VALUE(data->class[i]->OID, NULL, module);
381 data->class[i]->name = talloc_strdup(data->class[i],
382 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
383 SCHEMA_CHECK_VALUE(data->class[i]->name, NULL, module);
385 /* once we have both the OID and the class name, add the pointer to the store */
386 schema_store_add(data->class_store, data->class[i]->OID, data->class[i]);
387 schema_store_add(data->class_store, data->class[i]->name, data->class[i]);
389 data->class[i]->type = ldb_msg_find_attr_as_int(res->msgs[i], "objectClassCategory", -1);
390 /* 0 should not be a valid value, but turn out it is so test with -1 */
391 SCHEMA_CHECK_VALUE(data->class[i]->type, -1, module);
393 data->class[i]->defobjcat = talloc_strdup(data->class[i],
394 ldb_msg_find_attr_as_string(res->msgs[i],
395 "defaultObjectCategory", NULL));
396 /* SCHEMA_CHECK_VALUE(data->class[i]->defobjcat, NULL, module);
398 /* the following attributes are all optional */
400 data->class[i]->systemOnly = ldb_msg_find_attr_as_bool(res->msgs[i], "systemOnly", false);
401 data->class[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
402 data->class[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", false);
404 /* attributes are loaded first, so we can just go an query the attributes repo */
406 el = ldb_msg_find_element(res->msgs[i], "systemMustContain");
408 data->class[i]->sysmust = schema_get_attrs_list(module, data, el);
409 SCHEMA_CHECK_VALUE(data->class[i]->sysmust, NULL, module);
412 el = ldb_msg_find_element(res->msgs[i], "MustContain");
414 data->class[i]->must = schema_get_attrs_list(module, data, el);
415 SCHEMA_CHECK_VALUE(data->class[i]->must, NULL, module);
418 el = ldb_msg_find_element(res->msgs[i], "systemMayContain");
420 data->class[i]->sysmay = schema_get_attrs_list(module, data, el);
421 SCHEMA_CHECK_VALUE(data->class[i]->sysmay, NULL, module);
424 el = ldb_msg_find_element(res->msgs[i], "MayContain");
426 data->class[i]->may = schema_get_attrs_list(module, data, el);
427 SCHEMA_CHECK_VALUE(data->class[i]->may, NULL, module);
432 /* subClassOf, systemAuxiliaryClass, auxiliaryClass, systemPossSuperiors
433 * must be filled in a second loop, when all class objects are allocated
434 * or we may not find a class that has not yet been parsed */
435 for (i = 0; i < res->count; i++) {
436 struct ldb_message_element *el;
439 /* this is single valued anyway */
440 attr = ldb_msg_find_attr_as_string(res->msgs[i], "subClassOf", NULL);
441 SCHEMA_CHECK_VALUE(attr, NULL, module);
442 data->class[i]->parent = schema_store_find(data->class_store, attr);
443 SCHEMA_CHECK_VALUE(data->class[i]->parent, NULL, module);
445 /* the following attributes are all optional */
447 data->class[i]->sysaux = NULL;
448 el = ldb_msg_find_element(res->msgs[i], "systemAuxiliaryClass");
450 data->class[i]->sysaux = schema_get_class_list(module, data, el);
451 SCHEMA_CHECK_VALUE(data->class[i]->sysaux, NULL, module);
454 data->class[i]->aux = NULL;
455 el = ldb_msg_find_element(res->msgs[i], "auxiliaryClass");
457 data->class[i]->aux = schema_get_class_list(module, data, el);
458 SCHEMA_CHECK_VALUE(data->class[i]->aux, NULL, module);
461 data->class[i]->sysposssup = NULL;
462 el = ldb_msg_find_element(res->msgs[i], "systemPossSuperiors");
464 data->class[i]->sysposssup = schema_get_class_list(module, data, el);
465 SCHEMA_CHECK_VALUE(data->class[i]->sysposssup, NULL, module);
468 data->class[i]->posssup = NULL;
469 el = ldb_msg_find_element(res->msgs[i], "possSuperiors");
471 data->class[i]->posssup = schema_get_class_list(module, data, el);
472 SCHEMA_CHECK_VALUE(data->class[i]->posssup, NULL, module);
475 data->class[i]->possinf = NULL;
476 el = ldb_msg_find_element(res->msgs[i], "possibleInferiors");
478 data->class[i]->possinf = schema_get_class_list(module, data, el);
479 SCHEMA_CHECK_VALUE(data->class[i]->possinf, NULL, module);
488 static struct ldb_handle *schema_init_handle(struct ldb_request *req, struct ldb_module *module, enum sc_op op)
490 struct schema_context *sctx;
491 struct ldb_handle *h;
493 h = talloc_zero(req, struct ldb_handle);
495 ldb_set_errstring(module->ldb, "Out of Memory");
501 sctx = talloc_zero(h, struct schema_context);
503 ldb_set_errstring(module->ldb, "Out of Memory");
508 h->private_data = (void *)sctx;
510 h->state = LDB_ASYNC_INIT;
511 h->status = LDB_SUCCESS;
514 sctx->step = SC_INIT;
515 sctx->data = module->private_data;
516 sctx->module = module;
517 sctx->orig_req = req;
522 static int schema_add_check_parent(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
524 struct schema_context *sctx;
526 sctx = talloc_get_type(context, struct schema_context);
528 /* we are interested only in the single reply (base search) we receive here */
529 if (ares->type == LDB_REPLY_ENTRY) {
530 if (sctx->parent_res != NULL) {
531 ldb_set_errstring(ldb, "Too many results");
533 return LDB_ERR_OPERATIONS_ERROR;
535 sctx->parent_res = talloc_steal(sctx, ares);
543 static int schema_add_build_parent_req(struct schema_context *sctx)
545 const char * const parent_attrs[] = { "objectClass", NULL };
548 sctx->parent_req = talloc_zero(sctx, struct ldb_request);
549 if (sctx->parent_req == NULL) {
550 ldb_debug(sctx->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
551 return LDB_ERR_OPERATIONS_ERROR;
554 sctx->parent_req->operation = LDB_SEARCH;
555 sctx->parent_req->op.search.scope = LDB_SCOPE_BASE;
556 sctx->parent_req->op.search.base = ldb_dn_get_parent(sctx->parent_req, sctx->orig_req->op.add.message->dn);
557 sctx->parent_req->op.search.tree = ldb_parse_tree(sctx->parent_req, "(objectClass=*)");
558 sctx->parent_req->op.search.attrs = parent_attrs;
559 sctx->parent_req->controls = NULL;
560 sctx->parent_req->context = sctx;
561 sctx->parent_req->callback = schema_add_check_parent;
562 ret = ldb_set_timeout_from_prev_req(sctx->module->ldb, sctx->orig_req, sctx->parent_req);
567 static struct schema_class_dlist *schema_add_get_dlist_entry_with_class(struct schema_class_dlist *list, struct schema_class *class)
569 struct schema_class_dlist *temp;
571 for (temp = list; temp && (temp->class != class); temp = temp->next) /* noop */ ;
575 static int schema_add_class_to_dlist(struct schema_class_dlist *list, struct schema_class *class, enum schema_class_type role)
577 struct schema_class_dlist *entry;
578 struct schema_class_dlist *temp;
581 /* see if this class is usable */
582 if (class->isdefunct) {
583 return LDB_ERR_NO_SUCH_ATTRIBUTE;
586 /* see if this class already exist in the class list */
587 if (schema_add_get_dlist_entry_with_class(list, class)) {
591 /* this is a new class go on and add to the list */
592 entry = talloc_zero(list, struct schema_class_dlist);
593 if (!entry) return LDB_ERR_OPERATIONS_ERROR;
594 entry->class = class;
595 entry->role = class->type;
597 /* If parent is top (list is guaranteed to start always with top) */
598 if (class->parent == list->class) {
599 /* if the hierarchy role is structural try to add it just after top */
600 if (role == SCHEMA_CT_STRUCTURAL) {
601 /* but check no other class at after top has a structural role */
602 if (list->next && (list->next->role == SCHEMA_CT_STRUCTURAL)) {
603 return LDB_ERR_OBJECT_CLASS_VIOLATION;
605 DLIST_ADD_AFTER(list, entry, list);
607 DLIST_ADD_END(list, entry, struct schema_class_dlist *);
612 /* search if parent has already been added */
613 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
615 ret = schema_add_class_to_dlist(list, class->parent, role);
616 if (ret != LDB_SUCCESS) {
619 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
621 if (!temp) { /* parent not found !? */
622 return LDB_ERR_OPERATIONS_ERROR;
625 DLIST_ADD_AFTER(list, entry, temp);
626 if (role == SCHEMA_CT_STRUCTURAL || role == SCHEMA_CT_AUXILIARY) {
631 /* stop when hierarchy base is met or when base class parent is top */
632 } while (temp->class == temp->next->class->parent &&
633 temp->next->class->parent != list->class);
635 /* if we have not reached the head of the list
636 * and role is structural */
637 if (temp != list && role == SCHEMA_CT_STRUCTURAL) {
638 struct schema_class_dlist *hfirst, *hlast;
640 /* check if the list second entry is structural */
641 if (list->next->role == SCHEMA_CT_STRUCTURAL) {
642 /* we have a confilict here */
643 return LDB_ERR_OBJECT_CLASS_VIOLATION;
645 /* we have to move this hierarchy of classes
646 * so that the base of the structural hierarchy is right after top */
650 /* now hfirst - hlast are the boundaries of the structural hierarchy */
652 /* extract the structural hierachy from the list */
653 hfirst->prev->next = hlast->next;
654 if (hlast->next) hlast->next->prev = hfirst->prev;
656 /* insert the structural hierarchy just after top */
657 list->next->prev = hlast;
658 hlast->next = list->next;
667 /* merge source list into dest list and remove duplicates */
668 static int schema_merge_class_list(TALLOC_CTX *mem_ctx, struct schema_class ***dest, struct schema_class **source)
670 struct schema_class **list = *dest;
674 if (list) for (n = 0; list[n]; n++) /* noop */ ;
677 for (i = 0; source[i]; i++) {
678 for (j = 0; j < f; j++) {
679 if (list[j] == source[i]) {
683 if (j < f) { /* duplicate found */
687 list = talloc_realloc(mem_ctx, list, struct schema_class *, n + 2);
689 return LDB_ERR_OPERATIONS_ERROR;
701 /* validate and modify the objectclass attribute to sort and add parents */
702 static int schema_add_build_objectclass_list(struct schema_context *sctx)
704 struct schema_class_dlist *temp;
705 struct ldb_message_element * el;
706 struct schema_class *class;
709 /* First of all initialize list, it must start with class top */
710 sctx->class_list = talloc_zero(sctx, struct schema_class_dlist);
711 if (!sctx->class_list) return LDB_ERR_OPERATIONS_ERROR;
713 sctx->class_list->class = schema_store_find(sctx->data->class_store, "top");
714 if (!sctx->class_list->class) return LDB_ERR_OPERATIONS_ERROR;
716 el = ldb_msg_find_element(sctx->orig_req->op.add.message, "objectClass");
718 return LDB_ERR_OBJECT_CLASS_VIOLATION;
721 for (i = 0; i < el->num_values; i++) {
723 class = schema_store_find(sctx->data->class_store, (char *)el->values[i].data);
725 return LDB_ERR_NO_SUCH_ATTRIBUTE;
728 ret = schema_add_class_to_dlist(sctx->class_list, class, class->type);
729 if (ret != LDB_SUCCESS) {
734 /* now check if there is any class role that is still not STRUCTURAL or AUXILIARY */
735 /* build also the auxiliary class list and the possible superiors list */
736 temp = sctx->class_list->next; /* top is special, skip it */
740 if (temp->role == SCHEMA_CT_ABSTRACT || temp->role == SCHEMA_CT_88) {
741 return LDB_ERR_OBJECT_CLASS_VIOLATION;
743 if (temp->class->sysaux) {
744 ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->sysaux);
745 if (ret != LDB_SUCCESS) {
746 return LDB_ERR_OPERATIONS_ERROR;
749 if (temp->class->aux) {
750 ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->aux);
751 if (ret != LDB_SUCCESS) {
752 return LDB_ERR_OPERATIONS_ERROR;
755 if (temp->class->sysposssup) {
756 ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->sysposssup);
757 if (ret != LDB_SUCCESS) {
758 return LDB_ERR_OPERATIONS_ERROR;
761 if (temp->class->posssup) {
762 ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->posssup);
763 if (ret != LDB_SUCCESS) {
764 return LDB_ERR_OPERATIONS_ERROR;
770 /* complete sup_list with material from the aux classes */
771 for (i = 0; sctx->aux_list && sctx->aux_list[i]; i++) {
772 if (sctx->aux_list[i]->sysposssup) {
773 ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->sysposssup);
774 if (ret != LDB_SUCCESS) {
775 return LDB_ERR_OPERATIONS_ERROR;
778 if (sctx->aux_list[i]->posssup) {
779 ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->posssup);
780 if (ret != LDB_SUCCESS) {
781 return LDB_ERR_OPERATIONS_ERROR;
786 if (!sctx->sup_list) return LDB_ERR_NAMING_VIOLATION;
791 static int schema_add_check_container_constraints(struct schema_context *sctx)
793 struct schema_class **parent_possinf = NULL;
794 struct schema_class **parent_classes;
795 struct schema_class_dlist *temp;
796 struct ldb_message_element *el;
799 el = ldb_msg_find_element(sctx->parent_res->message, "objectClass");
802 return LDB_ERR_OPERATIONS_ERROR;
805 parent_classes = talloc_array(sctx, struct schema_class *, el->num_values + 1);
807 for (i = 0; i < el->num_values; i++) {
809 parent_classes[i] = schema_store_find(sctx->data->class_store, (const char *)el->values[i].data);
810 if (!parent_classes[i]) { /* should not be possible */
811 return LDB_ERR_OPERATIONS_ERROR;
814 if (parent_classes[i]->possinf) {
815 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->possinf);
816 if (ret != LDB_SUCCESS) {
817 return LDB_ERR_OPERATIONS_ERROR;
821 /* check also embedded auxiliary classes possinf */
822 for (j = 0; parent_classes[i]->sysaux && parent_classes[i]->sysaux[j]; j++) {
823 if (parent_classes[i]->sysaux[j]->possinf) {
824 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->sysaux[j]->possinf);
825 if (ret != LDB_SUCCESS) {
826 return LDB_ERR_OPERATIONS_ERROR;
830 for (j = 0; parent_classes[i]->aux && parent_classes[i]->aux[j]; j++) {
831 if (parent_classes[i]->aux[j]->possinf) {
832 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->aux[j]->possinf);
833 if (ret != LDB_SUCCESS) {
834 return LDB_ERR_OPERATIONS_ERROR;
840 /* foreach parent objectclass,
841 * check parent possible inferiors match all of the child objectclasses
843 * poss Superiors of the child objectclasses mathes one of the parent classes
846 temp = sctx->class_list->next; /* skip top it is special */
849 for (i = 0; parent_possinf[i]; i++) {
850 if (temp->class == parent_possinf[i]) {
854 if (parent_possinf[i] == NULL) {
855 /* class not found in possible inferiors */
856 return LDB_ERR_NAMING_VIOLATION;
862 for (i = 0; parent_classes[i]; i++) {
863 for (j = 0; sctx->sup_list[j]; j++) {
864 if (sctx->sup_list[j] == parent_classes[i]) {
868 if (sctx->sup_list[j]) { /* possible Superiors match one of the parent classes */
873 /* no parent classes matched superiors */
874 return LDB_ERR_NAMING_VIOLATION;
877 static int schema_add_build_down_req(struct schema_context *sctx)
879 struct schema_class_dlist *temp;
880 struct ldb_message *msg;
883 sctx->down_req = talloc(sctx, struct ldb_request);
884 if (!sctx->down_req) {
885 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
886 return LDB_ERR_OPERATIONS_ERROR;
889 *(sctx->down_req) = *(sctx->orig_req); /* copy the request */
890 msg = ldb_msg_copy_shallow(sctx->down_req, sctx->orig_req->op.add.message);
892 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
893 return LDB_ERR_OPERATIONS_ERROR;
896 /* rebuild the objectclass list */
897 ldb_msg_remove_attr(msg, "objectClass");
898 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
899 if (ret != LDB_SUCCESS) {
903 /* Add the complete list of classes back to the message */
904 for (temp = sctx->class_list; temp; temp = temp->next) {
905 ret = ldb_msg_add_string(msg, "objectClass", temp->class->name);
906 if (ret != LDB_SUCCESS) {
911 /* objectCategory can be set only by the system */
912 if (ldb_msg_find_element(msg, "objectCategory")) {
913 return LDB_ERR_CONSTRAINT_VIOLATION;
916 /* the OC is mandatory, every class defines it */
917 /* use the one defined in the structural class that defines the object */
918 for (temp = sctx->class_list->next; temp; temp = temp->next) {
919 if (!temp->next) break;
920 if (temp->next->role != SCHEMA_CT_STRUCTURAL) break;
922 /* oc = talloc_strdup(msg, temp->class->defobjcat);
923 ret = ldb_msg_add_string(msg, "objectCategory", oc);
925 sctx->down_req->op.add.message = msg;
930 static int schema_check_attributes_syntax(struct schema_context *sctx)
932 struct ldb_message *msg;
933 struct schema_attribute *attr;
936 msg = sctx->orig_req->op.add.message;
937 for (i = 0; i < msg->num_elements; i++) {
938 attr = schema_store_find(sctx->data->attrs_store, msg->elements[i].name);
940 return LDB_ERR_NO_SUCH_ATTRIBUTE;
942 ret = schema_validate(sctx->module->ldb, &msg->elements[i], attr->syntax, attr->single, attr->min, attr->max);
943 if (ret != LDB_SUCCESS) {
951 static int schema_add_continue(struct ldb_handle *h)
953 struct schema_context *sctx;
956 sctx = talloc_get_type(h->private_data, struct schema_context);
958 switch (sctx->step) {
961 /* First of all check that a parent exists for this entry */
962 ret = schema_add_build_parent_req(sctx);
963 if (ret != LDB_SUCCESS) {
967 sctx->step = SC_ADD_CHECK_PARENT;
968 return ldb_next_request(sctx->module, sctx->parent_req);
970 case SC_ADD_CHECK_PARENT:
972 /* parent search done, check result and go on */
973 if (sctx->parent_res == NULL) {
974 /* we must have a parent */
975 ret = LDB_ERR_NO_SUCH_OBJECT;
979 /* Check objectclasses are ok */
980 ret = schema_add_build_objectclass_list(sctx);
981 if (ret != LDB_SUCCESS) {
985 /* check the parent is of the right type for this object */
986 ret = schema_add_check_container_constraints(sctx);
987 if (ret != LDB_SUCCESS) {
991 /* check attributes syntax */
993 ret = schema_check_attributes_syntax(sctx);
994 if (ret != LDB_SUCCESS) {
998 ret = schema_add_build_down_req(sctx);
999 if (ret != LDB_SUCCESS) {
1002 sctx->step = SC_ADD_TEMP;
1004 return ldb_next_request(sctx->module, sctx->down_req);
1007 ret = LDB_ERR_OPERATIONS_ERROR;
1011 /* this is reached only in case of error */
1012 /* FIXME: fire an async reply ? */
1014 h->state = LDB_ASYNC_DONE;
1018 static int schema_add(struct ldb_module *module, struct ldb_request *req)
1020 struct schema_context *sctx;
1021 struct ldb_handle *h;
1023 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1024 return ldb_next_request(module, req);
1027 h = schema_init_handle(req, module, SC_ADD);
1029 return LDB_ERR_OPERATIONS_ERROR;
1032 sctx = talloc_get_type(h->private_data, struct schema_context);
1033 sctx->orig_req->handle = h;
1034 return schema_add_continue(h);
1038 static int schema_modify(struct ldb_module *module, struct ldb_request *req)
1040 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1041 return ldb_next_request(module, req);
1044 return ldb_next_request(module, req);
1047 static int schema_delete(struct ldb_module *module, struct ldb_request *req)
1049 if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */
1050 return ldb_next_request(module, req);
1053 /* First of all check no children exists for this entry */
1055 return ldb_next_request(module, req);
1058 static int schema_rename(struct ldb_module *module, struct ldb_request *req)
1060 if (ldb_dn_is_special(req->op.rename.olddn) &&
1061 ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1062 return ldb_next_request(module, req);
1065 return ldb_next_request(module, req);
1068 static int schema_wait_loop(struct ldb_handle *handle) {
1069 struct schema_context *sctx;
1072 if (!handle || !handle->private_data) {
1073 return LDB_ERR_OPERATIONS_ERROR;
1076 if (handle->state == LDB_ASYNC_DONE) {
1077 return handle->status;
1080 handle->state = LDB_ASYNC_PENDING;
1081 handle->status = LDB_SUCCESS;
1083 sctx = talloc_get_type(handle->private_data, struct schema_context);
1085 switch (sctx->step) {
1086 case SC_ADD_CHECK_PARENT:
1087 ret = ldb_wait(sctx->parent_req->handle, LDB_WAIT_NONE);
1089 if (ret != LDB_SUCCESS) {
1090 handle->status = ret;
1093 if (sctx->parent_req->handle->status != LDB_SUCCESS) {
1094 handle->status = sctx->parent_req->handle->status;
1098 if (sctx->parent_req->handle->state != LDB_ASYNC_DONE) {
1102 return schema_add_continue(handle);
1105 ret = ldb_wait(sctx->down_req->handle, LDB_WAIT_NONE);
1107 if (ret != LDB_SUCCESS) {
1108 handle->status = ret;
1111 if (sctx->down_req->handle->status != LDB_SUCCESS) {
1112 handle->status = sctx->down_req->handle->status;
1116 if (sctx->down_req->handle->state != LDB_ASYNC_DONE) {
1123 ret = LDB_ERR_OPERATIONS_ERROR;
1130 handle->state = LDB_ASYNC_DONE;
1134 static int schema_wait_all(struct ldb_handle *handle) {
1138 while (handle->state != LDB_ASYNC_DONE) {
1139 ret = schema_wait_loop(handle);
1140 if (ret != LDB_SUCCESS) {
1145 return handle->status;
1148 static int schema_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1150 if (type == LDB_WAIT_ALL) {
1151 return schema_wait_all(handle);
1153 return schema_wait_loop(handle);
1157 static int schema_init(struct ldb_module *module)
1159 static const char *schema_attrs[] = { "schemaNamingContext", NULL };
1160 struct schema_private_data *data;
1161 struct ldb_result *res;
1164 /* need to let the partition module to register first */
1165 ret = ldb_next_init(module);
1166 if (ret != LDB_SUCCESS) {
1170 data = ldb_get_opaque(module->ldb, "schema_instance");
1172 module->private_data = data;
1176 data = talloc_zero(module->ldb, struct schema_private_data);
1178 return LDB_ERR_OPERATIONS_ERROR;
1181 /* find the schema partition */
1182 ret = ldb_search(module->ldb,
1183 ldb_dn_new(module, module->ldb, NULL),
1189 if (res->count != 1) {
1190 /* FIXME: return a clear error string */
1193 return LDB_ERR_OPERATIONS_ERROR;
1196 data->schema_dn = ldb_msg_find_attr_as_dn(module->ldb, data, res->msgs[0], "schemaNamingContext");
1197 if (data->schema_dn == NULL) {
1198 /* FIXME: return a clear error string */
1201 return LDB_ERR_OPERATIONS_ERROR;
1206 ret = schema_init_attrs(module, data);
1207 if (ret != LDB_SUCCESS) {
1212 ret = schema_init_classes(module, data);
1213 if (ret != LDB_SUCCESS) {
1218 module->private_data = data;
1219 ldb_set_opaque(module->ldb, "schema_instance", data);
1224 _PUBLIC_ const struct ldb_module_ops ldb_schema_module_ops = {
1226 .init_context = schema_init,
1228 .modify = schema_modify,
1229 .del = schema_delete,
1230 .rename = schema_rename,