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