r19489: Change ldb_msg_add_value and ldb_msg_add_empty to take a foruth argument.
[samba.git] / source4 / dsdb / samdb / ldb_modules / schema.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2006
5
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.
10    
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.
15    
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.
19 */
20
21 /*
22  *  Name: ldb
23  *
24  *  Component: ldb schema module
25  *
26  *  Description: add schema check functionality
27  *
28  *  Author: Simo Sorce
29  *
30  *  License: GNU GPL v2 or Later
31  */
32
33 #include "includes.h"
34 #include "libcli/ldap/ldap.h"
35 #include "ldb/include/ldb_errors.h"
36 #include "ldb/include/ldb_private.h"
37 #include "lib/util/dlinklist.h"
38 #include "schema_syntax.h"
39
40 /* Syntax-Table
41
42    see ldap_server/devdocs/AD-syntaxes.txt
43 */
44
45 enum schema_class_type {
46         SCHEMA_CT_88            = 0,
47         SCHEMA_CT_STRUCTURAL    = 1,
48         SCHEMA_CT_ABSTRACT      = 2,
49         SCHEMA_CT_AUXILIARY     = 3
50 };
51
52 struct schema_attribute {
53         char *OID;                              /* attributeID     */
54         char *name;                             /* lDAPDisplayName */
55         enum schema_internal_syntax syntax;     /* generated from attributeSyntax, oMSyntax, oMObjectClass */
56         bool single;                            /* isSingleValued  */
57         int min;                                /* rangeLower      */
58         int max;                                /* rangeUpper      */
59         int systemflag;                         /* systemFlag      */
60         int searchflag;                         /* searchFlag      */
61         bool isdefunct;                         /* isDefunct       */
62 };
63
64 struct schema_class {
65         char *OID;                              /* governsID             */
66         char *name;                             /* lDAPDisplayName       */
67         enum schema_class_type type;            /* objectClassCategory   */
68         bool systemOnly;                        /* systemOnly            */
69         bool isdefunct;                         /* isDefunct             */
70         int systemflag;                         /* systemFlag            */
71         char *defobjcat;                        /* defaultObjectCategory */
72         struct schema_class *parent;            /* subClassOf            */
73         struct schema_class **sysaux;           /* systemAuxiliaryClass  */
74         struct schema_class **aux;              /* auxiliaryClass        */
75         struct schema_class **sysposssup;       /* systemPossSuperiors   */
76         struct schema_class **posssup;          /* possSuperiors         */
77         struct schema_class **possinf;          /* possibleInferiors     */
78         struct schema_attribute **sysmust;      /* systemMustContain     */
79         struct schema_attribute **must;         /* MustContain           */
80         struct schema_attribute **sysmay;       /* systemMayContain      */
81         struct schema_attribute **may;          /* MayContain            */
82 };
83
84 /* TODO: ditcontentrules */
85
86 struct schema_private_data {
87         struct ldb_dn *schema_dn;
88         struct schema_attribute **attrs;
89         struct schema_store *attrs_store;
90         int num_attributes;
91         struct schema_class **class;
92         struct schema_store *class_store;
93         int num_classes;
94 };
95
96 struct schema_class_dlist {
97         struct schema_class *class;
98         struct schema_class_dlist *prev;
99         struct schema_class_dlist *next;
100         enum schema_class_type role;
101 };
102
103 struct schema_context {
104
105         enum sc_op { SC_ADD, SC_MOD, SC_DEL, SC_RENAME } op;
106         enum sc_step { SC_INIT, SC_ADD_CHECK_PARENT, SC_ADD_TEMP, SC_DEL_CHECK_CHILDREN } step;
107
108         struct schema_private_data *data;
109
110         struct ldb_module *module;
111         struct ldb_request *orig_req;
112         struct ldb_request *down_req;
113
114         struct ldb_request *parent_req;
115         struct ldb_reply *parent_res;
116
117         struct schema_class_dlist *class_list;
118         struct schema_class **sup_list;
119         struct schema_class **aux_list;
120 };
121
122 /* FIXME: I'd really like to use an hash table here */
123 struct schema_link {
124         const char *name;
125         void *object;
126 };
127
128 struct schema_store {
129         struct schema_link *store;
130         int num_links;
131 };
132
133 static struct schema_store *schema_store_new(TALLOC_CTX *mem_ctx)
134 {
135         struct schema_store *ht;
136         
137         ht = talloc(mem_ctx, struct schema_store);
138         if (!ht) return NULL;
139
140         ht->store = NULL;
141         ht->num_links = 0;
142
143         return ht;
144 }
145         
146 static int schema_store_add(struct schema_store *ht, const char *key, void *object)
147 {
148         ht->store = talloc_realloc(ht, ht->store, struct schema_link, ht->num_links + 1);
149         if (!ht->store) return LDB_ERR_OPERATIONS_ERROR;
150
151         ht->store[ht->num_links].name = key;
152         ht->store[ht->num_links].object = object;
153
154         ht->num_links++;
155
156         return LDB_SUCCESS;
157 }
158
159 static void *schema_store_find(struct schema_store *ht, const char *key)
160 {
161         int i;
162
163         for (i = 0; i < ht->num_links; i++) {
164                 if (strcasecmp(ht->store[i].name, key) == 0) {
165                         return ht->store[i].object;
166                 }
167         }
168
169         return NULL;
170 }
171
172 #define SCHEMA_CHECK_VALUE(mem, val, mod) \
173                 do { if (mem == val) { \
174                         ret = LDB_ERR_OPERATIONS_ERROR; \
175                         ldb_asprintf_errstring(mod->ldb, \
176                                 "schema module: Memory allocation or attribute error on %s", #mem); \
177                         goto done; } } while(0)
178
179 struct schema_class **schema_get_class_list(struct ldb_module *module,
180                                             struct schema_private_data *data,
181                                             struct ldb_message_element *el)
182 {
183         struct schema_class **list;
184         int i;
185         
186         list = talloc_array(data, struct schema_class *, el->num_values + 1);
187         if (!list) {
188                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
189                 return NULL;
190         }
191         
192         for (i = 0; i < el->num_values; i++) {
193                 list[i] = (struct schema_class *)schema_store_find(data->class_store,
194                                                                   (char *)el->values[i].data);
195                 if (!list[i]) {
196                         ldb_debug_set(module->ldb,
197                                         LDB_DEBUG_ERROR,
198                                         "Class %s referenced but not found in schema\n",
199                                         (char *)el->values[i].data);
200                         return NULL;
201                 }
202         }
203         list[i] = NULL;
204
205         return list;
206 }
207
208 struct schema_attribute **schema_get_attrs_list(struct ldb_module *module,
209                                                 struct schema_private_data *data,
210                                                 struct ldb_message_element *el)
211 {
212         struct schema_attribute **list;
213         int i;
214
215         list = talloc_array(data, struct schema_attribute *, el->num_values + 1);
216         if (!list) {
217                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
218                 return NULL;
219         }
220         
221         for (i = 0; i < el->num_values; i++) {
222                 list[i] = (struct schema_attribute *)schema_store_find(data->attrs_store,
223                                                                       (char *)el->values[i].data);
224                 if (!list[i]) {
225                         ldb_debug_set(module->ldb,
226                                         LDB_DEBUG_ERROR,
227                                         "Attriobute %s referenced but not found in schema\n",
228                                         (char *)el->values[i].data);
229                         return NULL;
230                 }
231         }
232         list[i] = NULL;
233
234         return list;
235 }
236
237 static int schema_init_attrs(struct ldb_module *module, struct schema_private_data *data)
238 {
239         static const char *schema_attrs[] = {   "attributeID",
240                                                 "lDAPDisplayName",
241                                                 "attributeSyntax",
242                                                 "oMSyntax",
243                                                 "oMObjectClass",
244                                                 "isSingleValued",
245                                                 "rangeLower",
246                                                 "rangeUpper",
247                                                 "searchFlag",
248                                                 "systemFlag",
249                                                 "isDefunct",
250                                                 NULL };
251         struct ldb_result *res;
252         int ret, i;
253
254         ret = ldb_search(module->ldb,
255                          data->schema_dn,
256                          LDB_SCOPE_SUBTREE,
257                          "(objectClass=attributeSchema)",
258                          schema_attrs,
259                          &res);
260
261         if (ret != LDB_SUCCESS) {
262                 goto done;
263         }
264
265         data->num_attributes = res->count;
266         data->attrs = talloc_array(data, struct schema_attribute *, res->count);
267         SCHEMA_CHECK_VALUE(data->attrs, NULL, module);
268
269         data->attrs_store = schema_store_new(data);
270         SCHEMA_CHECK_VALUE(data->attrs_store, NULL, module);
271         
272         for (i = 0; i < res->count; i++) {
273                 const char *tmp_single;
274                 const char *attr_syntax;
275                 uint32_t om_syntax;
276                 const struct ldb_val *om_class;
277
278                 data->attrs[i] = talloc(data->attrs, struct schema_attribute);
279                 SCHEMA_CHECK_VALUE(data->attrs[i], NULL, module);
280
281                 data->attrs[i]->OID = talloc_strdup(data->attrs[i],
282                                                 ldb_msg_find_attr_as_string(res->msgs[i], "attributeID", NULL));
283                 SCHEMA_CHECK_VALUE(data->attrs[i]->OID, NULL, module);
284                 
285                 data->attrs[i]->name = talloc_strdup(data->attrs[i],
286                                                 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
287                 SCHEMA_CHECK_VALUE(data->attrs[i]->name, NULL, module);
288
289                 /* once we have both the OID and the attribute name, add the pointer to the store */
290                 schema_store_add(data->attrs_store, data->attrs[i]->OID, data->attrs[i]);
291                 schema_store_add(data->attrs_store, data->attrs[i]->name, data->attrs[i]);
292
293                 attr_syntax = ldb_msg_find_attr_as_string(res->msgs[i], "attributeSyntax", NULL);
294                 SCHEMA_CHECK_VALUE(attr_syntax, NULL, module);
295                 
296                 om_syntax = ldb_msg_find_attr_as_uint(res->msgs[i], "oMSyntax", 0);
297                 /* 0 is not a valid oMSyntax */
298                 SCHEMA_CHECK_VALUE(om_syntax, 0, module);
299
300                 om_class = ldb_msg_find_ldb_val(res->msgs[i], "oMObjectClass");
301
302                 ret = map_schema_syntax(om_syntax, attr_syntax, om_class, &data->attrs[i]->syntax);
303                 if (ret != LDB_SUCCESS) {
304                         ldb_asprintf_errstring(module->ldb,
305                                 "schema module: invalid om syntax value on %s",
306                                 data->attrs[i]->name);
307                         goto done;
308                 }
309                 
310                 tmp_single = ldb_msg_find_attr_as_string(res->msgs[i], "isSingleValued", NULL);
311                 SCHEMA_CHECK_VALUE(tmp_single, NULL, module);
312                 if (strcmp(tmp_single, "TRUE") == 0) {
313                         data->attrs[i]->single = 1;
314                 } else {
315                         data->attrs[i]->single = 0;
316                 }
317
318                 /* the following are optional */
319                 data->attrs[i]->min = ldb_msg_find_attr_as_int(res->msgs[i], "rangeLower", INT_MIN);
320                 data->attrs[i]->max = ldb_msg_find_attr_as_int(res->msgs[i], "rangeUpper", INT_MAX);
321                 data->attrs[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
322                 data->attrs[i]->searchflag = ldb_msg_find_attr_as_int(res->msgs[i], "searchFlag", 0);
323                 data->attrs[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", False);
324         }
325
326 done:
327         talloc_free(res);
328         return ret;
329 }
330
331 static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data)
332 {
333         static const char *schema_attrs[] = {   "governsID",
334                                                 "lDAPDisplayName",
335                                                 "objectClassCategory",
336                                                 "defaultObjectCategory",
337                                                 "systemOnly",
338                                                 "systemFlag",
339                                                 "isDefunct",
340                                                 "subClassOf",
341                                                 "systemAuxiliaryClass",
342                                                 "auxiliaryClass",
343                                                 "systemPossSuperiors",
344                                                 "possSuperiors",
345                                                 "possibleInferiors",
346                                                 "systemMustContain",
347                                                 "MustContain", 
348                                                 "systemMayContain",
349                                                 "MayContain",
350                                                 NULL };
351         struct ldb_result *res;
352         int ret, i;
353
354         ret = ldb_search(module->ldb,
355                          data->schema_dn,
356                          LDB_SCOPE_SUBTREE,
357                          "(objectClass=classSchema)",
358                          schema_attrs,
359                          &res);
360
361         if (ret != LDB_SUCCESS) {
362                 goto done;
363         }
364
365         data->num_classes = res->count;
366         data->class = talloc_array(data, struct schema_class *, res->count);
367         SCHEMA_CHECK_VALUE(data->class, NULL, module);
368
369         data->class_store = schema_store_new(data);
370         SCHEMA_CHECK_VALUE(data->class_store, NULL, module);
371
372         for (i = 0; i < res->count; i++) {
373                 struct ldb_message_element *el;
374
375                 data->class[i] = talloc(data->class, struct schema_class);
376                 SCHEMA_CHECK_VALUE(data->class[i], NULL, module);
377
378                 data->class[i]->OID = talloc_strdup(data->class[i],
379                                                 ldb_msg_find_attr_as_string(res->msgs[i], "governsID", NULL));
380                 SCHEMA_CHECK_VALUE(data->class[i]->OID, NULL, module);
381
382                 data->class[i]->name = talloc_strdup(data->class[i],
383                                                 ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
384                 SCHEMA_CHECK_VALUE(data->class[i]->name, NULL, module);
385
386                 /* once we have both the OID and the class name, add the pointer to the store */
387                 schema_store_add(data->class_store, data->class[i]->OID, data->class[i]);
388                 schema_store_add(data->class_store, data->class[i]->name, data->class[i]);
389
390                 data->class[i]->type = ldb_msg_find_attr_as_int(res->msgs[i], "objectClassCategory", -1);
391                 /* 0 should not be a valid value, but turn out it is so test with -1 */
392                 SCHEMA_CHECK_VALUE(data->class[i]->type, -1, module);
393
394                 data->class[i]->defobjcat = talloc_strdup(data->class[i],
395                                                 ldb_msg_find_attr_as_string(res->msgs[i],
396                                                                         "defaultObjectCategory", NULL));
397 /*              SCHEMA_CHECK_VALUE(data->class[i]->defobjcat, NULL, module);
398 */
399                 /* the following attributes are all optional */
400
401                 data->class[i]->systemOnly = ldb_msg_find_attr_as_bool(res->msgs[i], "systemOnly", False);
402                 data->class[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
403                 data->class[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", False);
404
405                 /* attributes are loaded first, so we can just go an query the attributes repo */
406                 
407                 el = ldb_msg_find_element(res->msgs[i], "systemMustContain");
408                 if (el) {
409                         data->class[i]->sysmust = schema_get_attrs_list(module, data, el);
410                         SCHEMA_CHECK_VALUE(data->class[i]->sysmust, NULL, module);
411                 }
412
413                 el = ldb_msg_find_element(res->msgs[i], "MustContain");
414                 if (el) {
415                         data->class[i]->must = schema_get_attrs_list(module, data, el);
416                         SCHEMA_CHECK_VALUE(data->class[i]->must, NULL, module);
417                 }
418
419                 el = ldb_msg_find_element(res->msgs[i], "systemMayContain");
420                 if (el) {
421                         data->class[i]->sysmay = schema_get_attrs_list(module, data, el);
422                         SCHEMA_CHECK_VALUE(data->class[i]->sysmay, NULL, module);
423                 }
424
425                 el = ldb_msg_find_element(res->msgs[i], "MayContain");
426                 if (el) {
427                         data->class[i]->may = schema_get_attrs_list(module, data, el);
428                         SCHEMA_CHECK_VALUE(data->class[i]->may, NULL, module);
429                 }
430
431         }
432
433         /* subClassOf, systemAuxiliaryClass, auxiliaryClass, systemPossSuperiors
434          * must be filled in a second loop, when all class objects are allocated
435          * or we may not find a class that has not yet been parsed */
436         for (i = 0; i < res->count; i++) {
437                 struct ldb_message_element *el;
438                 const char *attr;
439
440                 /* this is single valued anyway */
441                 attr = ldb_msg_find_attr_as_string(res->msgs[i], "subClassOf", NULL);
442                 SCHEMA_CHECK_VALUE(attr, NULL, module);
443                 data->class[i]->parent = schema_store_find(data->class_store, attr);
444                 SCHEMA_CHECK_VALUE(data->class[i]->parent, NULL, module);
445
446                 /* the following attributes are all optional */
447
448                 data->class[i]->sysaux = NULL;
449                 el = ldb_msg_find_element(res->msgs[i], "systemAuxiliaryClass");
450                 if (el) {
451                         data->class[i]->sysaux = schema_get_class_list(module, data, el); 
452                         SCHEMA_CHECK_VALUE(data->class[i]->sysaux, NULL, module);
453                 }
454
455                 data->class[i]->aux = NULL;
456                 el = ldb_msg_find_element(res->msgs[i], "auxiliaryClass");
457                 if (el) {
458                         data->class[i]->aux = schema_get_class_list(module, data, el); 
459                         SCHEMA_CHECK_VALUE(data->class[i]->aux, NULL, module);
460                 }
461
462                 data->class[i]->sysposssup = NULL;
463                 el = ldb_msg_find_element(res->msgs[i], "systemPossSuperiors");
464                 if (el) {
465                         data->class[i]->sysposssup = schema_get_class_list(module, data, el); 
466                         SCHEMA_CHECK_VALUE(data->class[i]->sysposssup, NULL, module);
467                 }
468
469                 data->class[i]->posssup = NULL;
470                 el = ldb_msg_find_element(res->msgs[i], "possSuperiors");
471                 if (el) {
472                         data->class[i]->posssup = schema_get_class_list(module, data, el); 
473                         SCHEMA_CHECK_VALUE(data->class[i]->posssup, NULL, module);
474                 }
475
476                 data->class[i]->possinf = NULL;
477                 el = ldb_msg_find_element(res->msgs[i], "possibleInferiors");
478                 if (el) {
479                         data->class[i]->possinf = schema_get_class_list(module, data, el); 
480                         SCHEMA_CHECK_VALUE(data->class[i]->possinf, NULL, module);
481                 }
482         }
483
484 done:
485         talloc_free(res);
486         return ret;
487 }
488
489 static struct ldb_handle *schema_init_handle(struct ldb_request *req, struct ldb_module *module, enum sc_op op)
490 {
491         struct schema_context *sctx;
492         struct ldb_handle *h;
493
494         h = talloc_zero(req, struct ldb_handle);
495         if (h == NULL) {
496                 ldb_set_errstring(module->ldb, "Out of Memory");
497                 return NULL;
498         }
499
500         h->module = module;
501
502         sctx = talloc_zero(h, struct schema_context);
503         if (sctx == NULL) {
504                 ldb_set_errstring(module->ldb, "Out of Memory");
505                 talloc_free(h);
506                 return NULL;
507         }
508
509         h->private_data = (void *)sctx;
510
511         h->state = LDB_ASYNC_INIT;
512         h->status = LDB_SUCCESS;
513
514         sctx->op = op;
515         sctx->step = SC_INIT;
516         sctx->data = module->private_data;
517         sctx->module = module;
518         sctx->orig_req = req;
519
520         return h;
521 }
522
523 static int schema_add_check_parent(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
524 {
525         struct schema_context *sctx;
526
527         if (!context || !ares) {
528                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
529                 return LDB_ERR_OPERATIONS_ERROR;
530         }
531
532         sctx = talloc_get_type(context, struct schema_context);
533
534         /* we are interested only in the single reply (base search) we receive here */
535         if (ares->type == LDB_REPLY_ENTRY) {
536                 if (sctx->parent_res != NULL) {
537                         ldb_set_errstring(ldb, "Too many results");
538                         talloc_free(ares);
539                         return LDB_ERR_OPERATIONS_ERROR;
540                 }
541                 sctx->parent_res = talloc_steal(sctx, ares);
542         } else {
543                 talloc_free(ares);
544         }
545
546         return LDB_SUCCESS;
547 }
548
549 static int schema_add_build_parent_req(struct schema_context *sctx)
550 {
551         static const char * const parent_attrs[] = { "objectClass", NULL };
552         int ret;
553
554         sctx->parent_req = talloc_zero(sctx, struct ldb_request);
555         if (sctx->parent_req == NULL) {
556                 ldb_debug(sctx->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
557                 return LDB_ERR_OPERATIONS_ERROR;
558         }
559
560         sctx->parent_req->operation = LDB_SEARCH;
561         sctx->parent_req->op.search.scope = LDB_SCOPE_BASE;
562         sctx->parent_req->op.search.base = ldb_dn_get_parent(sctx->parent_req, sctx->orig_req->op.add.message->dn);
563         sctx->parent_req->op.search.tree = ldb_parse_tree(sctx->parent_req, "(objectClass=*)");
564         sctx->parent_req->op.search.attrs = parent_attrs;
565         sctx->parent_req->controls = NULL;
566         sctx->parent_req->context = sctx;
567         sctx->parent_req->callback = schema_add_check_parent;
568         ret = ldb_set_timeout_from_prev_req(sctx->module->ldb, sctx->orig_req, sctx->parent_req);
569
570         return ret;
571 }
572
573 static struct schema_class_dlist *schema_add_get_dlist_entry_with_class(struct schema_class_dlist *list, struct schema_class *class)
574 {
575         struct schema_class_dlist *temp;
576
577         for (temp = list; temp && (temp->class != class); temp = temp->next) /* noop */ ;
578         return temp;
579 }
580
581 static int schema_add_class_to_dlist(struct schema_class_dlist *list, struct schema_class *class, enum schema_class_type role)
582 {
583         struct schema_class_dlist *entry;
584         struct schema_class_dlist *temp;
585         int ret;
586
587         /* see if this class is usable */
588         if (class->isdefunct) {
589                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
590         }
591
592         /* see if this class already exist in the class list */
593         if (schema_add_get_dlist_entry_with_class(list, class)) {
594                 return LDB_SUCCESS;
595         }
596
597         /* this is a new class go on and add to the list */
598         entry = talloc_zero(list, struct schema_class_dlist);
599         if (!entry) return LDB_ERR_OPERATIONS_ERROR;
600         entry->class = class;
601         entry->role = class->type;
602
603         /* If parent is top (list is guaranteed to start always with top) */
604         if (class->parent == list->class) {
605                 /* if the hierarchy role is structural try to add it just after top */
606                 if (role == SCHEMA_CT_STRUCTURAL) {
607                         /* but check no other class at after top has a structural role */
608                         if (list->next && (list->next->role == SCHEMA_CT_STRUCTURAL)) {
609                                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
610                         }
611                         DLIST_ADD_AFTER(list, entry, list);
612                 } else {
613                         DLIST_ADD_END(list, entry, struct schema_class_dlist *);
614                 }
615                 return LDB_SUCCESS;
616         }
617
618         /* search if parent has already been added */
619         temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
620         if (temp == NULL) {
621                 ret = schema_add_class_to_dlist(list, class->parent, role);
622                 if (ret != LDB_SUCCESS) {
623                         return ret;
624                 }
625                 temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
626         }
627         if (!temp) { /* parent not found !? */
628                 return LDB_ERR_OPERATIONS_ERROR;
629         }
630
631         DLIST_ADD_AFTER(list, entry, temp);
632         if (role == SCHEMA_CT_STRUCTURAL || role == SCHEMA_CT_AUXILIARY) {
633                 temp = entry;
634                 do {
635                         temp->role = role;
636                         temp = temp->prev;
637                         /* stop when hierarchy base is met or when base class parent is top */
638                 } while (temp->class == temp->next->class->parent &&
639                          temp->next->class->parent != list->class);
640
641                 /* if we have not reached the head of the list
642                  * and role is structural */
643                 if (temp != list && role == SCHEMA_CT_STRUCTURAL) {
644                         struct schema_class_dlist *hfirst, *hlast;
645
646                         /* check if the list second entry is structural */
647                         if (list->next->role == SCHEMA_CT_STRUCTURAL) {
648                                 /* we have a confilict here */
649                                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
650                         }
651                         /* we have to move this hierarchy of classes
652                          * so that the base of the structural hierarchy is right after top */
653                          
654                         hfirst = temp->next;
655                         hlast = entry;
656                         /* now hfirst - hlast are the boundaries of the structural hierarchy */
657                         
658                         /* extract the structural hierachy from the list */
659                         hfirst->prev->next = hlast->next;
660                         if (hlast->next) hlast->next->prev = hfirst->prev;
661                         
662                         /* insert the structural hierarchy just after top */
663                         list->next->prev = hlast;
664                         hlast->next = list->next;
665                         list->next = hfirst;
666                         hfirst->prev = list;
667                 }       
668         }
669
670         return LDB_SUCCESS;
671 }
672
673 /* merge source list into dest list and remove duplicates */
674 static int schema_merge_class_list(TALLOC_CTX *mem_ctx, struct schema_class ***dest, struct schema_class **source)
675 {
676         struct schema_class **list = *dest;
677         int i, j, n, f;
678
679         n = 0;  
680         if (list) for (n = 0; list[n]; n++) /* noop */ ;
681         f = n;
682
683         for (i = 0; source[i]; i++) {
684                 for (j = 0; j < f; j++) {
685                         if (list[j] == source[i]) {
686                                 break;
687                         }
688                 }
689                 if (j < f) { /* duplicate found */
690                         continue;
691                 }
692
693                 list = talloc_realloc(mem_ctx, list, struct schema_class *, n + 2);
694                 if (!list) {
695                         return LDB_ERR_OPERATIONS_ERROR;
696                 }
697                 list[n] = source[i];
698                 n++;
699                 list[n] = NULL;
700         }
701
702         *dest = list;
703
704         return LDB_SUCCESS;
705 }
706
707 /* validate and modify the objectclass attribute to sort and add parents */
708 static int schema_add_build_objectclass_list(struct schema_context *sctx)
709 {
710         struct schema_class_dlist *temp;
711         struct ldb_message_element * el;
712         struct schema_class *class;
713         int ret, i, an;
714
715         /* First of all initialize list, it must start with class top */
716         sctx->class_list = talloc_zero(sctx, struct schema_class_dlist);
717         if (!sctx->class_list) return LDB_ERR_OPERATIONS_ERROR;
718
719         sctx->class_list->class = schema_store_find(sctx->data->class_store, "top");
720         if (!sctx->class_list->class) return LDB_ERR_OPERATIONS_ERROR;
721
722         el = ldb_msg_find_element(sctx->orig_req->op.add.message, "objectClass");
723         if (!el) {
724                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
725         }
726
727         for (i = 0; i < el->num_values; i++) {
728
729                 class = schema_store_find(sctx->data->class_store, (char *)el->values[i].data);
730                 if (!class) {
731                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
732                 }
733                 
734                 ret = schema_add_class_to_dlist(sctx->class_list, class, class->type);
735                 if (ret != LDB_SUCCESS) {
736                         return ret;
737                 }
738         }
739
740         /* now check if there is any class role that is still not STRUCTURAL or AUXILIARY */
741         /* build also the auxiliary class list and the possible superiors list */ 
742         temp = sctx->class_list->next; /* top is special, skip it */
743         an = 0;
744
745         while (temp) {
746                 if (temp->role == SCHEMA_CT_ABSTRACT || temp->role == SCHEMA_CT_88) {
747                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
748                 }
749                 if (temp->class->sysaux) {
750                         ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->sysaux);
751                         if (ret != LDB_SUCCESS) {
752                                 return LDB_ERR_OPERATIONS_ERROR;
753                         }
754                 }
755                 if (temp->class->aux) {
756                         ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->aux);
757                         if (ret != LDB_SUCCESS) {
758                                 return LDB_ERR_OPERATIONS_ERROR;
759                         }
760                 }
761                 if (temp->class->sysposssup) {
762                         ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->sysposssup);
763                         if (ret != LDB_SUCCESS) {
764                                 return LDB_ERR_OPERATIONS_ERROR;
765                         }
766                 }
767                 if (temp->class->posssup) {
768                         ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->posssup);
769                         if (ret != LDB_SUCCESS) {
770                                 return LDB_ERR_OPERATIONS_ERROR;
771                         }
772                 }
773                 temp = temp->next;
774         }
775
776         /* complete sup_list with material from the aux classes */
777         for (i = 0; sctx->aux_list && sctx->aux_list[i]; i++) {
778                 if (sctx->aux_list[i]->sysposssup) {
779                         ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->sysposssup);
780                         if (ret != LDB_SUCCESS) {
781                                 return LDB_ERR_OPERATIONS_ERROR;
782                         }
783                 }
784                 if (sctx->aux_list[i]->posssup) {
785                         ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->posssup);
786                         if (ret != LDB_SUCCESS) {
787                                 return LDB_ERR_OPERATIONS_ERROR;
788                         }
789                 }
790         }
791
792         if (!sctx->sup_list) return LDB_ERR_NAMING_VIOLATION;
793
794         return LDB_SUCCESS;
795 }
796
797 static int schema_add_check_container_constraints(struct schema_context *sctx)
798 {
799         struct schema_class **parent_possinf = NULL;
800         struct schema_class **parent_classes;
801         struct schema_class_dlist *temp;
802         struct ldb_message_element *el;
803         int i, j, ret;
804
805         el = ldb_msg_find_element(sctx->parent_res->message, "objectClass");
806         if (!el) {
807                 /* what the .. */
808                 return LDB_ERR_OPERATIONS_ERROR;
809         }
810
811         parent_classes = talloc_array(sctx, struct schema_class *, el->num_values + 1);
812
813         for (i = 0; i < el->num_values; i++) {
814
815                 parent_classes[i] = schema_store_find(sctx->data->class_store, (const char *)el->values[i].data);
816                 if (!parent_classes[i]) { /* should not be possible */
817                         return LDB_ERR_OPERATIONS_ERROR;
818                 }
819
820                 if (parent_classes[i]->possinf) {
821                         ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->possinf);
822                         if (ret != LDB_SUCCESS) {
823                                 return LDB_ERR_OPERATIONS_ERROR;
824                         }
825                 }
826
827                 /* check also embedded auxiliary classes possinf */
828                 for (j = 0; parent_classes[i]->sysaux && parent_classes[i]->sysaux[j]; j++) {
829                         if (parent_classes[i]->sysaux[j]->possinf) {
830                                 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->sysaux[j]->possinf);
831                                 if (ret != LDB_SUCCESS) {
832                                         return LDB_ERR_OPERATIONS_ERROR;
833                                 }
834                         }
835                 }
836                 for (j = 0; parent_classes[i]->aux && parent_classes[i]->aux[j]; j++) {
837                         if (parent_classes[i]->aux[j]->possinf) {
838                                 ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->aux[j]->possinf);
839                                 if (ret != LDB_SUCCESS) {
840                                         return LDB_ERR_OPERATIONS_ERROR;
841                                 }
842                         }
843                 }
844         }
845
846         /* foreach parent objectclass,
847          *   check parent possible inferiors match all of the child objectclasses
848          *    and that
849          *   poss Superiors of the child objectclasses mathes one of the parent classes
850          */
851
852         temp = sctx->class_list->next; /* skip top it is special */
853         while (temp) {
854
855                 for (i = 0; parent_possinf[i]; i++) {
856                         if (temp->class == parent_possinf[i]) {
857                                 break;
858                         }
859                 }
860                 if (parent_possinf[i] == NULL) {
861                         /* class not found in possible inferiors */
862                         return LDB_ERR_NAMING_VIOLATION;
863                 }
864
865                 temp = temp->next;
866         }
867
868         for (i = 0; parent_classes[i]; i++) {
869                 for (j = 0; sctx->sup_list[j]; j++) {
870                         if (sctx->sup_list[j] == parent_classes[i]) {
871                                 break;
872                         }
873                 }
874                 if (sctx->sup_list[j]) { /* possible Superiors match one of the parent classes */
875                         return LDB_SUCCESS;
876                 }
877         }
878
879         /* no parent classes matched superiors */
880         return LDB_ERR_NAMING_VIOLATION;
881 }
882
883 static int schema_add_build_down_req(struct schema_context *sctx)
884 {
885         struct schema_class_dlist *temp;
886         struct ldb_message *msg;
887         char *oc;
888         int ret;
889
890         sctx->down_req = talloc(sctx, struct ldb_request);
891         if (!sctx->down_req) {
892                 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
893                 return LDB_ERR_OPERATIONS_ERROR;
894         }
895
896         *(sctx->down_req) = *(sctx->orig_req); /* copy the request */
897         msg = ldb_msg_copy_shallow(sctx->down_req, sctx->orig_req->op.add.message);
898         if (!msg) {
899                 ldb_set_errstring(sctx->module->ldb, "Out of memory!");
900                 return LDB_ERR_OPERATIONS_ERROR;
901         }
902
903         /* rebuild the objectclass list */
904         ldb_msg_remove_attr(msg, "objectClass");
905         ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
906         if (ret != LDB_SUCCESS) {
907                 return ret;
908         }
909
910         /* Add the complete list of classes back to the message */
911         for (temp = sctx->class_list; temp; temp = temp->next) {
912                 ret = ldb_msg_add_string(msg, "objectClass", temp->class->name);
913                 if (ret != LDB_SUCCESS) {
914                         return ret;
915                 }
916         }
917
918         /* objectCategory can be set only by the system */
919         if (ldb_msg_find_element(msg, "objectCategory")) {
920                 return LDB_ERR_CONSTRAINT_VIOLATION;
921         }
922
923         /* the OC is mandatory, every class defines it */
924         /* use the one defined in the structural class that defines the object */
925         for (temp = sctx->class_list->next; temp; temp = temp->next) {
926                 if (!temp->next) break;
927                 if (temp->next->role != SCHEMA_CT_STRUCTURAL) break;
928         }
929 /*      oc = talloc_strdup(msg, temp->class->defobjcat);
930         ret = ldb_msg_add_string(msg, "objectCategory", oc);
931 */
932         sctx->down_req->op.add.message = msg;
933
934         return LDB_SUCCESS;
935 }
936
937 static int schema_check_attributes_syntax(struct schema_context *sctx)
938 {
939         struct ldb_message *msg;
940         struct schema_attribute *attr;
941         int i, ret;
942
943         msg = sctx->orig_req->op.add.message;
944         for (i = 0; i < msg->num_elements; i++) {
945                 attr = schema_store_find(sctx->data->attrs_store, msg->elements[i].name);
946                 if (attr == NULL) {
947                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
948                 }
949                 ret = schema_validate(&msg->elements[i], attr->syntax, attr->single, attr->min, attr->max);
950                 if (ret != LDB_SUCCESS) {
951                         return ret;
952                 }
953         }
954
955         return LDB_SUCCESS;
956 }
957
958 static int schema_add_continue(struct ldb_handle *h)
959 {
960         struct schema_context *sctx;
961         int ret;
962
963         sctx = talloc_get_type(h->private_data, struct schema_context);
964
965         switch (sctx->step) {
966         case SC_INIT:
967
968                 /* First of all check that a parent exists for this entry */
969                 ret = schema_add_build_parent_req(sctx);
970                 if (ret != LDB_SUCCESS) {
971                         break;
972                 }
973
974                 sctx->step = SC_ADD_CHECK_PARENT;
975                 return ldb_next_request(sctx->module, sctx->parent_req);
976
977         case SC_ADD_CHECK_PARENT:
978
979                 /* parent search done, check result and go on */
980                 if (sctx->parent_res == NULL) {
981                         /* we must have a parent */
982                         ret = LDB_ERR_NO_SUCH_OBJECT;
983                         break;
984                 }
985
986                 /* Check objectclasses are ok */
987                 ret = schema_add_build_objectclass_list(sctx);
988                 if (ret != LDB_SUCCESS) {
989                         break;
990                 }
991
992                 /* check the parent is of the right type for this object */
993                 ret = schema_add_check_container_constraints(sctx);
994                 if (ret != LDB_SUCCESS) {
995                         break;
996                 }
997
998                 /* check attributes syntax */
999                 
1000                 ret = schema_check_attributes_syntax(sctx);
1001                 if (ret != LDB_SUCCESS) {
1002                         break;
1003                 }
1004
1005                 ret = schema_add_build_down_req(sctx);
1006                 if (ret != LDB_SUCCESS) {
1007                         break;
1008                 }
1009                 sctx->step = SC_ADD_TEMP;
1010
1011                 return ldb_next_request(sctx->module, sctx->down_req);
1012
1013         default:
1014                 ret = LDB_ERR_OPERATIONS_ERROR;
1015                 break;
1016         }
1017
1018         /* this is reached only in case of error */
1019         /* FIXME: fire an async reply ? */
1020         h->status = ret;
1021         h->state = LDB_ASYNC_DONE;
1022         return ret;
1023 }
1024
1025 static int schema_add(struct ldb_module *module, struct ldb_request *req)
1026 {
1027         struct schema_context *sctx;
1028         struct ldb_handle *h;
1029
1030         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1031                 return ldb_next_request(module, req);
1032         }
1033
1034         h = schema_init_handle(req, module, SC_ADD);
1035         if (!h) {
1036                 return LDB_ERR_OPERATIONS_ERROR;
1037         }
1038
1039         sctx = talloc_get_type(h->private_data, struct schema_context);
1040         sctx->orig_req->handle = h;
1041         return schema_add_continue(h);
1042 }
1043
1044
1045 static int schema_modify(struct ldb_module *module, struct ldb_request *req)
1046 {
1047         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1048                 return ldb_next_request(module, req);
1049         }
1050
1051         return ldb_next_request(module, req);   
1052 }
1053
1054 static int schema_delete(struct ldb_module *module, struct ldb_request *req)
1055 {
1056         if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */
1057                 return ldb_next_request(module, req);
1058         }
1059         
1060         /* First of all check no children exists for this entry */
1061
1062         return ldb_next_request(module, req);
1063 }
1064
1065 static int schema_rename(struct ldb_module *module, struct ldb_request *req)
1066 {
1067         if (ldb_dn_is_special(req->op.rename.olddn) &&
1068             ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1069                 return ldb_next_request(module, req);
1070         }
1071
1072         return ldb_next_request(module, req);
1073 }
1074
1075 static int schema_wait_loop(struct ldb_handle *handle) {
1076         struct schema_context *sctx;
1077         int ret;
1078     
1079         if (!handle || !handle->private_data) {
1080                 return LDB_ERR_OPERATIONS_ERROR;
1081         }
1082
1083         if (handle->state == LDB_ASYNC_DONE) {
1084                 return handle->status;
1085         }
1086
1087         handle->state = LDB_ASYNC_PENDING;
1088         handle->status = LDB_SUCCESS;
1089
1090         sctx = talloc_get_type(handle->private_data, struct schema_context);
1091
1092         switch (sctx->step) {
1093         case SC_ADD_CHECK_PARENT:
1094                 ret = ldb_wait(sctx->parent_req->handle, LDB_WAIT_NONE);
1095
1096                 if (ret != LDB_SUCCESS) {
1097                         handle->status = ret;
1098                         goto done;
1099                 }
1100                 if (sctx->parent_req->handle->status != LDB_SUCCESS) {
1101                         handle->status = sctx->parent_req->handle->status;
1102                         goto done;
1103                 }
1104
1105                 if (sctx->parent_req->handle->state != LDB_ASYNC_DONE) {
1106                         return LDB_SUCCESS;
1107                 }
1108
1109                 return schema_add_continue(handle);
1110
1111         case SC_ADD_TEMP:
1112                 ret = ldb_wait(sctx->down_req->handle, LDB_WAIT_NONE);
1113
1114                 if (ret != LDB_SUCCESS) {
1115                         handle->status = ret;
1116                         goto done;
1117                 }
1118                 if (sctx->down_req->handle->status != LDB_SUCCESS) {
1119                         handle->status = sctx->down_req->handle->status;
1120                         goto done;
1121                 }
1122
1123                 if (sctx->down_req->handle->state != LDB_ASYNC_DONE) {
1124                         return LDB_SUCCESS;
1125                 }
1126
1127                 break;
1128
1129         default:
1130                 ret = LDB_ERR_OPERATIONS_ERROR;
1131                 goto done;
1132         }
1133
1134         ret = LDB_SUCCESS;
1135
1136 done:
1137         handle->state = LDB_ASYNC_DONE;
1138         return ret;
1139 }
1140
1141 static int schema_wait_all(struct ldb_handle *handle) {
1142
1143         int ret;
1144
1145         while (handle->state != LDB_ASYNC_DONE) {
1146                 ret = schema_wait_loop(handle);
1147                 if (ret != LDB_SUCCESS) {
1148                         return ret;
1149                 }
1150         }
1151
1152         return handle->status;
1153 }
1154
1155 static int schema_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1156 {
1157         if (type == LDB_WAIT_ALL) {
1158                 return schema_wait_all(handle);
1159         } else {
1160                 return schema_wait_loop(handle);
1161         }
1162 }
1163
1164 static int schema_init(struct ldb_module *module)
1165 {
1166         static const char *schema_attrs[] = { "schemaNamingContext", NULL };
1167         struct schema_private_data *data;
1168         struct ldb_result *res;
1169         int ret;
1170
1171         /* need to let the partition module to register first */
1172         ret = ldb_next_init(module);
1173         if (ret != LDB_SUCCESS) {
1174                 return ret;
1175         }
1176
1177         data = ldb_get_opaque(module->ldb, "schema_instance");
1178         if (data) {
1179                 module->private_data = data;
1180                 return LDB_SUCCESS;
1181         }
1182
1183         data = talloc_zero(module->ldb, struct schema_private_data);
1184         if (data == NULL) {
1185                 return LDB_ERR_OPERATIONS_ERROR;
1186         }
1187
1188         /* find the schema partition */
1189         ret = ldb_search(module->ldb,
1190                          ldb_dn_new(module),
1191                          LDB_SCOPE_BASE,
1192                          "(objectClass=*)",
1193                          schema_attrs,
1194                          &res);
1195
1196         if (res->count != 1) {
1197                 /* FIXME: return a clear error string */
1198                 talloc_free(data);
1199                 talloc_free(res);
1200                 return LDB_ERR_OPERATIONS_ERROR;
1201         }
1202
1203         data->schema_dn = ldb_msg_find_attr_as_dn(data, res->msgs[0], "schemaNamingContext");
1204         if (data->schema_dn == NULL) {
1205                 /* FIXME: return a clear error string */
1206                 talloc_free(data);
1207                 talloc_free(res);
1208                 return LDB_ERR_OPERATIONS_ERROR;
1209         }
1210
1211         talloc_free(res);
1212
1213         ret = schema_init_attrs(module, data);
1214         if (ret != LDB_SUCCESS) {
1215                 talloc_free(data);
1216                 return ret;
1217         }
1218
1219         ret = schema_init_classes(module, data);
1220         if (ret != LDB_SUCCESS) {
1221                 talloc_free(data);
1222                 return ret;
1223         }
1224
1225         module->private_data = data;
1226         ldb_set_opaque(module->ldb, "schema_instance", data);
1227
1228         return LDB_SUCCESS;
1229 }
1230
1231 static const struct ldb_module_ops schema_ops = {
1232         .name          = "schema",
1233         .init_context  = schema_init,
1234         .add           = schema_add,
1235         .modify        = schema_modify,
1236         .del           = schema_delete,
1237         .rename        = schema_rename,
1238         .wait          = schema_wait
1239 };
1240
1241 int ldb_schema_init(void)
1242 {
1243         return ldb_register_module(&schema_ops);
1244 }