Fix spellings and file names
[Samba.git] / source4 / dsdb / samdb / ldb_modules / schema.c
blobf2c4d383051dfe48e33743a5fd2958772616d1ff
1 /*
2 ldb database library
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/>.
21 * Name: ldb
23 * Component: ldb schema module
25 * Description: add schema check functionality
27 * Author: Simo Sorce
30 #include "includes.h"
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"
37 /* Syntax-Table
39 see ldap_server/devdocs/AD-syntaxes.txt
42 enum schema_class_type {
43 SCHEMA_CT_88 = 0,
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 */
61 struct schema_class {
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;
87 int num_attributes;
88 struct schema_class **class;
89 struct schema_store *class_store;
90 int num_classes;
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 */
120 struct schema_link {
121 const char *name;
122 void *object;
125 struct schema_store {
126 struct schema_link *store;
127 int num_links;
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;
137 ht->store = NULL;
138 ht->num_links = 0;
140 return ht;
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;
151 ht->num_links++;
153 return LDB_SUCCESS;
156 static void *schema_store_find(struct schema_store *ht, const char *key)
158 int i;
160 for (i = 0; i < ht->num_links; i++) {
161 if (strcasecmp(ht->store[i].name, key) == 0) {
162 return ht->store[i].object;
166 return NULL;
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;
181 int i;
183 list = talloc_array(data, struct schema_class *, el->num_values + 1);
184 if (!list) {
185 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
186 return NULL;
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);
192 if (!list[i]) {
193 ldb_debug_set(module->ldb,
194 LDB_DEBUG_ERROR,
195 "Class %s referenced but not found in schema\n",
196 (char *)el->values[i].data);
197 return NULL;
200 list[i] = NULL;
202 return list;
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;
210 int i;
212 list = talloc_array(data, struct schema_attribute *, el->num_values + 1);
213 if (!list) {
214 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
215 return NULL;
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);
221 if (!list[i]) {
222 ldb_debug_set(module->ldb,
223 LDB_DEBUG_ERROR,
224 "Attriobute %s referenced but not found in schema\n",
225 (char *)el->values[i].data);
226 return NULL;
229 list[i] = NULL;
231 return list;
234 static int schema_init_attrs(struct ldb_module *module, struct schema_private_data *data)
236 static const char *schema_attrs[] = { "attributeID",
237 "lDAPDisplayName",
238 "attributeSyntax",
239 "oMSyntax",
240 "oMObjectClass",
241 "isSingleValued",
242 "rangeLower",
243 "rangeUpper",
244 "searchFlag",
245 "systemFlag",
246 "isDefunct",
247 NULL };
248 struct ldb_result *res;
249 int ret, i;
251 ret = ldb_search(module->ldb,
252 data->schema_dn,
253 LDB_SCOPE_SUBTREE,
254 "(objectClass=attributeSchema)",
255 schema_attrs,
256 &res);
258 if (ret != LDB_SUCCESS) {
259 goto done;
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;
272 uint32_t om_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);
304 goto done;
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;
311 } else {
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);
323 done:
324 talloc_free(res);
325 return ret;
328 static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data)
330 const char *schema_attrs[] = { "governsID",
331 "lDAPDisplayName",
332 "objectClassCategory",
333 "defaultObjectCategory",
334 "systemOnly",
335 "systemFlag",
336 "isDefunct",
337 "subClassOf",
338 "systemAuxiliaryClass",
339 "auxiliaryClass",
340 "systemPossSuperiors",
341 "possSuperiors",
342 "possibleInferiors",
343 "systemMustContain",
344 "MustContain",
345 "systemMayContain",
346 "MayContain",
347 NULL };
348 struct ldb_result *res;
349 int ret, i;
351 ret = ldb_search(module->ldb,
352 data->schema_dn,
353 LDB_SCOPE_SUBTREE,
354 "(objectClass=classSchema)",
355 schema_attrs,
356 &res);
358 if (ret != LDB_SUCCESS) {
359 goto done;
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");
405 if (el) {
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");
411 if (el) {
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");
417 if (el) {
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");
423 if (el) {
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;
435 const char *attr;
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");
447 if (el) {
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");
454 if (el) {
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");
461 if (el) {
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");
468 if (el) {
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");
475 if (el) {
476 data->class[i]->possinf = schema_get_class_list(module, data, el);
477 SCHEMA_CHECK_VALUE(data->class[i]->possinf, NULL, module);
481 done:
482 talloc_free(res);
483 return ret;
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);
492 if (h == NULL) {
493 ldb_set_errstring(module->ldb, "Out of Memory");
494 return NULL;
497 h->module = module;
499 sctx = talloc_zero(h, struct schema_context);
500 if (sctx == NULL) {
501 ldb_set_errstring(module->ldb, "Out of Memory");
502 talloc_free(h);
503 return NULL;
506 h->private_data = (void *)sctx;
508 h->state = LDB_ASYNC_INIT;
509 h->status = LDB_SUCCESS;
511 sctx->op = op;
512 sctx->step = SC_INIT;
513 sctx->data = module->private_data;
514 sctx->module = module;
515 sctx->orig_req = req;
517 return h;
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");
530 talloc_free(ares);
531 return LDB_ERR_OPERATIONS_ERROR;
533 sctx->parent_res = talloc_steal(sctx, ares);
534 } else {
535 talloc_free(ares);
538 return LDB_SUCCESS;
541 static int schema_add_build_parent_req(struct schema_context *sctx)
543 const char * const parent_attrs[] = { "objectClass", NULL };
544 int ret;
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);
562 return ret;
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 */ ;
570 return temp;
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;
577 int ret;
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)) {
586 return LDB_SUCCESS;
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);
604 } else {
605 DLIST_ADD_END(list, entry, struct schema_class_dlist *);
607 return LDB_SUCCESS;
610 /* search if parent has already been added */
611 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
612 if (temp == NULL) {
613 ret = schema_add_class_to_dlist(list, class->parent, role);
614 if (ret != LDB_SUCCESS) {
615 return ret;
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) {
625 temp = entry;
626 do {
627 temp->role = role;
628 temp = temp->prev;
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 */
646 hfirst = temp->next;
647 hlast = entry;
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;
657 list->next = hfirst;
658 hfirst->prev = list;
662 return LDB_SUCCESS;
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;
669 int i, j, n, f;
671 n = 0;
672 if (list) for (n = 0; list[n]; n++) /* noop */ ;
673 f = n;
675 for (i = 0; source[i]; i++) {
676 for (j = 0; j < f; j++) {
677 if (list[j] == source[i]) {
678 break;
681 if (j < f) { /* duplicate found */
682 continue;
685 list = talloc_realloc(mem_ctx, list, struct schema_class *, n + 2);
686 if (!list) {
687 return LDB_ERR_OPERATIONS_ERROR;
689 list[n] = source[i];
690 n++;
691 list[n] = NULL;
694 *dest = list;
696 return LDB_SUCCESS;
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;
705 int ret, i, an;
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");
715 if (!el) {
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);
722 if (!class) {
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) {
728 return ret;
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 */
735 an = 0;
737 while (temp) {
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;
765 temp = temp->next;
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;
786 return LDB_SUCCESS;
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;
795 int i, j, ret;
797 el = ldb_msg_find_element(sctx->parent_res->message, "objectClass");
798 if (!el) {
799 /* what the .. */
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
840 * and that
841 * poss Superiors of the child objectclasses mathes one of the parent classes
844 temp = sctx->class_list->next; /* skip top it is special */
845 while (temp) {
847 for (i = 0; parent_possinf[i]; i++) {
848 if (temp->class == parent_possinf[i]) {
849 break;
852 if (parent_possinf[i] == NULL) {
853 /* class not found in possible inferiors */
854 return LDB_ERR_NAMING_VIOLATION;
857 temp = temp->next;
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]) {
863 break;
866 if (sctx->sup_list[j]) { /* possible Superiors match one of the parent classes */
867 return LDB_SUCCESS;
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;
879 int ret;
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);
889 if (!msg) {
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) {
898 return ret;
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) {
905 return ret;
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;
925 return LDB_SUCCESS;
928 static int schema_check_attributes_syntax(struct schema_context *sctx)
930 struct ldb_message *msg;
931 struct schema_attribute *attr;
932 int i, ret;
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);
937 if (attr == NULL) {
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) {
942 return ret;
946 return LDB_SUCCESS;
949 static int schema_add_continue(struct ldb_handle *h)
951 struct schema_context *sctx;
952 int ret;
954 sctx = talloc_get_type(h->private_data, struct schema_context);
956 switch (sctx->step) {
957 case SC_INIT:
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) {
962 break;
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;
974 break;
977 /* Check objectclasses are ok */
978 ret = schema_add_build_objectclass_list(sctx);
979 if (ret != LDB_SUCCESS) {
980 break;
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) {
986 break;
989 /* check attributes syntax */
991 ret = schema_check_attributes_syntax(sctx);
992 if (ret != LDB_SUCCESS) {
993 break;
996 ret = schema_add_build_down_req(sctx);
997 if (ret != LDB_SUCCESS) {
998 break;
1000 sctx->step = SC_ADD_TEMP;
1002 return ldb_next_request(sctx->module, sctx->down_req);
1004 default:
1005 ret = LDB_ERR_OPERATIONS_ERROR;
1006 break;
1009 /* this is reached only in case of error */
1010 /* FIXME: fire an async reply ? */
1011 h->status = ret;
1012 h->state = LDB_ASYNC_DONE;
1013 return ret;
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);
1026 if (!h) {
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;
1068 int ret;
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;
1089 goto done;
1091 if (sctx->parent_req->handle->status != LDB_SUCCESS) {
1092 handle->status = sctx->parent_req->handle->status;
1093 goto done;
1096 if (sctx->parent_req->handle->state != LDB_ASYNC_DONE) {
1097 return LDB_SUCCESS;
1100 return schema_add_continue(handle);
1102 case SC_ADD_TEMP:
1103 ret = ldb_wait(sctx->down_req->handle, LDB_WAIT_NONE);
1105 if (ret != LDB_SUCCESS) {
1106 handle->status = ret;
1107 goto done;
1109 if (sctx->down_req->handle->status != LDB_SUCCESS) {
1110 handle->status = sctx->down_req->handle->status;
1111 goto done;
1114 if (sctx->down_req->handle->state != LDB_ASYNC_DONE) {
1115 return LDB_SUCCESS;
1118 break;
1120 default:
1121 ret = LDB_ERR_OPERATIONS_ERROR;
1122 goto done;
1125 ret = LDB_SUCCESS;
1127 done:
1128 handle->state = LDB_ASYNC_DONE;
1129 return ret;
1132 static int schema_wait_all(struct ldb_handle *handle) {
1134 int ret;
1136 while (handle->state != LDB_ASYNC_DONE) {
1137 ret = schema_wait_loop(handle);
1138 if (ret != LDB_SUCCESS) {
1139 return ret;
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);
1150 } else {
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;
1160 int ret;
1162 /* need to let the partition module to register first */
1163 ret = ldb_next_init(module);
1164 if (ret != LDB_SUCCESS) {
1165 return ret;
1168 data = ldb_get_opaque(module->ldb, "schema_instance");
1169 if (data) {
1170 module->private_data = data;
1171 return LDB_SUCCESS;
1174 data = talloc_zero(module->ldb, struct schema_private_data);
1175 if (data == NULL) {
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),
1182 LDB_SCOPE_BASE,
1183 "(objectClass=*)",
1184 schema_attrs,
1185 &res);
1187 if (res->count != 1) {
1188 /* FIXME: return a clear error string */
1189 talloc_free(data);
1190 talloc_free(res);
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 */
1197 talloc_free(data);
1198 talloc_free(res);
1199 return LDB_ERR_OPERATIONS_ERROR;
1202 talloc_free(res);
1204 ret = schema_init_attrs(module, data);
1205 if (ret != LDB_SUCCESS) {
1206 talloc_free(data);
1207 return ret;
1210 ret = schema_init_classes(module, data);
1211 if (ret != LDB_SUCCESS) {
1212 talloc_free(data);
1213 return ret;
1216 module->private_data = data;
1217 ldb_set_opaque(module->ldb, "schema_instance", data);
1219 return LDB_SUCCESS;
1222 _PUBLIC_ const struct ldb_module_ops ldb_schema_module_ops = {
1223 .name = "schema",
1224 .init_context = schema_init,
1225 .add = schema_add,
1226 .modify = schema_modify,
1227 .del = schema_delete,
1228 .rename = schema_rename,
1229 .wait = schema_wait