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