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
31 #include "libcli/ldap/ldap.h"
32 #include "ldb/include/ldb_errors.h"
33 #include "ldb/include/ldb_private.h"
34 #include "lib/util/dlinklist.h"
35 #include "schema_syntax.h"
39 see ldap_server/devdocs/AD-syntaxes.txt
42 enum schema_class_type {
44 SCHEMA_CT_STRUCTURAL = 1,
45 SCHEMA_CT_ABSTRACT = 2,
46 SCHEMA_CT_AUXILIARY = 3
49 struct schema_attribute {
50 char *OID; /* attributeID */
51 char *name; /* lDAPDisplayName */
52 enum schema_internal_syntax syntax; /* generated from attributeSyntax, oMSyntax, oMObjectClass */
53 bool single; /* isSingleValued */
54 int min; /* rangeLower */
55 int max; /* rangeUpper */
56 int systemflag; /* systemFlag */
57 int searchflag; /* searchFlag */
58 bool isdefunct; /* isDefunct */
62 char *OID; /* governsID */
63 char *name; /* lDAPDisplayName */
64 enum schema_class_type type; /* objectClassCategory */
65 bool systemOnly; /* systemOnly */
66 bool isdefunct; /* isDefunct */
67 int systemflag; /* systemFlag */
68 char *defobjcat; /* defaultObjectCategory */
69 struct schema_class *parent; /* subClassOf */
70 struct schema_class **sysaux; /* systemAuxiliaryClass */
71 struct schema_class **aux; /* auxiliaryClass */
72 struct schema_class **sysposssup; /* systemPossSuperiors */
73 struct schema_class **posssup; /* possSuperiors */
74 struct schema_class **possinf; /* possibleInferiors */
75 struct schema_attribute **sysmust; /* systemMustContain */
76 struct schema_attribute **must; /* MustContain */
77 struct schema_attribute **sysmay; /* systemMayContain */
78 struct schema_attribute **may; /* MayContain */
81 /* TODO: ditcontentrules */
83 struct schema_private_data {
84 struct ldb_dn *schema_dn;
85 struct schema_attribute **attrs;
86 struct schema_store *attrs_store;
88 struct schema_class **class;
89 struct schema_store *class_store;
93 struct schema_class_dlist {
94 struct schema_class *class;
95 struct schema_class_dlist *prev;
96 struct schema_class_dlist *next;
97 enum schema_class_type role;
100 struct schema_context {
102 enum sc_op { SC_ADD, SC_MOD, SC_DEL, SC_RENAME } op;
103 enum sc_step { SC_INIT, SC_ADD_CHECK_PARENT, SC_ADD_TEMP, SC_DEL_CHECK_CHILDREN } step;
105 struct schema_private_data *data;
107 struct ldb_module *module;
108 struct ldb_request *orig_req;
109 struct ldb_request *down_req;
111 struct ldb_request *parent_req;
112 struct ldb_reply *parent_res;
114 struct schema_class_dlist *class_list;
115 struct schema_class **sup_list;
116 struct schema_class **aux_list;
119 /* FIXME: I'd really like to use an hash table here */
125 struct schema_store {
126 struct schema_link *store;
130 static struct schema_store *schema_store_new(TALLOC_CTX *mem_ctx)
132 struct schema_store *ht;
134 ht = talloc(mem_ctx, struct schema_store);
135 if (!ht) return NULL;
143 static int schema_store_add(struct schema_store *ht, const char *key, void *object)
145 ht->store = talloc_realloc(ht, ht->store, struct schema_link, ht->num_links + 1);
146 if (!ht->store) return LDB_ERR_OPERATIONS_ERROR;
148 ht->store[ht->num_links].name = key;
149 ht->store[ht->num_links].object = object;
156 static void *schema_store_find(struct schema_store *ht, const char *key)
160 for (i = 0; i < ht->num_links; i++) {
161 if (strcasecmp(ht->store[i].name, key) == 0) {
162 return ht->store[i].object;
169 #define SCHEMA_CHECK_VALUE(mem, val, mod) \
170 do { if (mem == val) { \
171 ret = LDB_ERR_OPERATIONS_ERROR; \
172 ldb_asprintf_errstring(mod->ldb, \
173 "schema module: Memory allocation or attribute error on %s", #mem); \
174 goto done; } } while(0)
176 struct schema_class **schema_get_class_list(struct ldb_module *module,
177 struct schema_private_data *data,
178 struct ldb_message_element *el)
180 struct schema_class **list;
183 list = talloc_array(data, struct schema_class *, el->num_values + 1);
185 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
189 for (i = 0; i < el->num_values; i++) {
190 list[i] = (struct schema_class *)schema_store_find(data->class_store,
191 (char *)el->values[i].data);
193 ldb_debug_set(module->ldb,
195 "Class %s referenced but not found in schema\n",
196 (char *)el->values[i].data);
205 struct schema_attribute **schema_get_attrs_list(struct ldb_module *module,
206 struct schema_private_data *data,
207 struct ldb_message_element *el)
209 struct schema_attribute **list;
212 list = talloc_array(data, struct schema_attribute *, el->num_values + 1);
214 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
218 for (i = 0; i < el->num_values; i++) {
219 list[i] = (struct schema_attribute *)schema_store_find(data->attrs_store,
220 (char *)el->values[i].data);
222 ldb_debug_set(module->ldb,
224 "Attriobute %s referenced but not found in schema\n",
225 (char *)el->values[i].data);
234 static int schema_init_attrs(struct ldb_module *module, struct schema_private_data *data)
236 static const char *schema_attrs[] = { "attributeID",
248 struct ldb_result *res;
251 ret = ldb_search(module->ldb,
254 "(objectClass=attributeSchema)",
258 if (ret != LDB_SUCCESS) {
262 data->num_attributes = res->count;
263 data->attrs = talloc_array(data, struct schema_attribute *, res->count);
264 SCHEMA_CHECK_VALUE(data->attrs, NULL, module);
266 data->attrs_store = schema_store_new(data);
267 SCHEMA_CHECK_VALUE(data->attrs_store, NULL, module);
269 for (i = 0; i < res->count; i++) {
270 const char *tmp_single;
271 const char *attr_syntax;
273 const struct ldb_val *om_class;
275 data->attrs[i] = talloc(data->attrs, struct schema_attribute);
276 SCHEMA_CHECK_VALUE(data->attrs[i], NULL, module);
278 data->attrs[i]->OID = talloc_strdup(data->attrs[i],
279 ldb_msg_find_attr_as_string(res->msgs[i], "attributeID", NULL));
280 SCHEMA_CHECK_VALUE(data->attrs[i]->OID, NULL, module);
282 data->attrs[i]->name = talloc_strdup(data->attrs[i],
283 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
284 SCHEMA_CHECK_VALUE(data->attrs[i]->name, NULL, module);
286 /* once we have both the OID and the attribute name, add the pointer to the store */
287 schema_store_add(data->attrs_store, data->attrs[i]->OID, data->attrs[i]);
288 schema_store_add(data->attrs_store, data->attrs[i]->name, data->attrs[i]);
290 attr_syntax = ldb_msg_find_attr_as_string(res->msgs[i], "attributeSyntax", NULL);
291 SCHEMA_CHECK_VALUE(attr_syntax, NULL, module);
293 om_syntax = ldb_msg_find_attr_as_uint(res->msgs[i], "oMSyntax", 0);
294 /* 0 is not a valid oMSyntax */
295 SCHEMA_CHECK_VALUE(om_syntax, 0, module);
297 om_class = ldb_msg_find_ldb_val(res->msgs[i], "oMObjectClass");
299 ret = map_schema_syntax(om_syntax, attr_syntax, om_class, &data->attrs[i]->syntax);
300 if (ret != LDB_SUCCESS) {
301 ldb_asprintf_errstring(module->ldb,
302 "schema module: invalid om syntax value on %s",
303 data->attrs[i]->name);
307 tmp_single = ldb_msg_find_attr_as_string(res->msgs[i], "isSingleValued", NULL);
308 SCHEMA_CHECK_VALUE(tmp_single, NULL, module);
309 if (strcmp(tmp_single, "TRUE") == 0) {
310 data->attrs[i]->single = 1;
312 data->attrs[i]->single = 0;
315 /* the following are optional */
316 data->attrs[i]->min = ldb_msg_find_attr_as_int(res->msgs[i], "rangeLower", INT_MIN);
317 data->attrs[i]->max = ldb_msg_find_attr_as_int(res->msgs[i], "rangeUpper", INT_MAX);
318 data->attrs[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
319 data->attrs[i]->searchflag = ldb_msg_find_attr_as_int(res->msgs[i], "searchFlag", 0);
320 data->attrs[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", false);
328 static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data)
330 const char *schema_attrs[] = { "governsID",
332 "objectClassCategory",
333 "defaultObjectCategory",
338 "systemAuxiliaryClass",
340 "systemPossSuperiors",
348 struct ldb_result *res;
351 ret = ldb_search(module->ldb,
354 "(objectClass=classSchema)",
358 if (ret != LDB_SUCCESS) {
362 data->num_classes = res->count;
363 data->class = talloc_array(data, struct schema_class *, res->count);
364 SCHEMA_CHECK_VALUE(data->class, NULL, module);
366 data->class_store = schema_store_new(data);
367 SCHEMA_CHECK_VALUE(data->class_store, NULL, module);
369 for (i = 0; i < res->count; i++) {
370 struct ldb_message_element *el;
372 data->class[i] = talloc(data->class, struct schema_class);
373 SCHEMA_CHECK_VALUE(data->class[i], NULL, module);
375 data->class[i]->OID = talloc_strdup(data->class[i],
376 ldb_msg_find_attr_as_string(res->msgs[i], "governsID", NULL));
377 SCHEMA_CHECK_VALUE(data->class[i]->OID, NULL, module);
379 data->class[i]->name = talloc_strdup(data->class[i],
380 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
381 SCHEMA_CHECK_VALUE(data->class[i]->name, NULL, module);
383 /* once we have both the OID and the class name, add the pointer to the store */
384 schema_store_add(data->class_store, data->class[i]->OID, data->class[i]);
385 schema_store_add(data->class_store, data->class[i]->name, data->class[i]);
387 data->class[i]->type = ldb_msg_find_attr_as_int(res->msgs[i], "objectClassCategory", -1);
388 /* 0 should not be a valid value, but turn out it is so test with -1 */
389 SCHEMA_CHECK_VALUE(data->class[i]->type, -1, module);
391 data->class[i]->defobjcat = talloc_strdup(data->class[i],
392 ldb_msg_find_attr_as_string(res->msgs[i],
393 "defaultObjectCategory", NULL));
394 /* SCHEMA_CHECK_VALUE(data->class[i]->defobjcat, NULL, module);
396 /* the following attributes are all optional */
398 data->class[i]->systemOnly = ldb_msg_find_attr_as_bool(res->msgs[i], "systemOnly", false);
399 data->class[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
400 data->class[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", false);
402 /* attributes are loaded first, so we can just go an query the attributes repo */
404 el = ldb_msg_find_element(res->msgs[i], "systemMustContain");
406 data->class[i]->sysmust = schema_get_attrs_list(module, data, el);
407 SCHEMA_CHECK_VALUE(data->class[i]->sysmust, NULL, module);
410 el = ldb_msg_find_element(res->msgs[i], "MustContain");
412 data->class[i]->must = schema_get_attrs_list(module, data, el);
413 SCHEMA_CHECK_VALUE(data->class[i]->must, NULL, module);
416 el = ldb_msg_find_element(res->msgs[i], "systemMayContain");
418 data->class[i]->sysmay = schema_get_attrs_list(module, data, el);
419 SCHEMA_CHECK_VALUE(data->class[i]->sysmay, NULL, module);
422 el = ldb_msg_find_element(res->msgs[i], "MayContain");
424 data->class[i]->may = schema_get_attrs_list(module, data, el);
425 SCHEMA_CHECK_VALUE(data->class[i]->may, NULL, module);
430 /* subClassOf, systemAuxiliaryClass, auxiliaryClass, systemPossSuperiors
431 * must be filled in a second loop, when all class objects are allocated
432 * or we may not find a class that has not yet been parsed */
433 for (i = 0; i < res->count; i++) {
434 struct ldb_message_element *el;
437 /* this is single valued anyway */
438 attr = ldb_msg_find_attr_as_string(res->msgs[i], "subClassOf", NULL);
439 SCHEMA_CHECK_VALUE(attr, NULL, module);
440 data->class[i]->parent = schema_store_find(data->class_store, attr);
441 SCHEMA_CHECK_VALUE(data->class[i]->parent, NULL, module);
443 /* the following attributes are all optional */
445 data->class[i]->sysaux = NULL;
446 el = ldb_msg_find_element(res->msgs[i], "systemAuxiliaryClass");
448 data->class[i]->sysaux = schema_get_class_list(module, data, el);
449 SCHEMA_CHECK_VALUE(data->class[i]->sysaux, NULL, module);
452 data->class[i]->aux = NULL;
453 el = ldb_msg_find_element(res->msgs[i], "auxiliaryClass");
455 data->class[i]->aux = schema_get_class_list(module, data, el);
456 SCHEMA_CHECK_VALUE(data->class[i]->aux, NULL, module);
459 data->class[i]->sysposssup = NULL;
460 el = ldb_msg_find_element(res->msgs[i], "systemPossSuperiors");
462 data->class[i]->sysposssup = schema_get_class_list(module, data, el);
463 SCHEMA_CHECK_VALUE(data->class[i]->sysposssup, NULL, module);
466 data->class[i]->posssup = NULL;
467 el = ldb_msg_find_element(res->msgs[i], "possSuperiors");
469 data->class[i]->posssup = schema_get_class_list(module, data, el);
470 SCHEMA_CHECK_VALUE(data->class[i]->posssup, NULL, module);
473 data->class[i]->possinf = NULL;
474 el = ldb_msg_find_element(res->msgs[i], "possibleInferiors");
476 data->class[i]->possinf = schema_get_class_list(module, data, el);
477 SCHEMA_CHECK_VALUE(data->class[i]->possinf, NULL, module);
486 static struct ldb_handle *schema_init_handle(struct ldb_request *req, struct ldb_module *module, enum sc_op op)
488 struct schema_context *sctx;
489 struct ldb_handle *h;
491 h = talloc_zero(req, struct ldb_handle);
493 ldb_set_errstring(module->ldb, "Out of Memory");
499 sctx = talloc_zero(h, struct schema_context);
501 ldb_set_errstring(module->ldb, "Out of Memory");
506 h->private_data = (void *)sctx;
508 h->state = LDB_ASYNC_INIT;
509 h->status = LDB_SUCCESS;
512 sctx->step = SC_INIT;
513 sctx->data = module->private_data;
514 sctx->module = module;
515 sctx->orig_req = req;
520 static int schema_add_check_parent(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
522 struct schema_context *sctx;
524 sctx = talloc_get_type(context, struct schema_context);
526 /* we are interested only in the single reply (base search) we receive here */
527 if (ares->type == LDB_REPLY_ENTRY) {
528 if (sctx->parent_res != NULL) {
529 ldb_set_errstring(ldb, "Too many results");
531 return LDB_ERR_OPERATIONS_ERROR;
533 sctx->parent_res = talloc_steal(sctx, ares);
541 static int schema_add_build_parent_req(struct schema_context *sctx)
543 const char * const parent_attrs[] = { "objectClass", NULL };
546 sctx->parent_req = talloc_zero(sctx, struct ldb_request);
547 if (sctx->parent_req == NULL) {
548 ldb_debug(sctx->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
549 return LDB_ERR_OPERATIONS_ERROR;
552 sctx->parent_req->operation = LDB_SEARCH;
553 sctx->parent_req->op.search.scope = LDB_SCOPE_BASE;
554 sctx->parent_req->op.search.base = ldb_dn_get_parent(sctx->parent_req, sctx->orig_req->op.add.message->dn);
555 sctx->parent_req->op.search.tree = ldb_parse_tree(sctx->parent_req, "(objectClass=*)");
556 sctx->parent_req->op.search.attrs = parent_attrs;
557 sctx->parent_req->controls = NULL;
558 sctx->parent_req->context = sctx;
559 sctx->parent_req->callback = schema_add_check_parent;
560 ret = ldb_set_timeout_from_prev_req(sctx->module->ldb, sctx->orig_req, sctx->parent_req);
565 static struct schema_class_dlist *schema_add_get_dlist_entry_with_class(struct schema_class_dlist *list, struct schema_class *class)
567 struct schema_class_dlist *temp;
569 for (temp = list; temp && (temp->class != class); temp = temp->next) /* noop */ ;
573 static int schema_add_class_to_dlist(struct schema_class_dlist *list, struct schema_class *class, enum schema_class_type role)
575 struct schema_class_dlist *entry;
576 struct schema_class_dlist *temp;
579 /* see if this class is usable */
580 if (class->isdefunct) {
581 return LDB_ERR_NO_SUCH_ATTRIBUTE;
584 /* see if this class already exist in the class list */
585 if (schema_add_get_dlist_entry_with_class(list, class)) {
589 /* this is a new class go on and add to the list */
590 entry = talloc_zero(list, struct schema_class_dlist);
591 if (!entry) return LDB_ERR_OPERATIONS_ERROR;
592 entry->class = class;
593 entry->role = class->type;
595 /* If parent is top (list is guaranteed to start always with top) */
596 if (class->parent == list->class) {
597 /* if the hierarchy role is structural try to add it just after top */
598 if (role == SCHEMA_CT_STRUCTURAL) {
599 /* but check no other class at after top has a structural role */
600 if (list->next && (list->next->role == SCHEMA_CT_STRUCTURAL)) {
601 return LDB_ERR_OBJECT_CLASS_VIOLATION;
603 DLIST_ADD_AFTER(list, entry, list);
605 DLIST_ADD_END(list, entry, struct schema_class_dlist *);
610 /* search if parent has already been added */
611 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
613 ret = schema_add_class_to_dlist(list, class->parent, role);
614 if (ret != LDB_SUCCESS) {
617 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
619 if (!temp) { /* parent not found !? */
620 return LDB_ERR_OPERATIONS_ERROR;
623 DLIST_ADD_AFTER(list, entry, temp);
624 if (role == SCHEMA_CT_STRUCTURAL || role == SCHEMA_CT_AUXILIARY) {
629 /* stop when hierarchy base is met or when base class parent is top */
630 } while (temp->class == temp->next->class->parent &&
631 temp->next->class->parent != list->class);
633 /* if we have not reached the head of the list
634 * and role is structural */
635 if (temp != list && role == SCHEMA_CT_STRUCTURAL) {
636 struct schema_class_dlist *hfirst, *hlast;
638 /* check if the list second entry is structural */
639 if (list->next->role == SCHEMA_CT_STRUCTURAL) {
640 /* we have a confilict here */
641 return LDB_ERR_OBJECT_CLASS_VIOLATION;
643 /* we have to move this hierarchy of classes
644 * so that the base of the structural hierarchy is right after top */
648 /* now hfirst - hlast are the boundaries of the structural hierarchy */
650 /* extract the structural hierachy from the list */
651 hfirst->prev->next = hlast->next;
652 if (hlast->next) hlast->next->prev = hfirst->prev;
654 /* insert the structural hierarchy just after top */
655 list->next->prev = hlast;
656 hlast->next = list->next;
665 /* merge source list into dest list and remove duplicates */
666 static int schema_merge_class_list(TALLOC_CTX *mem_ctx, struct schema_class ***dest, struct schema_class **source)
668 struct schema_class **list = *dest;
672 if (list) for (n = 0; list[n]; n++) /* noop */ ;
675 for (i = 0; source[i]; i++) {
676 for (j = 0; j < f; j++) {
677 if (list[j] == source[i]) {
681 if (j < f) { /* duplicate found */
685 list = talloc_realloc(mem_ctx, list, struct schema_class *, n + 2);
687 return LDB_ERR_OPERATIONS_ERROR;
699 /* validate and modify the objectclass attribute to sort and add parents */
700 static int schema_add_build_objectclass_list(struct schema_context *sctx)
702 struct schema_class_dlist *temp;
703 struct ldb_message_element * el;
704 struct schema_class *class;
707 /* First of all initialize list, it must start with class top */
708 sctx->class_list = talloc_zero(sctx, struct schema_class_dlist);
709 if (!sctx->class_list) return LDB_ERR_OPERATIONS_ERROR;
711 sctx->class_list->class = schema_store_find(sctx->data->class_store, "top");
712 if (!sctx->class_list->class) return LDB_ERR_OPERATIONS_ERROR;
714 el = ldb_msg_find_element(sctx->orig_req->op.add.message, "objectClass");
716 return LDB_ERR_OBJECT_CLASS_VIOLATION;
719 for (i = 0; i < el->num_values; i++) {
721 class = schema_store_find(sctx->data->class_store, (char *)el->values[i].data);
723 return LDB_ERR_NO_SUCH_ATTRIBUTE;
726 ret = schema_add_class_to_dlist(sctx->class_list, class, class->type);
727 if (ret != LDB_SUCCESS) {
732 /* now check if there is any class role that is still not STRUCTURAL or AUXILIARY */
733 /* build also the auxiliary class list and the possible superiors list */
734 temp = sctx->class_list->next; /* top is special, skip it */
738 if (temp->role == SCHEMA_CT_ABSTRACT || temp->role == SCHEMA_CT_88) {
739 return LDB_ERR_OBJECT_CLASS_VIOLATION;
741 if (temp->class->sysaux) {
742 ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->sysaux);
743 if (ret != LDB_SUCCESS) {
744 return LDB_ERR_OPERATIONS_ERROR;
747 if (temp->class->aux) {
748 ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->aux);
749 if (ret != LDB_SUCCESS) {
750 return LDB_ERR_OPERATIONS_ERROR;
753 if (temp->class->sysposssup) {
754 ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->sysposssup);
755 if (ret != LDB_SUCCESS) {
756 return LDB_ERR_OPERATIONS_ERROR;
759 if (temp->class->posssup) {
760 ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->posssup);
761 if (ret != LDB_SUCCESS) {
762 return LDB_ERR_OPERATIONS_ERROR;
768 /* complete sup_list with material from the aux classes */
769 for (i = 0; sctx->aux_list && sctx->aux_list[i]; i++) {
770 if (sctx->aux_list[i]->sysposssup) {
771 ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->sysposssup);
772 if (ret != LDB_SUCCESS) {
773 return LDB_ERR_OPERATIONS_ERROR;
776 if (sctx->aux_list[i]->posssup) {
777 ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->posssup);
778 if (ret != LDB_SUCCESS) {
779 return LDB_ERR_OPERATIONS_ERROR;
784 if (!sctx->sup_list) return LDB_ERR_NAMING_VIOLATION;
789 static int schema_add_check_container_constraints(struct schema_context *sctx)
791 struct schema_class **parent_possinf = NULL;
792 struct schema_class **parent_classes;
793 struct schema_class_dlist *temp;
794 struct ldb_message_element *el;
797 el = ldb_msg_find_element(sctx->parent_res->message, "objectClass");
800 return LDB_ERR_OPERATIONS_ERROR;
803 parent_classes = talloc_array(sctx, struct schema_class *, el->num_values + 1);
805 for (i = 0; i < el->num_values; i++) {
807 parent_classes[i] = schema_store_find(sctx->data->class_store, (const char *)el->values[i].data);
808 if (!parent_classes[i]) { /* should not be possible */
809 return LDB_ERR_OPERATIONS_ERROR;
812 if (parent_classes[i]->possinf) {
813 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->possinf);
814 if (ret != LDB_SUCCESS) {
815 return LDB_ERR_OPERATIONS_ERROR;
819 /* check also embedded auxiliary classes possinf */
820 for (j = 0; parent_classes[i]->sysaux && parent_classes[i]->sysaux[j]; j++) {
821 if (parent_classes[i]->sysaux[j]->possinf) {
822 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->sysaux[j]->possinf);
823 if (ret != LDB_SUCCESS) {
824 return LDB_ERR_OPERATIONS_ERROR;
828 for (j = 0; parent_classes[i]->aux && parent_classes[i]->aux[j]; j++) {
829 if (parent_classes[i]->aux[j]->possinf) {
830 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->aux[j]->possinf);
831 if (ret != LDB_SUCCESS) {
832 return LDB_ERR_OPERATIONS_ERROR;
838 /* foreach parent objectclass,
839 * check parent possible inferiors match all of the child objectclasses
841 * poss Superiors of the child objectclasses mathes one of the parent classes
844 temp = sctx->class_list->next; /* skip top it is special */
847 for (i = 0; parent_possinf[i]; i++) {
848 if (temp->class == parent_possinf[i]) {
852 if (parent_possinf[i] == NULL) {
853 /* class not found in possible inferiors */
854 return LDB_ERR_NAMING_VIOLATION;
860 for (i = 0; parent_classes[i]; i++) {
861 for (j = 0; sctx->sup_list[j]; j++) {
862 if (sctx->sup_list[j] == parent_classes[i]) {
866 if (sctx->sup_list[j]) { /* possible Superiors match one of the parent classes */
871 /* no parent classes matched superiors */
872 return LDB_ERR_NAMING_VIOLATION;
875 static int schema_add_build_down_req(struct schema_context *sctx)
877 struct schema_class_dlist *temp;
878 struct ldb_message *msg;
881 sctx->down_req = talloc(sctx, struct ldb_request);
882 if (!sctx->down_req) {
883 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
884 return LDB_ERR_OPERATIONS_ERROR;
887 *(sctx->down_req) = *(sctx->orig_req); /* copy the request */
888 msg = ldb_msg_copy_shallow(sctx->down_req, sctx->orig_req->op.add.message);
890 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
891 return LDB_ERR_OPERATIONS_ERROR;
894 /* rebuild the objectclass list */
895 ldb_msg_remove_attr(msg, "objectClass");
896 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
897 if (ret != LDB_SUCCESS) {
901 /* Add the complete list of classes back to the message */
902 for (temp = sctx->class_list; temp; temp = temp->next) {
903 ret = ldb_msg_add_string(msg, "objectClass", temp->class->name);
904 if (ret != LDB_SUCCESS) {
909 /* objectCategory can be set only by the system */
910 if (ldb_msg_find_element(msg, "objectCategory")) {
911 return LDB_ERR_CONSTRAINT_VIOLATION;
914 /* the OC is mandatory, every class defines it */
915 /* use the one defined in the structural class that defines the object */
916 for (temp = sctx->class_list->next; temp; temp = temp->next) {
917 if (!temp->next) break;
918 if (temp->next->role != SCHEMA_CT_STRUCTURAL) break;
920 /* oc = talloc_strdup(msg, temp->class->defobjcat);
921 ret = ldb_msg_add_string(msg, "objectCategory", oc);
923 sctx->down_req->op.add.message = msg;
928 static int schema_check_attributes_syntax(struct schema_context *sctx)
930 struct ldb_message *msg;
931 struct schema_attribute *attr;
934 msg = sctx->orig_req->op.add.message;
935 for (i = 0; i < msg->num_elements; i++) {
936 attr = schema_store_find(sctx->data->attrs_store, msg->elements[i].name);
938 return LDB_ERR_NO_SUCH_ATTRIBUTE;
940 ret = schema_validate(sctx->module->ldb, &msg->elements[i], attr->syntax, attr->single, attr->min, attr->max);
941 if (ret != LDB_SUCCESS) {
949 static int schema_add_continue(struct ldb_handle *h)
951 struct schema_context *sctx;
954 sctx = talloc_get_type(h->private_data, struct schema_context);
956 switch (sctx->step) {
959 /* First of all check that a parent exists for this entry */
960 ret = schema_add_build_parent_req(sctx);
961 if (ret != LDB_SUCCESS) {
965 sctx->step = SC_ADD_CHECK_PARENT;
966 return ldb_next_request(sctx->module, sctx->parent_req);
968 case SC_ADD_CHECK_PARENT:
970 /* parent search done, check result and go on */
971 if (sctx->parent_res == NULL) {
972 /* we must have a parent */
973 ret = LDB_ERR_NO_SUCH_OBJECT;
977 /* Check objectclasses are ok */
978 ret = schema_add_build_objectclass_list(sctx);
979 if (ret != LDB_SUCCESS) {
983 /* check the parent is of the right type for this object */
984 ret = schema_add_check_container_constraints(sctx);
985 if (ret != LDB_SUCCESS) {
989 /* check attributes syntax */
991 ret = schema_check_attributes_syntax(sctx);
992 if (ret != LDB_SUCCESS) {
996 ret = schema_add_build_down_req(sctx);
997 if (ret != LDB_SUCCESS) {
1000 sctx->step = SC_ADD_TEMP;
1002 return ldb_next_request(sctx->module, sctx->down_req);
1005 ret = LDB_ERR_OPERATIONS_ERROR;
1009 /* this is reached only in case of error */
1010 /* FIXME: fire an async reply ? */
1012 h->state = LDB_ASYNC_DONE;
1016 static int schema_add(struct ldb_module *module, struct ldb_request *req)
1018 struct schema_context *sctx;
1019 struct ldb_handle *h;
1021 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1022 return ldb_next_request(module, req);
1025 h = schema_init_handle(req, module, SC_ADD);
1027 return LDB_ERR_OPERATIONS_ERROR;
1030 sctx = talloc_get_type(h->private_data, struct schema_context);
1031 sctx->orig_req->handle = h;
1032 return schema_add_continue(h);
1036 static int schema_modify(struct ldb_module *module, struct ldb_request *req)
1038 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1039 return ldb_next_request(module, req);
1042 return ldb_next_request(module, req);
1045 static int schema_delete(struct ldb_module *module, struct ldb_request *req)
1047 if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */
1048 return ldb_next_request(module, req);
1051 /* First of all check no children exists for this entry */
1053 return ldb_next_request(module, req);
1056 static int schema_rename(struct ldb_module *module, struct ldb_request *req)
1058 if (ldb_dn_is_special(req->op.rename.olddn) &&
1059 ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1060 return ldb_next_request(module, req);
1063 return ldb_next_request(module, req);
1066 static int schema_wait_loop(struct ldb_handle *handle) {
1067 struct schema_context *sctx;
1070 if (!handle || !handle->private_data) {
1071 return LDB_ERR_OPERATIONS_ERROR;
1074 if (handle->state == LDB_ASYNC_DONE) {
1075 return handle->status;
1078 handle->state = LDB_ASYNC_PENDING;
1079 handle->status = LDB_SUCCESS;
1081 sctx = talloc_get_type(handle->private_data, struct schema_context);
1083 switch (sctx->step) {
1084 case SC_ADD_CHECK_PARENT:
1085 ret = ldb_wait(sctx->parent_req->handle, LDB_WAIT_NONE);
1087 if (ret != LDB_SUCCESS) {
1088 handle->status = ret;
1091 if (sctx->parent_req->handle->status != LDB_SUCCESS) {
1092 handle->status = sctx->parent_req->handle->status;
1096 if (sctx->parent_req->handle->state != LDB_ASYNC_DONE) {
1100 return schema_add_continue(handle);
1103 ret = ldb_wait(sctx->down_req->handle, LDB_WAIT_NONE);
1105 if (ret != LDB_SUCCESS) {
1106 handle->status = ret;
1109 if (sctx->down_req->handle->status != LDB_SUCCESS) {
1110 handle->status = sctx->down_req->handle->status;
1114 if (sctx->down_req->handle->state != LDB_ASYNC_DONE) {
1121 ret = LDB_ERR_OPERATIONS_ERROR;
1128 handle->state = LDB_ASYNC_DONE;
1132 static int schema_wait_all(struct ldb_handle *handle) {
1136 while (handle->state != LDB_ASYNC_DONE) {
1137 ret = schema_wait_loop(handle);
1138 if (ret != LDB_SUCCESS) {
1143 return handle->status;
1146 static int schema_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1148 if (type == LDB_WAIT_ALL) {
1149 return schema_wait_all(handle);
1151 return schema_wait_loop(handle);
1155 static int schema_init(struct ldb_module *module)
1157 static const char *schema_attrs[] = { "schemaNamingContext", NULL };
1158 struct schema_private_data *data;
1159 struct ldb_result *res;
1162 /* need to let the partition module to register first */
1163 ret = ldb_next_init(module);
1164 if (ret != LDB_SUCCESS) {
1168 data = ldb_get_opaque(module->ldb, "schema_instance");
1170 module->private_data = data;
1174 data = talloc_zero(module->ldb, struct schema_private_data);
1176 return LDB_ERR_OPERATIONS_ERROR;
1179 /* find the schema partition */
1180 ret = ldb_search(module->ldb,
1181 ldb_dn_new(module, module->ldb, NULL),
1187 if (res->count != 1) {
1188 /* FIXME: return a clear error string */
1191 return LDB_ERR_OPERATIONS_ERROR;
1194 data->schema_dn = ldb_msg_find_attr_as_dn(module->ldb, data, res->msgs[0], "schemaNamingContext");
1195 if (data->schema_dn == NULL) {
1196 /* FIXME: return a clear error string */
1199 return LDB_ERR_OPERATIONS_ERROR;
1204 ret = schema_init_attrs(module, data);
1205 if (ret != LDB_SUCCESS) {
1210 ret = schema_init_classes(module, data);
1211 if (ret != LDB_SUCCESS) {
1216 module->private_data = data;
1217 ldb_set_opaque(module->ldb, "schema_instance", data);
1222 _PUBLIC_ const struct ldb_module_ops ldb_schema_module_ops = {
1224 .init_context = schema_init,
1226 .modify = schema_modify,
1227 .del = schema_delete,
1228 .rename = schema_rename,