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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Component: ldb schema module
26 * Description: add schema check functionality
30 * License: GNU GPL v2 or Later
34 #include "libcli/ldap/ldap.h"
35 #include "ldb/include/ldb_errors.h"
36 #include "ldb/include/ldb_private.h"
37 #include "include/dlinklist.h"
41 see ldap_server/devdocs/AD-syntaxes.txt
44 enum schema_internal_syntax {
47 SCHEMA_AS_OCTET_STRING,
50 SCHEMA_AS_ENUMERATION,
51 SCHEMA_AS_NUMERIC_STRING,
52 SCHEMA_AS_PRINTABLE_STRING,
53 SCHEMA_AS_CASE_IGNORE_STRING,
56 SCHEMA_AS_GENERALIZED_TIME,
57 SCHEMA_AS_CASE_SENSITIVE_STRING,
58 SCHEMA_AS_DIRECTORY_STRING,
59 SCHEMA_AS_LARGE_INTEGER,
60 SCHEMA_AS_OBJECT_SECURITY_DESCRIPTOR,
64 SCHEMA_AS_REPLICA_LINK,
65 SCHEMA_AS_PRESENTATION_ADDRESS,
66 SCHEMA_AS_ACCESS_POINT,
70 enum schema_class_type {
72 SCHEMA_CT_STRUCTURAL = 1,
73 SCHEMA_CT_ABSTRACT = 2,
74 SCHEMA_CT_AUXILIARY = 3
77 struct schema_attribute {
78 char *OID; /* attributeID */
79 char *name; /* lDAPDisplayName */
80 enum schema_internal_syntax syntax; /* generated from attributeSyntax, oMSyntax, oMObjectClass */
81 bool single; /* isSingleValued */
82 int min; /* rangeLower */
83 int max; /* rangeUpper */
84 int systemflag; /* systemFlag */
85 int searchflag; /* searchFlag */
86 bool isdefunct; /* isDefunct */
90 char *OID; /* governsID */
91 char *name; /* lDAPDisplayName */
92 enum schema_class_type type; /* objectClassCategory */
93 bool systemOnly; /* systemOnly */
94 bool isdefunct; /* isDefunct */
95 int systemflag; /* systemFlag */
96 char *defobjcat; /* defaultObjectCategory */
97 struct schema_class *parent; /* subClassOf */
98 struct schema_class **sysaux; /* systemAuxiliaryClass */
99 struct schema_class **aux; /* auxiliaryClass */
100 struct schema_class **sysposssup; /* systemPossSuperiors */
101 struct schema_class **posssup; /* possSuperiors */
102 struct schema_class **possinf; /* possibleInferiors */
103 struct schema_attribute **sysmust; /* systemMustContain */
104 struct schema_attribute **must; /* MustContain */
105 struct schema_attribute **sysmay; /* systemMayContain */
106 struct schema_attribute **may; /* MayContain */
109 /* TODO: ditcontentrules */
111 struct schema_private_data {
112 struct ldb_dn *schema_dn;
113 struct schema_attribute **attrs;
114 struct schema_store *attrs_store;
116 struct schema_class **class;
117 struct schema_store *class_store;
121 struct schema_class_dlist {
122 struct schema_class *class;
123 struct schema_class_dlist *prev;
124 struct schema_class_dlist *next;
125 enum schema_class_type role;
128 struct schema_context {
130 enum sc_op { SC_ADD, SC_MOD, SC_DEL, SC_RENAME } op;
131 enum sc_step { SC_INIT, SC_ADD_CHECK_PARENT, SC_ADD_TEMP, SC_DEL_CHECK_CHILDREN } step;
133 struct schema_private_data *data;
135 struct ldb_module *module;
136 struct ldb_request *orig_req;
137 struct ldb_request *down_req;
139 struct ldb_request *parent_req;
140 struct ldb_reply *parent_res;
142 struct schema_class_dlist *class_list;
143 struct schema_class **sup_list;
144 struct schema_class **aux_list;
147 /* FIXME: I'd really like to use an hash table here */
153 struct schema_store {
154 struct schema_link *store;
158 static struct schema_store *schema_store_new(TALLOC_CTX *mem_ctx)
160 struct schema_store *ht;
162 ht = talloc(mem_ctx, struct schema_store);
163 if (!ht) return NULL;
171 static int schema_store_add(struct schema_store *ht, const char *key, void *object)
173 ht->store = talloc_realloc(ht, ht->store, struct schema_link, ht->num_links + 1);
174 if (!ht->store) return LDB_ERR_OPERATIONS_ERROR;
176 ht->store[ht->num_links].name = key;
177 ht->store[ht->num_links].object = object;
184 static void *schema_store_find(struct schema_store *ht, const char *key)
188 for (i = 0; i < ht->num_links; i++) {
189 if (strcasecmp(ht->store[i].name, key) == 0) {
190 return ht->store[i].object;
197 #define SCHEMA_CHECK_VALUE(mem, val, mod) \
198 do { if (mem == val) { \
199 ret = LDB_ERR_OPERATIONS_ERROR; \
200 ldb_asprintf_errstring(mod->ldb, \
201 "schema module: Memory allocation or attribute error on %s", #mem); \
202 goto done; } } while(0)
204 struct schema_class **schema_get_class_list(struct ldb_module *module,
205 struct schema_private_data *data,
206 struct ldb_message_element *el)
208 struct schema_class **list;
211 list = talloc_array(data, struct schema_class *, el->num_values + 1);
213 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
217 for (i = 0; i < el->num_values; i++) {
218 list[i] = (struct schema_class *)schema_store_find(data->class_store,
219 (char *)el->values[i].data);
221 ldb_debug_set(module->ldb,
223 "Class %s referenced but not found in schema\n",
224 (char *)el->values[i].data);
233 struct schema_attribute **schema_get_attrs_list(struct ldb_module *module,
234 struct schema_private_data *data,
235 struct ldb_message_element *el)
237 struct schema_attribute **list;
240 list = talloc_array(data, struct schema_attribute *, el->num_values + 1);
242 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
246 for (i = 0; i < el->num_values; i++) {
247 list[i] = (struct schema_attribute *)schema_store_find(data->attrs_store,
248 (char *)el->values[i].data);
250 ldb_debug_set(module->ldb,
252 "Attriobute %s referenced but not found in schema\n",
253 (char *)el->values[i].data);
262 static int map_schema_syntax(uint32_t om_syntax, const char *attr_syntax, const struct ldb_val *om_class, enum schema_internal_syntax *syntax)
270 *syntax = SCHEMA_AS_BOOLEAN;
273 *syntax = SCHEMA_AS_INTEGER;
276 if (strcmp(attr_syntax, "2.5.5.10") == 0) {
277 *syntax = SCHEMA_AS_OCTET_STRING;
280 if (strcmp(attr_syntax, "2.5.5.17") == 0) {
281 *syntax = SCHEMA_AS_SID;
284 ret = LDB_ERR_OPERATIONS_ERROR;
287 *syntax = SCHEMA_AS_OID;
290 *syntax = SCHEMA_AS_ENUMERATION;
293 *syntax = SCHEMA_AS_NUMERIC_STRING;
296 *syntax = SCHEMA_AS_PRINTABLE_STRING;
299 *syntax = SCHEMA_AS_CASE_IGNORE_STRING;
302 *syntax = SCHEMA_AS_IA5_STRING;
305 *syntax = SCHEMA_AS_UTC_TIME;
308 *syntax = SCHEMA_AS_GENERALIZED_TIME;
311 *syntax = SCHEMA_AS_CASE_SENSITIVE_STRING;
314 *syntax = SCHEMA_AS_DIRECTORY_STRING;
317 *syntax = SCHEMA_AS_LARGE_INTEGER;
320 *syntax = SCHEMA_AS_OBJECT_SECURITY_DESCRIPTOR;
324 ret = LDB_ERR_OPERATIONS_ERROR;
328 if (memcmp(om_class->data, "\x2b\x0c\x02\x87\x73\x1c\x00\x85\x4a\x00", MIN(om_class->length, 10)) == 0) {
329 *syntax = SCHEMA_AS_DN;
332 if (memcmp(om_class->data, "\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0b", MIN(om_class->length, 10)) == 0) {
333 *syntax = SCHEMA_AS_DN_BINARY;
336 if (memcmp(om_class->data, "\x56\x06\x01\x02\x05\x0b\x1d\x00\x00\x00", MIN(om_class->length, 10)) == 0) {
337 *syntax = SCHEMA_AS_OR_NAME;
340 if (memcmp(om_class->data, "\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x06", MIN(om_class->length, 10)) == 0) {
341 *syntax = SCHEMA_AS_REPLICA_LINK;
344 if (memcmp(om_class->data, "\x2b\x0c\x02\x87\x73\x1c\x00\x85\x5c\x00", MIN(om_class->length, 10)) == 0) {
345 *syntax = SCHEMA_AS_PRESENTATION_ADDRESS;
348 if (memcmp(om_class->data, "\x2b\x0c\x02\x87\x73\x1c\x00\x85\x3e\x00", MIN(om_class->length, 10)) == 0) {
349 *syntax = SCHEMA_AS_ACCESS_POINT;
352 if (memcmp(om_class->data, "\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0c", MIN(om_class->length, 10)) == 0) {
353 *syntax = SCHEMA_AS_DN_STRING;
356 /* not found will error in default: */
358 ret = LDB_ERR_OPERATIONS_ERROR;
364 static int schema_init_attrs(struct ldb_module *module, struct schema_private_data *data)
366 static const char *schema_attrs[] = { "attributeID",
378 struct ldb_result *res;
381 ret = ldb_search(module->ldb,
384 "(objectClass=attributeSchema)",
388 if (ret != LDB_SUCCESS) {
392 data->num_attributes = res->count;
393 data->attrs = talloc_array(data, struct schema_attribute *, res->count);
394 SCHEMA_CHECK_VALUE(data->attrs, NULL, module);
396 data->attrs_store = schema_store_new(data);
397 SCHEMA_CHECK_VALUE(data->attrs_store, NULL, module);
399 for (i = 0; i < res->count; i++) {
400 const char *tmp_single;
401 const char *attr_syntax;
403 const struct ldb_val *om_class;
405 data->attrs[i] = talloc(data->attrs, struct schema_attribute);
406 SCHEMA_CHECK_VALUE(data->attrs[i], NULL, module);
408 data->attrs[i]->OID = talloc_strdup(data->attrs[i],
409 ldb_msg_find_attr_as_string(res->msgs[i], "attributeID", NULL));
410 SCHEMA_CHECK_VALUE(data->attrs[i]->OID, NULL, module);
412 data->attrs[i]->name = talloc_strdup(data->attrs[i],
413 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
414 SCHEMA_CHECK_VALUE(data->attrs[i]->name, NULL, module);
416 /* once we have both the OID and the attribute name, add the pointer to the store */
417 schema_store_add(data->attrs_store, data->attrs[i]->OID, data->attrs[i]);
418 schema_store_add(data->attrs_store, data->attrs[i]->name, data->attrs[i]);
420 attr_syntax = ldb_msg_find_attr_as_string(res->msgs[i], "attributeSyntax", NULL);
421 SCHEMA_CHECK_VALUE(attr_syntax, NULL, module);
423 om_syntax = ldb_msg_find_attr_as_uint(res->msgs[i], "oMSyntax", 0);
424 /* 0 is not a valid oMSyntax */
425 SCHEMA_CHECK_VALUE(om_syntax, 0, module);
427 om_class = ldb_msg_find_ldb_val(res->msgs[i], "oMObjectClass");
429 ret = map_schema_syntax(om_syntax, attr_syntax, om_class, &data->attrs[i]->syntax);
430 if (ret != LDB_SUCCESS) {
431 ldb_asprintf_errstring(module->ldb,
432 "schema module: invalid om syntax value on %s",
433 data->attrs[i]->name);
437 tmp_single = ldb_msg_find_attr_as_string(res->msgs[i], "isSingleValued", NULL);
438 SCHEMA_CHECK_VALUE(tmp_single, NULL, module);
439 if (strcmp(tmp_single, "TRUE") == 0) {
440 data->attrs[i]->single = 1;
442 data->attrs[i]->single = 0;
445 /* the following are optional */
446 data->attrs[i]->min = ldb_msg_find_attr_as_int(res->msgs[i], "rangeLower", -1);
447 data->attrs[i]->max = ldb_msg_find_attr_as_int(res->msgs[i], "rangeUpper", -1);
448 data->attrs[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
449 data->attrs[i]->searchflag = ldb_msg_find_attr_as_int(res->msgs[i], "searchFlag", 0);
450 data->attrs[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", False);
458 static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data)
460 static const char *schema_attrs[] = { "governsID",
462 "objectClassCategory",
463 "defaultObjectCategory"
468 "systemAuxiliaryClass",
470 "systemPossSuperiors",
478 struct ldb_result *res;
481 ret = ldb_search(module->ldb,
484 "(objectClass=classSchema)",
488 if (ret != LDB_SUCCESS) {
492 data->num_classes = res->count;
493 data->class = talloc_array(data, struct schema_class *, res->count);
494 SCHEMA_CHECK_VALUE(data->class, NULL, module);
496 data->class_store = schema_store_new(data);
497 SCHEMA_CHECK_VALUE(data->class_store, NULL, module);
499 for (i = 0; i < res->count; i++) {
500 struct ldb_message_element *el;
502 data->class[i] = talloc(data->class, struct schema_class);
503 SCHEMA_CHECK_VALUE(data->class[i], NULL, module);
505 data->class[i]->OID = talloc_strdup(data->class[i],
506 ldb_msg_find_attr_as_string(res->msgs[i], "governsID", NULL));
507 SCHEMA_CHECK_VALUE(data->class[i]->OID, NULL, module);
509 data->class[i]->name = talloc_strdup(data->class[i],
510 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
511 SCHEMA_CHECK_VALUE(data->class[i]->name, NULL, module);
513 /* once we have both the OID and the class name, add the pointer to the store */
514 schema_store_add(data->class_store, data->class[i]->OID, data->class[i]);
515 schema_store_add(data->class_store, data->class[i]->name, data->class[i]);
517 data->class[i]->type = ldb_msg_find_attr_as_int(res->msgs[i], "objectClassCategory", -1);
518 /* 0 should not be a valid value, but turn out it is so test with -1 */
519 SCHEMA_CHECK_VALUE(data->class[i]->type, -1, module);
521 data->class[i]->defobjcat = talloc_strdup(data->class[i],
522 ldb_msg_find_attr_as_string(res->msgs[i],
523 "defaultObjectCategory", NULL));
524 SCHEMA_CHECK_VALUE(data->class[i]->defobjcat, NULL, module);
526 /* the following attributes are all optional */
528 data->class[i]->systemOnly = ldb_msg_find_attr_as_bool(res->msgs[i], "systemOnly", False);
529 data->class[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
530 data->class[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", False);
532 /* attributes are loaded first, so we can just go an query the attributes repo */
534 el = ldb_msg_find_element(res->msgs[i], "systemMustContain");
536 data->class[i]->sysmust = schema_get_attrs_list(module, data, el);
537 SCHEMA_CHECK_VALUE(data->class[i]->sysmust, NULL, module);
540 el = ldb_msg_find_element(res->msgs[i], "MustContain");
542 data->class[i]->must = schema_get_attrs_list(module, data, el);
543 SCHEMA_CHECK_VALUE(data->class[i]->must, NULL, module);
546 el = ldb_msg_find_element(res->msgs[i], "systemMayContain");
548 data->class[i]->sysmay = schema_get_attrs_list(module, data, el);
549 SCHEMA_CHECK_VALUE(data->class[i]->sysmay, NULL, module);
552 el = ldb_msg_find_element(res->msgs[i], "MayContain");
554 data->class[i]->may = schema_get_attrs_list(module, data, el);
555 SCHEMA_CHECK_VALUE(data->class[i]->may, NULL, module);
560 /* subClassOf, systemAuxiliaryClass, auxiliaryClass, systemPossSuperiors
561 * must be filled in a second loop, when all class objects are allocated
562 * or we may not find a class that has not yet been parsed */
563 for (i = 0; i < res->count; i++) {
564 struct ldb_message_element *el;
567 /* this is single valued anyway */
568 attr = ldb_msg_find_attr_as_string(res->msgs[i], "subClassOf", NULL);
569 SCHEMA_CHECK_VALUE(attr, NULL, module);
570 data->class[i]->parent = schema_store_find(data->class_store, attr);
571 SCHEMA_CHECK_VALUE(data->class[i]->parent, NULL, module);
573 /* the following attributes are all optional */
575 data->class[i]->sysaux = NULL;
576 el = ldb_msg_find_element(res->msgs[i], "systemAuxiliaryClass");
578 data->class[i]->sysaux = schema_get_class_list(module, data, el);
579 SCHEMA_CHECK_VALUE(data->class[i]->sysaux, NULL, module);
582 data->class[i]->aux = NULL;
583 el = ldb_msg_find_element(res->msgs[i], "auxiliaryClass");
585 data->class[i]->aux = schema_get_class_list(module, data, el);
586 SCHEMA_CHECK_VALUE(data->class[i]->aux, NULL, module);
589 data->class[i]->sysposssup = NULL;
590 el = ldb_msg_find_element(res->msgs[i], "systemPossSuperiors");
592 data->class[i]->sysposssup = schema_get_class_list(module, data, el);
593 SCHEMA_CHECK_VALUE(data->class[i]->sysposssup, NULL, module);
596 data->class[i]->posssup = NULL;
597 el = ldb_msg_find_element(res->msgs[i], "possSuperiors");
599 data->class[i]->posssup = schema_get_class_list(module, data, el);
600 SCHEMA_CHECK_VALUE(data->class[i]->posssup, NULL, module);
603 data->class[i]->possinf = NULL;
604 el = ldb_msg_find_element(res->msgs[i], "possibleInferiors");
606 data->class[i]->possinf = schema_get_class_list(module, data, el);
607 SCHEMA_CHECK_VALUE(data->class[i]->possinf, NULL, module);
616 static struct ldb_handle *schema_init_handle(struct ldb_request *req, struct ldb_module *module, enum sc_op op)
618 struct schema_context *sctx;
619 struct ldb_handle *h;
621 h = talloc_zero(req, struct ldb_handle);
623 ldb_set_errstring(module->ldb, "Out of Memory");
629 sctx = talloc_zero(h, struct schema_context);
631 ldb_set_errstring(module->ldb, "Out of Memory");
636 h->private_data = (void *)sctx;
638 h->state = LDB_ASYNC_INIT;
639 h->status = LDB_SUCCESS;
642 sctx->step = SC_INIT;
643 sctx->data = module->private_data;
644 sctx->module = module;
645 sctx->orig_req = req;
650 static int schema_add_check_parent(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
652 struct schema_context *sctx;
654 if (!context || !ares) {
655 ldb_set_errstring(ldb, "NULL Context or Result in callback");
656 return LDB_ERR_OPERATIONS_ERROR;
659 sctx = talloc_get_type(context, struct schema_context);
661 /* we are interested only in the single reply (base search) we receive here */
662 if (ares->type == LDB_REPLY_ENTRY) {
663 if (sctx->parent_res != NULL) {
664 ldb_set_errstring(ldb, "Too many results");
666 return LDB_ERR_OPERATIONS_ERROR;
668 sctx->parent_res = talloc_steal(sctx, ares);
676 static int schema_add_build_parent_req(struct schema_context *sctx)
678 static const char * const parent_attrs[] = { "objectClass", NULL };
681 sctx->parent_req = talloc_zero(sctx, struct ldb_request);
682 if (sctx->parent_req == NULL) {
683 ldb_debug(sctx->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
684 return LDB_ERR_OPERATIONS_ERROR;
687 sctx->parent_req->operation = LDB_SEARCH;
688 sctx->parent_req->op.search.scope = LDB_SCOPE_BASE;
689 sctx->parent_req->op.search.base = ldb_dn_get_parent(sctx->parent_req, sctx->orig_req->op.add.message->dn);
690 sctx->parent_req->op.search.tree = ldb_parse_tree(sctx->module->ldb, "(objectClass=*)");
691 sctx->parent_req->op.search.attrs = parent_attrs;
692 sctx->parent_req->controls = NULL;
693 sctx->parent_req->context = sctx;
694 sctx->parent_req->callback = schema_add_check_parent;
695 ret = ldb_set_timeout_from_prev_req(sctx->module->ldb, sctx->orig_req, sctx->parent_req);
700 static struct schema_class_dlist *schema_add_get_dlist_entry_with_class(struct schema_class_dlist *list, struct schema_class *class)
702 struct schema_class_dlist *temp;
704 for (temp = list; temp && (temp->class != class); temp = temp->next) /* noop */ ;
708 static int schema_add_class_to_dlist(struct schema_class_dlist *list, struct schema_class *class, enum schema_class_type role)
710 struct schema_class_dlist *entry;
711 struct schema_class_dlist *temp;
714 /* see if this class is usable */
715 if (class->isdefunct) {
716 return LDB_ERR_NO_SUCH_ATTRIBUTE;
719 /* see if this class already exist in the class list */
720 if (schema_add_get_dlist_entry_with_class(list, class)) {
724 /* this is a new class go on and add to the list */
725 entry = talloc_zero(list, struct schema_class_dlist);
726 if (!entry) return LDB_ERR_OPERATIONS_ERROR;
727 entry->class = class;
728 entry->role = class->type;
730 /* If parent is top (list is guaranteed to start always with top) */
731 if (class->parent == list->class) {
732 /* if the hierarchy role is structural try to add it just after top */
733 if (role == SCHEMA_CT_STRUCTURAL) {
734 /* but check no other class at after top has a structural role */
735 if (list->next && (list->next->role == SCHEMA_CT_STRUCTURAL)) {
736 return LDB_ERR_OBJECT_CLASS_VIOLATION;
738 DLIST_ADD_AFTER(list, entry, list);
740 DLIST_ADD_END(list, entry, struct schema_class_dlist *);
745 /* search if parent has already been added */
746 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
748 ret = schema_add_class_to_dlist(list, class->parent, role);
749 if (ret != LDB_SUCCESS) {
752 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
754 if (!temp) { /* parent not found !? */
755 return LDB_ERR_OPERATIONS_ERROR;
758 DLIST_ADD_AFTER(list, entry, temp);
759 if (role == SCHEMA_CT_STRUCTURAL || role == SCHEMA_CT_AUXILIARY) {
764 /* stop when hierarchy base is met or when base class parent is top */
765 } while (temp->class == temp->next->class->parent &&
766 temp->next->class->parent != list->class);
768 /* if we have not reached the head of the list
769 * and role is structural */
770 if (temp != list && role == SCHEMA_CT_STRUCTURAL) {
771 struct schema_class_dlist *hfirst, *hlast;
773 /* check if the list second entry is structural */
774 if (list->next->role == SCHEMA_CT_STRUCTURAL) {
775 /* we have a confilict here */
776 return LDB_ERR_OBJECT_CLASS_VIOLATION;
778 /* we have to move this hierarchy of classes
779 * so that the base of the structural hierarchy is right after top */
783 /* now hfirst - hlast are the boundaries of the structural hierarchy */
785 /* extract the structural hierachy from the list */
786 hfirst->prev->next = hlast->next;
787 if (hlast->next) hlast->next->prev = hfirst->prev;
789 /* insert the structural hierarchy just after top */
790 list->next->prev = hlast;
791 hlast->next = list->next;
800 /* merge source list into dest list and remove duplicates */
801 static int schema_merge_class_list(TALLOC_CTX *mem_ctx, struct schema_class ***dest, struct schema_class **source)
803 struct schema_class **list = *dest;
807 if (list) for (n = 0; list[n]; n++) /* noop */ ;
810 for (i = 0; source[i]; i++) {
811 for (j = 0; j < f; j++) {
812 if (list[j] == source[i]) {
816 if (j < f) { /* duplicate found */
820 list = talloc_realloc(mem_ctx, list, struct schema_class *, n + 2);
822 return LDB_ERR_OPERATIONS_ERROR;
834 /* validate and modify the objectclass attribute to sort and add parents */
835 static int schema_add_build_objectclass_list(struct schema_context *sctx)
837 struct schema_class_dlist *temp;
838 struct ldb_message_element * el;
839 struct schema_class *class;
842 /* First of all initialize list, it must start with class top */
843 sctx->class_list = talloc_zero(sctx, struct schema_class_dlist);
844 if (!sctx->class_list) return LDB_ERR_OPERATIONS_ERROR;
846 sctx->class_list->class = schema_store_find(sctx->data->class_store, "top");
847 if (!sctx->class_list->class) return LDB_ERR_OPERATIONS_ERROR;
849 el = ldb_msg_find_element(sctx->orig_req->op.add.message, "objectClass");
851 return LDB_ERR_OBJECT_CLASS_VIOLATION;
854 for (i = 0; i < el->num_values; i++) {
856 class = schema_store_find(sctx->data->class_store, (char *)el->values[i].data);
858 return LDB_ERR_NO_SUCH_ATTRIBUTE;
861 ret = schema_add_class_to_dlist(sctx->class_list, class, class->type);
862 if (ret != LDB_SUCCESS) {
867 /* now check if there is any class role that is still not STRUCTURAL or AUXILIARY */
868 /* build also the auxiliary class list and the possible superiors list */
869 temp = sctx->class_list->next; /* top is special, skip it */
873 if (temp->role == SCHEMA_CT_ABSTRACT || temp->role == SCHEMA_CT_88) {
874 return LDB_ERR_OBJECT_CLASS_VIOLATION;
876 if (temp->class->sysaux) {
877 ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->sysaux);
878 if (ret != LDB_SUCCESS) {
879 return LDB_ERR_OPERATIONS_ERROR;
882 if (temp->class->aux) {
883 ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->aux);
884 if (ret != LDB_SUCCESS) {
885 return LDB_ERR_OPERATIONS_ERROR;
888 if (temp->class->sysposssup) {
889 ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->sysposssup);
890 if (ret != LDB_SUCCESS) {
891 return LDB_ERR_OPERATIONS_ERROR;
894 if (temp->class->posssup) {
895 ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->posssup);
896 if (ret != LDB_SUCCESS) {
897 return LDB_ERR_OPERATIONS_ERROR;
903 /* complete sup_list with material from the aux classes */
904 for (i = 0; sctx->aux_list && sctx->aux_list[i]; i++) {
905 if (sctx->aux_list[i]->sysposssup) {
906 ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->sysposssup);
907 if (ret != LDB_SUCCESS) {
908 return LDB_ERR_OPERATIONS_ERROR;
911 if (sctx->aux_list[i]->posssup) {
912 ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->posssup);
913 if (ret != LDB_SUCCESS) {
914 return LDB_ERR_OPERATIONS_ERROR;
919 if (!sctx->sup_list) return LDB_ERR_NAMING_VIOLATION;
924 static int schema_add_check_container_constraints(struct schema_context *sctx)
926 struct schema_class **parent_possinf = NULL;
927 struct schema_class **parent_classes;
928 struct schema_class_dlist *temp;
929 struct ldb_message_element *el;
932 el = ldb_msg_find_element(sctx->parent_res->message, "objectClass");
935 return LDB_ERR_OPERATIONS_ERROR;
938 parent_classes = talloc_array(sctx, struct schema_class *, el->num_values + 1);
940 for (i = 0; i < el->num_values; i++) {
942 parent_classes[i] = schema_store_find(sctx->data->class_store, (const char *)el->values[i].data);
943 if (!parent_classes[i]) { /* should not be possible */
944 return LDB_ERR_OPERATIONS_ERROR;
947 if (parent_classes[i]->possinf) {
948 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->possinf);
949 if (ret != LDB_SUCCESS) {
950 return LDB_ERR_OPERATIONS_ERROR;
954 /* check also embedded auxiliary classes possinf */
955 for (j = 0; parent_classes[i]->sysaux && parent_classes[i]->sysaux[j]; j++) {
956 if (parent_classes[i]->sysaux[j]->possinf) {
957 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->sysaux[j]->possinf);
958 if (ret != LDB_SUCCESS) {
959 return LDB_ERR_OPERATIONS_ERROR;
963 for (j = 0; parent_classes[i]->aux && parent_classes[i]->aux[j]; j++) {
964 if (parent_classes[i]->aux[j]->possinf) {
965 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->aux[j]->possinf);
966 if (ret != LDB_SUCCESS) {
967 return LDB_ERR_OPERATIONS_ERROR;
973 /* foreach parent objectclass,
974 * check parent possible inferiors match all of the child objectclasses
976 * poss Superiors of the child objectclasses mathes one of the parent classes
979 temp = sctx->class_list->next; /* skip top it is special */
982 for (i = 0; parent_possinf[i]; i++) {
983 if (temp->class == parent_possinf[i]) {
987 if (parent_possinf[i] == NULL) {
988 /* class not found in possible inferiors */
989 return LDB_ERR_NAMING_VIOLATION;
995 for (i = 0; parent_classes[i]; i++) {
996 for (j = 0; sctx->sup_list[j]; j++) {
997 if (sctx->sup_list[j] == parent_classes[i]) {
1001 if (sctx->sup_list[j]) { /* possible Superiors match one of the parent classes */
1006 /* no parent classes matched superiors */
1007 return LDB_ERR_NAMING_VIOLATION;
1010 static int schema_add_build_down_req(struct schema_context *sctx)
1012 struct schema_class_dlist *temp;
1013 struct ldb_message *msg;
1017 sctx->down_req = talloc(sctx, struct ldb_request);
1018 if (!sctx->down_req) {
1019 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
1020 return LDB_ERR_OPERATIONS_ERROR;
1023 *(sctx->down_req) = *(sctx->orig_req); /* copy the request */
1024 msg = ldb_msg_copy_shallow(sctx->down_req, sctx->orig_req->op.add.message);
1026 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
1027 return LDB_ERR_OPERATIONS_ERROR;
1030 /* rebuild the objectclass list */
1031 ldb_msg_remove_attr(msg, "objectClass");
1032 ret = ldb_msg_add_empty(msg, "objectClass", 0);
1033 if (ret != LDB_SUCCESS) {
1037 /* Add the complete list of classes back to the message */
1038 for (temp = sctx->class_list; temp; temp = temp->next) {
1039 ret = ldb_msg_add_string(msg, "objectClass", temp->class->name);
1040 if (ret != LDB_SUCCESS) {
1045 /* objectCategory can be set only by the system */
1046 if (ldb_msg_find_element(msg, "objectCategory")) {
1047 return LDB_ERR_CONSTRAINT_VIOLATION;
1050 /* the OC is mandatory, every class defines it */
1051 /* use the one defined in the structural class that defines the object */
1052 for (temp = sctx->class_list->next; temp; temp = temp->next) {
1053 if (!temp->next) break;
1054 if (temp->next->role != SCHEMA_CT_STRUCTURAL) break;
1056 oc = talloc_strdup(msg, temp->class->defobjcat);
1057 ret = ldb_msg_add_string(msg, "objectCategory", oc);
1059 sctx->down_req->op.add.message = msg;
1064 static int schema_add_continue(struct ldb_handle *h)
1066 struct schema_context *sctx;
1069 sctx = talloc_get_type(h->private_data, struct schema_context);
1071 switch (sctx->step) {
1074 /* First of all check that a parent exists for this entry */
1075 ret = schema_add_build_parent_req(sctx);
1076 if (ret != LDB_SUCCESS) {
1080 sctx->step = SC_ADD_CHECK_PARENT;
1081 return ldb_next_request(sctx->module, sctx->parent_req);
1083 case SC_ADD_CHECK_PARENT:
1085 /* parent search done, check result and go on */
1086 if (sctx->parent_res == NULL) {
1087 /* we must have a parent */
1088 ret = LDB_ERR_NO_SUCH_OBJECT;
1092 /* Check objectclasses are ok */
1093 ret = schema_add_build_objectclass_list(sctx);
1094 if (ret != LDB_SUCCESS) {
1098 /* check the parent is of the right type for this object */
1099 ret = schema_add_check_container_constraints(sctx);
1100 if (ret != LDB_SUCCESS) {
1104 /* check attributes syntax */
1106 ret = schema_check_attributes_syntax(sctx);
1107 if (ret != LDB_SUCCESS) {
1112 ret = schema_add_build_down_req(sctx);
1113 if (ret != LDB_SUCCESS) {
1116 sctx->step = SC_ADD_TEMP;
1118 return ldb_next_request(sctx->module, sctx->down_req);
1121 ret = LDB_ERR_OPERATIONS_ERROR;
1125 /* this is reached only in case of error */
1126 /* FIXME: fire an async reply ? */
1128 h->state = LDB_ASYNC_DONE;
1132 static int schema_add(struct ldb_module *module, struct ldb_request *req)
1134 struct schema_context *sctx;
1135 struct ldb_handle *h;
1137 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1138 return ldb_next_request(module, req);
1141 h = schema_init_handle(req, module, SC_ADD);
1143 return LDB_ERR_OPERATIONS_ERROR;
1146 sctx = talloc_get_type(h->private_data, struct schema_context);
1147 sctx->orig_req->handle = h;
1148 return schema_add_continue(h);
1152 static int schema_modify(struct ldb_module *module, struct ldb_request *req)
1154 struct ldb_handle *h;
1155 struct schema_context *sctx;
1157 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1158 return ldb_next_request(module, req);
1161 return ldb_next_request(module, req);
1164 static int schema_delete(struct ldb_module *module, struct ldb_request *req)
1166 struct ldb_handle *h;
1167 struct schema_context *sctx;
1169 if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */
1170 return ldb_next_request(module, req);
1173 /* First of all check no children exists for this entry */
1175 return ldb_next_request(module, req);
1178 static int schema_rename(struct ldb_module *module, struct ldb_request *req)
1180 struct ldb_handle *h;
1181 struct schema_context *sctx;
1183 if (ldb_dn_is_special(req->op.rename.olddn) &&
1184 ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1185 return ldb_next_request(module, req);
1188 return ldb_next_request(module, req);
1191 static int schema_wait_loop(struct ldb_handle *handle) {
1192 struct schema_context *sctx;
1195 if (!handle || !handle->private_data) {
1196 return LDB_ERR_OPERATIONS_ERROR;
1199 if (handle->state == LDB_ASYNC_DONE) {
1200 return handle->status;
1203 handle->state = LDB_ASYNC_PENDING;
1204 handle->status = LDB_SUCCESS;
1206 sctx = talloc_get_type(handle->private_data, struct schema_context);
1208 switch (sctx->step) {
1209 case SC_ADD_CHECK_PARENT:
1210 ret = ldb_wait(sctx->parent_req->handle, LDB_WAIT_NONE);
1212 if (ret != LDB_SUCCESS) {
1213 handle->status = ret;
1216 if (sctx->parent_req->handle->status != LDB_SUCCESS) {
1217 handle->status = sctx->parent_req->handle->status;
1221 if (sctx->parent_req->handle->state != LDB_ASYNC_DONE) {
1225 return schema_add_continue(handle);
1228 ret = ldb_wait(sctx->down_req->handle, LDB_WAIT_NONE);
1230 if (ret != LDB_SUCCESS) {
1231 handle->status = ret;
1234 if (sctx->down_req->handle->status != LDB_SUCCESS) {
1235 handle->status = sctx->down_req->handle->status;
1239 if (sctx->down_req->handle->state != LDB_ASYNC_DONE) {
1246 ret = LDB_ERR_OPERATIONS_ERROR;
1253 handle->state = LDB_ASYNC_DONE;
1257 static int schema_wait_all(struct ldb_handle *handle) {
1261 while (handle->state != LDB_ASYNC_DONE) {
1262 ret = schema_wait_loop(handle);
1263 if (ret != LDB_SUCCESS) {
1268 return handle->status;
1271 static int schema_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1273 if (type == LDB_WAIT_ALL) {
1274 return schema_wait_all(handle);
1276 return schema_wait_loop(handle);
1280 static int schema_init(struct ldb_module *module)
1282 static const char *schema_attrs[] = { "schemaNamingContext", NULL };
1283 struct schema_private_data *data;
1284 struct ldb_result *res;
1287 /* need to let the partiorion module to register first */
1288 ret = ldb_next_init(module);
1289 if (ret != LDB_SUCCESS) {
1293 data = talloc_zero(module, struct schema_private_data);
1295 return LDB_ERR_OPERATIONS_ERROR;
1298 /* find the schema partition */
1299 ret = ldb_search(module->ldb,
1306 if (res->count != 1) {
1307 /* FIXME: return a clear error string */
1310 return LDB_ERR_OPERATIONS_ERROR;
1313 data->schema_dn = ldb_msg_find_attr_as_dn(data, res->msgs[0], "schemaNamingContext");
1314 if (data->schema_dn == NULL) {
1315 /* FIXME: return a clear error string */
1318 return LDB_ERR_OPERATIONS_ERROR;
1323 ret = schema_init_attrs(module, data);
1324 if (ret != LDB_SUCCESS) {
1329 ret = schema_init_classes(module, data);
1330 if (ret != LDB_SUCCESS) {
1335 module->private_data = data;
1339 static const struct ldb_module_ops schema_ops = {
1341 .init_context = schema_init,
1343 .modify = schema_modify,
1344 .del = schema_delete,
1345 .rename = schema_rename,
1349 int ldb_schema_init(void)
1351 return ldb_register_module(&schema_ops);