4 Copyright (C) Simo Sorce 2004-2006
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Component: ldb schema module
25 * Description: add schema check functionality
31 #include "libcli/ldap/ldap.h"
32 #include "ldb/include/ldb_errors.h"
33 #include "ldb/include/ldb_private.h"
34 #include "lib/util/dlinklist.h"
35 #include "schema_syntax.h"
39 see ldap_server/devdocs/AD-syntaxes.txt
42 enum schema_class_type
{
44 SCHEMA_CT_STRUCTURAL
= 1,
45 SCHEMA_CT_ABSTRACT
= 2,
46 SCHEMA_CT_AUXILIARY
= 3
49 struct schema_attribute
{
50 char *OID
; /* attributeID */
51 char *name
; /* lDAPDisplayName */
52 enum schema_internal_syntax syntax
; /* generated from attributeSyntax, oMSyntax, oMObjectClass */
53 bool single
; /* isSingleValued */
54 int min
; /* rangeLower */
55 int max
; /* rangeUpper */
56 int systemflag
; /* systemFlag */
57 int searchflag
; /* searchFlag */
58 bool isdefunct
; /* isDefunct */
62 char *OID
; /* governsID */
63 char *name
; /* lDAPDisplayName */
64 enum schema_class_type type
; /* objectClassCategory */
65 bool systemOnly
; /* systemOnly */
66 bool isdefunct
; /* isDefunct */
67 int systemflag
; /* systemFlag */
68 char *defobjcat
; /* defaultObjectCategory */
69 struct schema_class
*parent
; /* subClassOf */
70 struct schema_class
**sysaux
; /* systemAuxiliaryClass */
71 struct schema_class
**aux
; /* auxiliaryClass */
72 struct schema_class
**sysposssup
; /* systemPossSuperiors */
73 struct schema_class
**posssup
; /* possSuperiors */
74 struct schema_class
**possinf
; /* possibleInferiors */
75 struct schema_attribute
**sysmust
; /* systemMustContain */
76 struct schema_attribute
**must
; /* MustContain */
77 struct schema_attribute
**sysmay
; /* systemMayContain */
78 struct schema_attribute
**may
; /* MayContain */
81 /* TODO: ditcontentrules */
83 struct schema_private_data
{
84 struct ldb_dn
*schema_dn
;
85 struct schema_attribute
**attrs
;
86 struct schema_store
*attrs_store
;
88 struct schema_class
**class;
89 struct schema_store
*class_store
;
93 struct schema_class_dlist
{
94 struct schema_class
*class;
95 struct schema_class_dlist
*prev
;
96 struct schema_class_dlist
*next
;
97 enum schema_class_type role
;
100 struct schema_context
{
102 enum sc_op
{ SC_ADD
, SC_MOD
, SC_DEL
, SC_RENAME
} op
;
103 enum sc_step
{ SC_INIT
, SC_ADD_CHECK_PARENT
, SC_ADD_TEMP
, SC_DEL_CHECK_CHILDREN
} step
;
105 struct schema_private_data
*data
;
107 struct ldb_module
*module
;
108 struct ldb_request
*orig_req
;
109 struct ldb_request
*down_req
;
111 struct ldb_request
*parent_req
;
112 struct ldb_reply
*parent_res
;
114 struct schema_class_dlist
*class_list
;
115 struct schema_class
**sup_list
;
116 struct schema_class
**aux_list
;
119 /* FIXME: I'd really like to use an hash table here */
125 struct schema_store
{
126 struct schema_link
*store
;
130 static struct schema_store
*schema_store_new(TALLOC_CTX
*mem_ctx
)
132 struct schema_store
*ht
;
134 ht
= talloc(mem_ctx
, struct schema_store
);
135 if (!ht
) return NULL
;
143 static int schema_store_add(struct schema_store
*ht
, const char *key
, void *object
)
145 ht
->store
= talloc_realloc(ht
, ht
->store
, struct schema_link
, ht
->num_links
+ 1);
146 if (!ht
->store
) return LDB_ERR_OPERATIONS_ERROR
;
148 ht
->store
[ht
->num_links
].name
= key
;
149 ht
->store
[ht
->num_links
].object
= object
;
156 static void *schema_store_find(struct schema_store
*ht
, const char *key
)
160 for (i
= 0; i
< ht
->num_links
; i
++) {
161 if (strcasecmp(ht
->store
[i
].name
, key
) == 0) {
162 return ht
->store
[i
].object
;
169 #define SCHEMA_CHECK_VALUE(mem, val, mod) \
170 do { if (mem == val) { \
171 ret = LDB_ERR_OPERATIONS_ERROR; \
172 ldb_asprintf_errstring(mod->ldb, \
173 "schema module: Memory allocation or attribute error on %s", #mem); \
174 goto done; } } while(0)
176 struct schema_class
**schema_get_class_list(struct ldb_module
*module
,
177 struct schema_private_data
*data
,
178 struct ldb_message_element
*el
)
180 struct schema_class
**list
;
183 list
= talloc_array(data
, struct schema_class
*, el
->num_values
+ 1);
185 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory");
189 for (i
= 0; i
< el
->num_values
; i
++) {
190 list
[i
] = (struct schema_class
*)schema_store_find(data
->class_store
,
191 (char *)el
->values
[i
].data
);
193 ldb_debug_set(module
->ldb
,
195 "Class %s referenced but not found in schema\n",
196 (char *)el
->values
[i
].data
);
205 struct schema_attribute
**schema_get_attrs_list(struct ldb_module
*module
,
206 struct schema_private_data
*data
,
207 struct ldb_message_element
*el
)
209 struct schema_attribute
**list
;
212 list
= talloc_array(data
, struct schema_attribute
*, el
->num_values
+ 1);
214 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory");
218 for (i
= 0; i
< el
->num_values
; i
++) {
219 list
[i
] = (struct schema_attribute
*)schema_store_find(data
->attrs_store
,
220 (char *)el
->values
[i
].data
);
222 ldb_debug_set(module
->ldb
,
224 "Attriobute %s referenced but not found in schema\n",
225 (char *)el
->values
[i
].data
);
234 static int schema_init_attrs(struct ldb_module
*module
, struct schema_private_data
*data
)
236 static const char *schema_attrs
[] = { "attributeID",
248 struct ldb_result
*res
;
251 ret
= ldb_search(module
->ldb
,
254 "(objectClass=attributeSchema)",
258 if (ret
!= LDB_SUCCESS
) {
262 data
->num_attributes
= res
->count
;
263 data
->attrs
= talloc_array(data
, struct schema_attribute
*, res
->count
);
264 SCHEMA_CHECK_VALUE(data
->attrs
, NULL
, module
);
266 data
->attrs_store
= schema_store_new(data
);
267 SCHEMA_CHECK_VALUE(data
->attrs_store
, NULL
, module
);
269 for (i
= 0; i
< res
->count
; i
++) {
270 const char *tmp_single
;
271 const char *attr_syntax
;
273 const struct ldb_val
*om_class
;
275 data
->attrs
[i
] = talloc(data
->attrs
, struct schema_attribute
);
276 SCHEMA_CHECK_VALUE(data
->attrs
[i
], NULL
, module
);
278 data
->attrs
[i
]->OID
= talloc_strdup(data
->attrs
[i
],
279 ldb_msg_find_attr_as_string(res
->msgs
[i
], "attributeID", NULL
));
280 SCHEMA_CHECK_VALUE(data
->attrs
[i
]->OID
, NULL
, module
);
282 data
->attrs
[i
]->name
= talloc_strdup(data
->attrs
[i
],
283 ldb_msg_find_attr_as_string(res
->msgs
[i
], "lDAPDisplayName", NULL
));
284 SCHEMA_CHECK_VALUE(data
->attrs
[i
]->name
, NULL
, module
);
286 /* once we have both the OID and the attribute name, add the pointer to the store */
287 schema_store_add(data
->attrs_store
, data
->attrs
[i
]->OID
, data
->attrs
[i
]);
288 schema_store_add(data
->attrs_store
, data
->attrs
[i
]->name
, data
->attrs
[i
]);
290 attr_syntax
= ldb_msg_find_attr_as_string(res
->msgs
[i
], "attributeSyntax", NULL
);
291 SCHEMA_CHECK_VALUE(attr_syntax
, NULL
, module
);
293 om_syntax
= ldb_msg_find_attr_as_uint(res
->msgs
[i
], "oMSyntax", 0);
294 /* 0 is not a valid oMSyntax */
295 SCHEMA_CHECK_VALUE(om_syntax
, 0, module
);
297 om_class
= ldb_msg_find_ldb_val(res
->msgs
[i
], "oMObjectClass");
299 ret
= map_schema_syntax(om_syntax
, attr_syntax
, om_class
, &data
->attrs
[i
]->syntax
);
300 if (ret
!= LDB_SUCCESS
) {
301 ldb_asprintf_errstring(module
->ldb
,
302 "schema module: invalid om syntax value on %s",
303 data
->attrs
[i
]->name
);
307 tmp_single
= ldb_msg_find_attr_as_string(res
->msgs
[i
], "isSingleValued", NULL
);
308 SCHEMA_CHECK_VALUE(tmp_single
, NULL
, module
);
309 if (strcmp(tmp_single
, "TRUE") == 0) {
310 data
->attrs
[i
]->single
= 1;
312 data
->attrs
[i
]->single
= 0;
315 /* the following are optional */
316 data
->attrs
[i
]->min
= ldb_msg_find_attr_as_int(res
->msgs
[i
], "rangeLower", INT_MIN
);
317 data
->attrs
[i
]->max
= ldb_msg_find_attr_as_int(res
->msgs
[i
], "rangeUpper", INT_MAX
);
318 data
->attrs
[i
]->systemflag
= ldb_msg_find_attr_as_int(res
->msgs
[i
], "systemFlag", 0);
319 data
->attrs
[i
]->searchflag
= ldb_msg_find_attr_as_int(res
->msgs
[i
], "searchFlag", 0);
320 data
->attrs
[i
]->isdefunct
= ldb_msg_find_attr_as_bool(res
->msgs
[i
], "isDefunct", false);
328 static int schema_init_classes(struct ldb_module
*module
, struct schema_private_data
*data
)
330 const char *schema_attrs
[] = { "governsID",
332 "objectClassCategory",
333 "defaultObjectCategory",
338 "systemAuxiliaryClass",
340 "systemPossSuperiors",
348 struct ldb_result
*res
;
351 ret
= ldb_search(module
->ldb
,
354 "(objectClass=classSchema)",
358 if (ret
!= LDB_SUCCESS
) {
362 data
->num_classes
= res
->count
;
363 data
->class = talloc_array(data
, struct schema_class
*, res
->count
);
364 SCHEMA_CHECK_VALUE(data
->class, NULL
, module
);
366 data
->class_store
= schema_store_new(data
);
367 SCHEMA_CHECK_VALUE(data
->class_store
, NULL
, module
);
369 for (i
= 0; i
< res
->count
; i
++) {
370 struct ldb_message_element
*el
;
372 data
->class[i
] = talloc(data
->class, struct schema_class
);
373 SCHEMA_CHECK_VALUE(data
->class[i
], NULL
, module
);
375 data
->class[i
]->OID
= talloc_strdup(data
->class[i
],
376 ldb_msg_find_attr_as_string(res
->msgs
[i
], "governsID", NULL
));
377 SCHEMA_CHECK_VALUE(data
->class[i
]->OID
, NULL
, module
);
379 data
->class[i
]->name
= talloc_strdup(data
->class[i
],
380 ldb_msg_find_attr_as_string(res
->msgs
[i
], "lDAPDisplayName", NULL
));
381 SCHEMA_CHECK_VALUE(data
->class[i
]->name
, NULL
, module
);
383 /* once we have both the OID and the class name, add the pointer to the store */
384 schema_store_add(data
->class_store
, data
->class[i
]->OID
, data
->class[i
]);
385 schema_store_add(data
->class_store
, data
->class[i
]->name
, data
->class[i
]);
387 data
->class[i
]->type
= ldb_msg_find_attr_as_int(res
->msgs
[i
], "objectClassCategory", -1);
388 /* 0 should not be a valid value, but turn out it is so test with -1 */
389 SCHEMA_CHECK_VALUE(data
->class[i
]->type
, -1, module
);
391 data
->class[i
]->defobjcat
= talloc_strdup(data
->class[i
],
392 ldb_msg_find_attr_as_string(res
->msgs
[i
],
393 "defaultObjectCategory", NULL
));
394 /* SCHEMA_CHECK_VALUE(data->class[i]->defobjcat, NULL, module);
396 /* the following attributes are all optional */
398 data
->class[i
]->systemOnly
= ldb_msg_find_attr_as_bool(res
->msgs
[i
], "systemOnly", false);
399 data
->class[i
]->systemflag
= ldb_msg_find_attr_as_int(res
->msgs
[i
], "systemFlag", 0);
400 data
->class[i
]->isdefunct
= ldb_msg_find_attr_as_bool(res
->msgs
[i
], "isDefunct", false);
402 /* attributes are loaded first, so we can just go an query the attributes repo */
404 el
= ldb_msg_find_element(res
->msgs
[i
], "systemMustContain");
406 data
->class[i
]->sysmust
= schema_get_attrs_list(module
, data
, el
);
407 SCHEMA_CHECK_VALUE(data
->class[i
]->sysmust
, NULL
, module
);
410 el
= ldb_msg_find_element(res
->msgs
[i
], "MustContain");
412 data
->class[i
]->must
= schema_get_attrs_list(module
, data
, el
);
413 SCHEMA_CHECK_VALUE(data
->class[i
]->must
, NULL
, module
);
416 el
= ldb_msg_find_element(res
->msgs
[i
], "systemMayContain");
418 data
->class[i
]->sysmay
= schema_get_attrs_list(module
, data
, el
);
419 SCHEMA_CHECK_VALUE(data
->class[i
]->sysmay
, NULL
, module
);
422 el
= ldb_msg_find_element(res
->msgs
[i
], "MayContain");
424 data
->class[i
]->may
= schema_get_attrs_list(module
, data
, el
);
425 SCHEMA_CHECK_VALUE(data
->class[i
]->may
, NULL
, module
);
430 /* subClassOf, systemAuxiliaryClass, auxiliaryClass, systemPossSuperiors
431 * must be filled in a second loop, when all class objects are allocated
432 * or we may not find a class that has not yet been parsed */
433 for (i
= 0; i
< res
->count
; i
++) {
434 struct ldb_message_element
*el
;
437 /* this is single valued anyway */
438 attr
= ldb_msg_find_attr_as_string(res
->msgs
[i
], "subClassOf", NULL
);
439 SCHEMA_CHECK_VALUE(attr
, NULL
, module
);
440 data
->class[i
]->parent
= schema_store_find(data
->class_store
, attr
);
441 SCHEMA_CHECK_VALUE(data
->class[i
]->parent
, NULL
, module
);
443 /* the following attributes are all optional */
445 data
->class[i
]->sysaux
= NULL
;
446 el
= ldb_msg_find_element(res
->msgs
[i
], "systemAuxiliaryClass");
448 data
->class[i
]->sysaux
= schema_get_class_list(module
, data
, el
);
449 SCHEMA_CHECK_VALUE(data
->class[i
]->sysaux
, NULL
, module
);
452 data
->class[i
]->aux
= NULL
;
453 el
= ldb_msg_find_element(res
->msgs
[i
], "auxiliaryClass");
455 data
->class[i
]->aux
= schema_get_class_list(module
, data
, el
);
456 SCHEMA_CHECK_VALUE(data
->class[i
]->aux
, NULL
, module
);
459 data
->class[i
]->sysposssup
= NULL
;
460 el
= ldb_msg_find_element(res
->msgs
[i
], "systemPossSuperiors");
462 data
->class[i
]->sysposssup
= schema_get_class_list(module
, data
, el
);
463 SCHEMA_CHECK_VALUE(data
->class[i
]->sysposssup
, NULL
, module
);
466 data
->class[i
]->posssup
= NULL
;
467 el
= ldb_msg_find_element(res
->msgs
[i
], "possSuperiors");
469 data
->class[i
]->posssup
= schema_get_class_list(module
, data
, el
);
470 SCHEMA_CHECK_VALUE(data
->class[i
]->posssup
, NULL
, module
);
473 data
->class[i
]->possinf
= NULL
;
474 el
= ldb_msg_find_element(res
->msgs
[i
], "possibleInferiors");
476 data
->class[i
]->possinf
= schema_get_class_list(module
, data
, el
);
477 SCHEMA_CHECK_VALUE(data
->class[i
]->possinf
, NULL
, module
);
486 static struct ldb_handle
*schema_init_handle(struct ldb_request
*req
, struct ldb_module
*module
, enum sc_op op
)
488 struct schema_context
*sctx
;
489 struct ldb_handle
*h
;
491 h
= talloc_zero(req
, struct ldb_handle
);
493 ldb_set_errstring(module
->ldb
, "Out of Memory");
499 sctx
= talloc_zero(h
, struct schema_context
);
501 ldb_set_errstring(module
->ldb
, "Out of Memory");
506 h
->private_data
= (void *)sctx
;
508 h
->state
= LDB_ASYNC_INIT
;
509 h
->status
= LDB_SUCCESS
;
512 sctx
->step
= SC_INIT
;
513 sctx
->data
= module
->private_data
;
514 sctx
->module
= module
;
515 sctx
->orig_req
= req
;
520 static int schema_add_check_parent(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
522 struct schema_context
*sctx
;
524 sctx
= talloc_get_type(context
, struct schema_context
);
526 /* we are interested only in the single reply (base search) we receive here */
527 if (ares
->type
== LDB_REPLY_ENTRY
) {
528 if (sctx
->parent_res
!= NULL
) {
529 ldb_set_errstring(ldb
, "Too many results");
531 return LDB_ERR_OPERATIONS_ERROR
;
533 sctx
->parent_res
= talloc_steal(sctx
, ares
);
541 static int schema_add_build_parent_req(struct schema_context
*sctx
)
543 const char * const parent_attrs
[] = { "objectClass", NULL
};
546 sctx
->parent_req
= talloc_zero(sctx
, struct ldb_request
);
547 if (sctx
->parent_req
== NULL
) {
548 ldb_debug(sctx
->module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory!\n");
549 return LDB_ERR_OPERATIONS_ERROR
;
552 sctx
->parent_req
->operation
= LDB_SEARCH
;
553 sctx
->parent_req
->op
.search
.scope
= LDB_SCOPE_BASE
;
554 sctx
->parent_req
->op
.search
.base
= ldb_dn_get_parent(sctx
->parent_req
, sctx
->orig_req
->op
.add
.message
->dn
);
555 sctx
->parent_req
->op
.search
.tree
= ldb_parse_tree(sctx
->parent_req
, "(objectClass=*)");
556 sctx
->parent_req
->op
.search
.attrs
= parent_attrs
;
557 sctx
->parent_req
->controls
= NULL
;
558 sctx
->parent_req
->context
= sctx
;
559 sctx
->parent_req
->callback
= schema_add_check_parent
;
560 ret
= ldb_set_timeout_from_prev_req(sctx
->module
->ldb
, sctx
->orig_req
, sctx
->parent_req
);
565 static struct schema_class_dlist
*schema_add_get_dlist_entry_with_class(struct schema_class_dlist
*list
, struct schema_class
*class)
567 struct schema_class_dlist
*temp
;
569 for (temp
= list
; temp
&& (temp
->class != class); temp
= temp
->next
) /* noop */ ;
573 static int schema_add_class_to_dlist(struct schema_class_dlist
*list
, struct schema_class
*class, enum schema_class_type role
)
575 struct schema_class_dlist
*entry
;
576 struct schema_class_dlist
*temp
;
579 /* see if this class is usable */
580 if (class->isdefunct
) {
581 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
584 /* see if this class already exist in the class list */
585 if (schema_add_get_dlist_entry_with_class(list
, class)) {
589 /* this is a new class go on and add to the list */
590 entry
= talloc_zero(list
, struct schema_class_dlist
);
591 if (!entry
) return LDB_ERR_OPERATIONS_ERROR
;
592 entry
->class = class;
593 entry
->role
= class->type
;
595 /* If parent is top (list is guaranteed to start always with top) */
596 if (class->parent
== list
->class) {
597 /* if the hierarchy role is structural try to add it just after top */
598 if (role
== SCHEMA_CT_STRUCTURAL
) {
599 /* but check no other class at after top has a structural role */
600 if (list
->next
&& (list
->next
->role
== SCHEMA_CT_STRUCTURAL
)) {
601 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
603 DLIST_ADD_AFTER(list
, entry
, list
);
605 DLIST_ADD_END(list
, entry
, struct schema_class_dlist
*);
610 /* search if parent has already been added */
611 temp
= schema_add_get_dlist_entry_with_class(list
->next
, class->parent
);
613 ret
= schema_add_class_to_dlist(list
, class->parent
, role
);
614 if (ret
!= LDB_SUCCESS
) {
617 temp
= schema_add_get_dlist_entry_with_class(list
->next
, class->parent
);
619 if (!temp
) { /* parent not found !? */
620 return LDB_ERR_OPERATIONS_ERROR
;
623 DLIST_ADD_AFTER(list
, entry
, temp
);
624 if (role
== SCHEMA_CT_STRUCTURAL
|| role
== SCHEMA_CT_AUXILIARY
) {
629 /* stop when hierarchy base is met or when base class parent is top */
630 } while (temp
->class == temp
->next
->class->parent
&&
631 temp
->next
->class->parent
!= list
->class);
633 /* if we have not reached the head of the list
634 * and role is structural */
635 if (temp
!= list
&& role
== SCHEMA_CT_STRUCTURAL
) {
636 struct schema_class_dlist
*hfirst
, *hlast
;
638 /* check if the list second entry is structural */
639 if (list
->next
->role
== SCHEMA_CT_STRUCTURAL
) {
640 /* we have a confilict here */
641 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
643 /* we have to move this hierarchy of classes
644 * so that the base of the structural hierarchy is right after top */
648 /* now hfirst - hlast are the boundaries of the structural hierarchy */
650 /* extract the structural hierachy from the list */
651 hfirst
->prev
->next
= hlast
->next
;
652 if (hlast
->next
) hlast
->next
->prev
= hfirst
->prev
;
654 /* insert the structural hierarchy just after top */
655 list
->next
->prev
= hlast
;
656 hlast
->next
= list
->next
;
665 /* merge source list into dest list and remove duplicates */
666 static int schema_merge_class_list(TALLOC_CTX
*mem_ctx
, struct schema_class
***dest
, struct schema_class
**source
)
668 struct schema_class
**list
= *dest
;
672 if (list
) for (n
= 0; list
[n
]; n
++) /* noop */ ;
675 for (i
= 0; source
[i
]; i
++) {
676 for (j
= 0; j
< f
; j
++) {
677 if (list
[j
] == source
[i
]) {
681 if (j
< f
) { /* duplicate found */
685 list
= talloc_realloc(mem_ctx
, list
, struct schema_class
*, n
+ 2);
687 return LDB_ERR_OPERATIONS_ERROR
;
699 /* validate and modify the objectclass attribute to sort and add parents */
700 static int schema_add_build_objectclass_list(struct schema_context
*sctx
)
702 struct schema_class_dlist
*temp
;
703 struct ldb_message_element
* el
;
704 struct schema_class
*class;
707 /* First of all initialize list, it must start with class top */
708 sctx
->class_list
= talloc_zero(sctx
, struct schema_class_dlist
);
709 if (!sctx
->class_list
) return LDB_ERR_OPERATIONS_ERROR
;
711 sctx
->class_list
->class = schema_store_find(sctx
->data
->class_store
, "top");
712 if (!sctx
->class_list
->class) return LDB_ERR_OPERATIONS_ERROR
;
714 el
= ldb_msg_find_element(sctx
->orig_req
->op
.add
.message
, "objectClass");
716 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
719 for (i
= 0; i
< el
->num_values
; i
++) {
721 class = schema_store_find(sctx
->data
->class_store
, (char *)el
->values
[i
].data
);
723 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
726 ret
= schema_add_class_to_dlist(sctx
->class_list
, class, class->type
);
727 if (ret
!= LDB_SUCCESS
) {
732 /* now check if there is any class role that is still not STRUCTURAL or AUXILIARY */
733 /* build also the auxiliary class list and the possible superiors list */
734 temp
= sctx
->class_list
->next
; /* top is special, skip it */
738 if (temp
->role
== SCHEMA_CT_ABSTRACT
|| temp
->role
== SCHEMA_CT_88
) {
739 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
741 if (temp
->class->sysaux
) {
742 ret
= schema_merge_class_list(sctx
, &sctx
->aux_list
, temp
->class->sysaux
);
743 if (ret
!= LDB_SUCCESS
) {
744 return LDB_ERR_OPERATIONS_ERROR
;
747 if (temp
->class->aux
) {
748 ret
= schema_merge_class_list(sctx
, &sctx
->aux_list
, temp
->class->aux
);
749 if (ret
!= LDB_SUCCESS
) {
750 return LDB_ERR_OPERATIONS_ERROR
;
753 if (temp
->class->sysposssup
) {
754 ret
= schema_merge_class_list(sctx
, &sctx
->sup_list
, temp
->class->sysposssup
);
755 if (ret
!= LDB_SUCCESS
) {
756 return LDB_ERR_OPERATIONS_ERROR
;
759 if (temp
->class->posssup
) {
760 ret
= schema_merge_class_list(sctx
, &sctx
->sup_list
, temp
->class->posssup
);
761 if (ret
!= LDB_SUCCESS
) {
762 return LDB_ERR_OPERATIONS_ERROR
;
768 /* complete sup_list with material from the aux classes */
769 for (i
= 0; sctx
->aux_list
&& sctx
->aux_list
[i
]; i
++) {
770 if (sctx
->aux_list
[i
]->sysposssup
) {
771 ret
= schema_merge_class_list(sctx
, &sctx
->sup_list
, sctx
->aux_list
[i
]->sysposssup
);
772 if (ret
!= LDB_SUCCESS
) {
773 return LDB_ERR_OPERATIONS_ERROR
;
776 if (sctx
->aux_list
[i
]->posssup
) {
777 ret
= schema_merge_class_list(sctx
, &sctx
->sup_list
, sctx
->aux_list
[i
]->posssup
);
778 if (ret
!= LDB_SUCCESS
) {
779 return LDB_ERR_OPERATIONS_ERROR
;
784 if (!sctx
->sup_list
) return LDB_ERR_NAMING_VIOLATION
;
789 static int schema_add_check_container_constraints(struct schema_context
*sctx
)
791 struct schema_class
**parent_possinf
= NULL
;
792 struct schema_class
**parent_classes
;
793 struct schema_class_dlist
*temp
;
794 struct ldb_message_element
*el
;
797 el
= ldb_msg_find_element(sctx
->parent_res
->message
, "objectClass");
800 return LDB_ERR_OPERATIONS_ERROR
;
803 parent_classes
= talloc_array(sctx
, struct schema_class
*, el
->num_values
+ 1);
805 for (i
= 0; i
< el
->num_values
; i
++) {
807 parent_classes
[i
] = schema_store_find(sctx
->data
->class_store
, (const char *)el
->values
[i
].data
);
808 if (!parent_classes
[i
]) { /* should not be possible */
809 return LDB_ERR_OPERATIONS_ERROR
;
812 if (parent_classes
[i
]->possinf
) {
813 ret
= schema_merge_class_list(sctx
, &parent_possinf
, parent_classes
[i
]->possinf
);
814 if (ret
!= LDB_SUCCESS
) {
815 return LDB_ERR_OPERATIONS_ERROR
;
819 /* check also embedded auxiliary classes possinf */
820 for (j
= 0; parent_classes
[i
]->sysaux
&& parent_classes
[i
]->sysaux
[j
]; j
++) {
821 if (parent_classes
[i
]->sysaux
[j
]->possinf
) {
822 ret
= schema_merge_class_list(sctx
, &parent_possinf
, parent_classes
[i
]->sysaux
[j
]->possinf
);
823 if (ret
!= LDB_SUCCESS
) {
824 return LDB_ERR_OPERATIONS_ERROR
;
828 for (j
= 0; parent_classes
[i
]->aux
&& parent_classes
[i
]->aux
[j
]; j
++) {
829 if (parent_classes
[i
]->aux
[j
]->possinf
) {
830 ret
= schema_merge_class_list(sctx
, &parent_possinf
, parent_classes
[i
]->aux
[j
]->possinf
);
831 if (ret
!= LDB_SUCCESS
) {
832 return LDB_ERR_OPERATIONS_ERROR
;
838 /* foreach parent objectclass,
839 * check parent possible inferiors match all of the child objectclasses
841 * poss Superiors of the child objectclasses mathes one of the parent classes
844 temp
= sctx
->class_list
->next
; /* skip top it is special */
847 for (i
= 0; parent_possinf
[i
]; i
++) {
848 if (temp
->class == parent_possinf
[i
]) {
852 if (parent_possinf
[i
] == NULL
) {
853 /* class not found in possible inferiors */
854 return LDB_ERR_NAMING_VIOLATION
;
860 for (i
= 0; parent_classes
[i
]; i
++) {
861 for (j
= 0; sctx
->sup_list
[j
]; j
++) {
862 if (sctx
->sup_list
[j
] == parent_classes
[i
]) {
866 if (sctx
->sup_list
[j
]) { /* possible Superiors match one of the parent classes */
871 /* no parent classes matched superiors */
872 return LDB_ERR_NAMING_VIOLATION
;
875 static int schema_add_build_down_req(struct schema_context
*sctx
)
877 struct schema_class_dlist
*temp
;
878 struct ldb_message
*msg
;
881 sctx
->down_req
= talloc(sctx
, struct ldb_request
);
882 if (!sctx
->down_req
) {
883 ldb_set_errstring(sctx
->module
->ldb
, "Out of memory!");
884 return LDB_ERR_OPERATIONS_ERROR
;
887 *(sctx
->down_req
) = *(sctx
->orig_req
); /* copy the request */
888 msg
= ldb_msg_copy_shallow(sctx
->down_req
, sctx
->orig_req
->op
.add
.message
);
890 ldb_set_errstring(sctx
->module
->ldb
, "Out of memory!");
891 return LDB_ERR_OPERATIONS_ERROR
;
894 /* rebuild the objectclass list */
895 ldb_msg_remove_attr(msg
, "objectClass");
896 ret
= ldb_msg_add_empty(msg
, "objectClass", 0, NULL
);
897 if (ret
!= LDB_SUCCESS
) {
901 /* Add the complete list of classes back to the message */
902 for (temp
= sctx
->class_list
; temp
; temp
= temp
->next
) {
903 ret
= ldb_msg_add_string(msg
, "objectClass", temp
->class->name
);
904 if (ret
!= LDB_SUCCESS
) {
909 /* objectCategory can be set only by the system */
910 if (ldb_msg_find_element(msg
, "objectCategory")) {
911 return LDB_ERR_CONSTRAINT_VIOLATION
;
914 /* the OC is mandatory, every class defines it */
915 /* use the one defined in the structural class that defines the object */
916 for (temp
= sctx
->class_list
->next
; temp
; temp
= temp
->next
) {
917 if (!temp
->next
) break;
918 if (temp
->next
->role
!= SCHEMA_CT_STRUCTURAL
) break;
920 /* oc = talloc_strdup(msg, temp->class->defobjcat);
921 ret = ldb_msg_add_string(msg, "objectCategory", oc);
923 sctx
->down_req
->op
.add
.message
= msg
;
928 static int schema_check_attributes_syntax(struct schema_context
*sctx
)
930 struct ldb_message
*msg
;
931 struct schema_attribute
*attr
;
934 msg
= sctx
->orig_req
->op
.add
.message
;
935 for (i
= 0; i
< msg
->num_elements
; i
++) {
936 attr
= schema_store_find(sctx
->data
->attrs_store
, msg
->elements
[i
].name
);
938 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
940 ret
= schema_validate(sctx
->module
->ldb
, &msg
->elements
[i
], attr
->syntax
, attr
->single
, attr
->min
, attr
->max
);
941 if (ret
!= LDB_SUCCESS
) {
949 static int schema_add_continue(struct ldb_handle
*h
)
951 struct schema_context
*sctx
;
954 sctx
= talloc_get_type(h
->private_data
, struct schema_context
);
956 switch (sctx
->step
) {
959 /* First of all check that a parent exists for this entry */
960 ret
= schema_add_build_parent_req(sctx
);
961 if (ret
!= LDB_SUCCESS
) {
965 sctx
->step
= SC_ADD_CHECK_PARENT
;
966 return ldb_next_request(sctx
->module
, sctx
->parent_req
);
968 case SC_ADD_CHECK_PARENT
:
970 /* parent search done, check result and go on */
971 if (sctx
->parent_res
== NULL
) {
972 /* we must have a parent */
973 ret
= LDB_ERR_NO_SUCH_OBJECT
;
977 /* Check objectclasses are ok */
978 ret
= schema_add_build_objectclass_list(sctx
);
979 if (ret
!= LDB_SUCCESS
) {
983 /* check the parent is of the right type for this object */
984 ret
= schema_add_check_container_constraints(sctx
);
985 if (ret
!= LDB_SUCCESS
) {
989 /* check attributes syntax */
991 ret
= schema_check_attributes_syntax(sctx
);
992 if (ret
!= LDB_SUCCESS
) {
996 ret
= schema_add_build_down_req(sctx
);
997 if (ret
!= LDB_SUCCESS
) {
1000 sctx
->step
= SC_ADD_TEMP
;
1002 return ldb_next_request(sctx
->module
, sctx
->down_req
);
1005 ret
= LDB_ERR_OPERATIONS_ERROR
;
1009 /* this is reached only in case of error */
1010 /* FIXME: fire an async reply ? */
1012 h
->state
= LDB_ASYNC_DONE
;
1016 static int schema_add(struct ldb_module
*module
, struct ldb_request
*req
)
1018 struct schema_context
*sctx
;
1019 struct ldb_handle
*h
;
1021 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
1022 return ldb_next_request(module
, req
);
1025 h
= schema_init_handle(req
, module
, SC_ADD
);
1027 return LDB_ERR_OPERATIONS_ERROR
;
1030 sctx
= talloc_get_type(h
->private_data
, struct schema_context
);
1031 sctx
->orig_req
->handle
= h
;
1032 return schema_add_continue(h
);
1036 static int schema_modify(struct ldb_module
*module
, struct ldb_request
*req
)
1038 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
1039 return ldb_next_request(module
, req
);
1042 return ldb_next_request(module
, req
);
1045 static int schema_delete(struct ldb_module
*module
, struct ldb_request
*req
)
1047 if (ldb_dn_is_special(req
->op
.del
.dn
)) { /* do not manipulate our control entries */
1048 return ldb_next_request(module
, req
);
1051 /* First of all check no children exists for this entry */
1053 return ldb_next_request(module
, req
);
1056 static int schema_rename(struct ldb_module
*module
, struct ldb_request
*req
)
1058 if (ldb_dn_is_special(req
->op
.rename
.olddn
) &&
1059 ldb_dn_is_special(req
->op
.rename
.newdn
)) { /* do not manipulate our control entries */
1060 return ldb_next_request(module
, req
);
1063 return ldb_next_request(module
, req
);
1066 static int schema_wait_loop(struct ldb_handle
*handle
) {
1067 struct schema_context
*sctx
;
1070 if (!handle
|| !handle
->private_data
) {
1071 return LDB_ERR_OPERATIONS_ERROR
;
1074 if (handle
->state
== LDB_ASYNC_DONE
) {
1075 return handle
->status
;
1078 handle
->state
= LDB_ASYNC_PENDING
;
1079 handle
->status
= LDB_SUCCESS
;
1081 sctx
= talloc_get_type(handle
->private_data
, struct schema_context
);
1083 switch (sctx
->step
) {
1084 case SC_ADD_CHECK_PARENT
:
1085 ret
= ldb_wait(sctx
->parent_req
->handle
, LDB_WAIT_NONE
);
1087 if (ret
!= LDB_SUCCESS
) {
1088 handle
->status
= ret
;
1091 if (sctx
->parent_req
->handle
->status
!= LDB_SUCCESS
) {
1092 handle
->status
= sctx
->parent_req
->handle
->status
;
1096 if (sctx
->parent_req
->handle
->state
!= LDB_ASYNC_DONE
) {
1100 return schema_add_continue(handle
);
1103 ret
= ldb_wait(sctx
->down_req
->handle
, LDB_WAIT_NONE
);
1105 if (ret
!= LDB_SUCCESS
) {
1106 handle
->status
= ret
;
1109 if (sctx
->down_req
->handle
->status
!= LDB_SUCCESS
) {
1110 handle
->status
= sctx
->down_req
->handle
->status
;
1114 if (sctx
->down_req
->handle
->state
!= LDB_ASYNC_DONE
) {
1121 ret
= LDB_ERR_OPERATIONS_ERROR
;
1128 handle
->state
= LDB_ASYNC_DONE
;
1132 static int schema_wait_all(struct ldb_handle
*handle
) {
1136 while (handle
->state
!= LDB_ASYNC_DONE
) {
1137 ret
= schema_wait_loop(handle
);
1138 if (ret
!= LDB_SUCCESS
) {
1143 return handle
->status
;
1146 static int schema_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
1148 if (type
== LDB_WAIT_ALL
) {
1149 return schema_wait_all(handle
);
1151 return schema_wait_loop(handle
);
1155 static int schema_init(struct ldb_module
*module
)
1157 static const char *schema_attrs
[] = { "schemaNamingContext", NULL
};
1158 struct schema_private_data
*data
;
1159 struct ldb_result
*res
;
1162 /* need to let the partition module to register first */
1163 ret
= ldb_next_init(module
);
1164 if (ret
!= LDB_SUCCESS
) {
1168 data
= ldb_get_opaque(module
->ldb
, "schema_instance");
1170 module
->private_data
= data
;
1174 data
= talloc_zero(module
->ldb
, struct schema_private_data
);
1176 return LDB_ERR_OPERATIONS_ERROR
;
1179 /* find the schema partition */
1180 ret
= ldb_search(module
->ldb
,
1181 ldb_dn_new(module
, module
->ldb
, NULL
),
1187 if (res
->count
!= 1) {
1188 /* FIXME: return a clear error string */
1191 return LDB_ERR_OPERATIONS_ERROR
;
1194 data
->schema_dn
= ldb_msg_find_attr_as_dn(module
->ldb
, data
, res
->msgs
[0], "schemaNamingContext");
1195 if (data
->schema_dn
== NULL
) {
1196 /* FIXME: return a clear error string */
1199 return LDB_ERR_OPERATIONS_ERROR
;
1204 ret
= schema_init_attrs(module
, data
);
1205 if (ret
!= LDB_SUCCESS
) {
1210 ret
= schema_init_classes(module
, data
);
1211 if (ret
!= LDB_SUCCESS
) {
1216 module
->private_data
= data
;
1217 ldb_set_opaque(module
->ldb
, "schema_instance", data
);
1222 _PUBLIC_
const struct ldb_module_ops ldb_schema_module_ops
= {
1224 .init_context
= schema_init
,
1226 .modify
= schema_modify
,
1227 .del
= schema_delete
,
1228 .rename
= schema_rename
,