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