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