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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Component: ldb schema module
26 * Description: add schema check functionality
30 * License: GNU GPL v2 or Later
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"
41 see ldap_server/devdocs/AD-syntaxes.txt
44 enum schema_int_attr_id
{
47 SCHEMA_AS_OCTET_STRING
,
50 SCHEMA_AS_ENUMERATION
,
51 SCHEMA_AS_NUMERIC_STRING
,
52 SCHEMA_AS_PRINTABLE_STRING
,
53 SCHEMA_AS_CASE_IGNORE_STRING
,
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
,
64 SCHEMA_AS_REPLICA_LINK
,
65 SCHEMA_AS_PRESENTATION_ADDRESS
,
66 SCHEMA_AS_ACCESS_POINT
,
70 enum schema_class_type
{
72 SCHEMA_CT_STRUCTURAL
= 1,
73 SCHEMA_CT_ABSTRACT
= 2,
74 SCHEMA_CT_AUXILIARY
= 3
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 */
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 */
103 /* TODO: ditcontentrules */
105 struct schema_private_data
{
106 struct ldb_dn
*schema_dn
;
107 struct schema_attribute
**attrs
;
108 struct schema_store
*attrs_store
;
110 struct schema_class
**class;
111 struct schema_store
*class_store
;
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
;
122 struct schema_context
{
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
;
127 struct schema_private_data
*data
;
129 struct ldb_module
*module
;
130 struct ldb_request
*orig_req
;
131 struct ldb_request
*down_req
;
133 struct ldb_request
*parent_req
;
134 struct ldb_reply
*parent_res
;
136 struct schema_class_dlist
*class_list
;
137 struct schema_class
**sup_list
;
138 struct schema_class
**aux_list
;
141 /* FIXME: I'd really like to use an hash table here */
147 struct schema_store
{
148 struct schema_link
*store
;
152 static struct schema_store
*schema_store_new(TALLOC_CTX
*mem_ctx
)
154 struct schema_store
*ht
;
156 ht
= talloc(mem_ctx
, struct schema_store
);
157 if (!ht
) return NULL
;
165 static int schema_store_add(struct schema_store
*ht
, const char *key
, void *object
)
167 ht
->store
= talloc_realloc(ht
, ht
->store
, struct schema_link
, ht
->num_links
+ 1);
168 if (!ht
->store
) return LDB_ERR_OPERATIONS_ERROR
;
170 ht
->store
[ht
->num_links
].name
= key
;
171 ht
->store
[ht
->num_links
].object
= object
;
178 static void *schema_store_find(struct schema_store
*ht
, const char *key
)
182 for (i
= 0; i
< ht
->num_links
; i
++) {
183 if (strcasecmp(ht
->store
[i
].name
, key
) == 0) {
184 return ht
->store
[i
].object
;
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)
198 struct schema_class
**schema_get_class_list(struct ldb_module
*module
,
199 struct schema_private_data
*data
,
200 struct ldb_message_element
*el
)
202 struct schema_class
**list
;
205 list
= talloc_array(data
, struct schema_class
*, el
->num_values
+ 1);
207 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory");
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
);
215 ldb_debug_set(module
->ldb
,
217 "Class %s referenced but not found in schema\n",
218 (char *)el
->values
[i
].data
);
227 struct schema_attribute
**schema_get_attrs_list(struct ldb_module
*module
,
228 struct schema_private_data
*data
,
229 struct ldb_message_element
*el
)
231 struct schema_attribute
**list
;
234 list
= talloc_array(data
, struct schema_attribute
*, el
->num_values
+ 1);
236 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Out of Memory");
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
);
244 ldb_debug_set(module
->ldb
,
246 "Attriobute %s referenced but not found in schema\n",
247 (char *)el
->values
[i
].data
);
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
)
264 *syntax
= SCHEMA_AS_BOOLEAN
;
267 *syntax
= SCHEMA_AS_INTEGER
;
270 if (strcmp(attr_syntax
, "2.5.5.10") == 0) {
271 *syntax
= SCHEMA_AS_OCTET_STRING
;
274 if (strcmp(attr_syntax
, "2.5.5.17") == 0) {
275 *syntax
= SCHEMA_AS_SID
;
278 ret
= LDB_ERR_OPERATIONS_ERROR
;
281 *syntax
= SCHEMA_AS_OID
;
284 *syntax
= SCHEMA_AS_ENUMERATION
;
287 *syntax
= SCHEMA_AS_NUMERIC_STRING
;
290 *syntax
= SCHEMA_AS_PRINTABLE_STRING
;
293 *syntax
= SCHEMA_AS_CASE_IGNORE_STRING
;
296 *syntax
= SCHEMA_AS_IA5_STRING
;
299 *syntax
= SCHEMA_AS_UTC_TIME
;
302 *syntax
= SCHEMA_AS_GENERALIZED_TIME
;
305 *syntax
= SCHEMA_AS_CASE_SENSITIVE_STRING
;
308 *syntax
= SCHEMA_AS_DIRECTORY_STRING
;
311 *syntax
= SCHEMA_AS_LARGE_INTEGER
;
314 *syntax
= SCHEMA_AS_OBJECT_SECURITY_DESCRIPTOR
;
318 ret
= LDB_ERR_OPERATIONS_ERROR
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
350 /* not found will error in default: */
352 ret
= LDB_ERR_OPERATIONS_ERROR
;
358 static int schema_init_attrs(struct ldb_module
*module
, struct schema_private_data
*data
)
360 static const char *schema_attrs
[] = { "attributeID",
369 struct ldb_result
*res
;
372 ret
= ldb_search(module
->ldb
,
375 "(objectClass=attributeSchema)",
379 if (ret
!= LDB_SUCCESS
) {
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
);
387 data
->attrs_store
= schema_store_new(data
);
388 SCHEMA_CHECK_VALUE(data
->attrs_store
, NULL
, module
);
390 for (i
= 0; i
< res
->count
; i
++) {
391 const char *tmp_single
;
392 const char *attr_syntax
;
394 const struct ldb_val
*om_class
;
396 data
->attrs
[i
] = talloc(data
->attrs
, struct schema_attribute
);
397 SCHEMA_CHECK_VALUE(data
->attrs
[i
], NULL
, module
);
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
);
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
);
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
]);
411 attr_syntax
= ldb_msg_find_attr_as_string(res
->msgs
[i
], "attributeSyntax", NULL
);
412 SCHEMA_CHECK_VALUE(attr_syntax
, NULL
, module
);
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
);
418 om_class
= ldb_msg_find_ldb_val(res
->msgs
[i
], "oMObjectClass");
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
);
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;
433 data
->attrs
[i
]->single
= 0;
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);
446 static int schema_init_classes(struct ldb_module
*module
, struct schema_private_data
*data
)
448 static const char *schema_attrs
[] = { "governsID",
450 "objectClassCategory",
453 "systemAuxiliaryClass",
455 "systemPossSuperiors",
463 struct ldb_result
*res
;
466 ret
= ldb_search(module
->ldb
,
469 "(objectClass=classSchema)",
473 if (ret
!= LDB_SUCCESS
) {
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
);
481 data
->class_store
= schema_store_new(data
);
482 SCHEMA_CHECK_VALUE(data
->class_store
, NULL
, module
);
484 for (i
= 0; i
< res
->count
; i
++) {
485 struct ldb_message_element
*el
;
487 data
->class[i
] = talloc(data
->class, struct schema_class
);
488 SCHEMA_CHECK_VALUE(data
->class[i
], NULL
, module
);
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
);
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
);
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
]);
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
);
506 /* the following attributes are all optional */
508 data
->class[i
]->systemOnly
= ldb_msg_find_attr_as_bool(res
->msgs
[i
], "systemOnly", False
);
510 /* attributes are loaded first, so we can just go an query the attributes repo */
512 el
= ldb_msg_find_element(res
->msgs
[i
], "systemMustContain");
514 data
->class[i
]->sysmust
= schema_get_attrs_list(module
, data
, el
);
515 SCHEMA_CHECK_VALUE(data
->class[i
]->sysmust
, NULL
, module
);
518 el
= ldb_msg_find_element(res
->msgs
[i
], "MustContain");
520 data
->class[i
]->must
= schema_get_attrs_list(module
, data
, el
);
521 SCHEMA_CHECK_VALUE(data
->class[i
]->must
, NULL
, module
);
524 el
= ldb_msg_find_element(res
->msgs
[i
], "systemMayContain");
526 data
->class[i
]->sysmay
= schema_get_attrs_list(module
, data
, el
);
527 SCHEMA_CHECK_VALUE(data
->class[i
]->sysmay
, NULL
, module
);
530 el
= ldb_msg_find_element(res
->msgs
[i
], "MayContain");
532 data
->class[i
]->may
= schema_get_attrs_list(module
, data
, el
);
533 SCHEMA_CHECK_VALUE(data
->class[i
]->may
, NULL
, module
);
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
;
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
);
551 /* the following attributes are all optional */
553 data
->class[i
]->sysaux
= NULL
;
554 el
= ldb_msg_find_element(res
->msgs
[i
], "systemAuxiliaryClass");
556 data
->class[i
]->sysaux
= schema_get_class_list(module
, data
, el
);
557 SCHEMA_CHECK_VALUE(data
->class[i
]->sysaux
, NULL
, module
);
560 data
->class[i
]->aux
= NULL
;
561 el
= ldb_msg_find_element(res
->msgs
[i
], "auxiliaryClass");
563 data
->class[i
]->aux
= schema_get_class_list(module
, data
, el
);
564 SCHEMA_CHECK_VALUE(data
->class[i
]->aux
, NULL
, module
);
567 data
->class[i
]->sysposssup
= NULL
;
568 el
= ldb_msg_find_element(res
->msgs
[i
], "systemPossSuperiors");
570 data
->class[i
]->sysposssup
= schema_get_class_list(module
, data
, el
);
571 SCHEMA_CHECK_VALUE(data
->class[i
]->sysposssup
, NULL
, module
);
574 data
->class[i
]->posssup
= NULL
;
575 el
= ldb_msg_find_element(res
->msgs
[i
], "possSuperiors");
577 data
->class[i
]->posssup
= schema_get_class_list(module
, data
, el
);
578 SCHEMA_CHECK_VALUE(data
->class[i
]->posssup
, NULL
, module
);
581 data
->class[i
]->possinf
= NULL
;
582 el
= ldb_msg_find_element(res
->msgs
[i
], "possibleInferiors");
584 data
->class[i
]->possinf
= schema_get_class_list(module
, data
, el
);
585 SCHEMA_CHECK_VALUE(data
->class[i
]->possinf
, NULL
, module
);
594 static struct ldb_handle
*schema_init_handle(struct ldb_request
*req
, struct ldb_module
*module
, enum sc_op op
)
596 struct schema_context
*sctx
;
597 struct ldb_handle
*h
;
599 h
= talloc_zero(req
, struct ldb_handle
);
601 ldb_set_errstring(module
->ldb
, "Out of Memory");
607 sctx
= talloc_zero(h
, struct schema_context
);
609 ldb_set_errstring(module
->ldb
, "Out of Memory");
614 h
->private_data
= (void *)sctx
;
616 h
->state
= LDB_ASYNC_INIT
;
617 h
->status
= LDB_SUCCESS
;
620 sctx
->step
= SC_INIT
;
621 sctx
->data
= module
->private_data
;
622 sctx
->module
= module
;
623 sctx
->orig_req
= req
;
628 static int schema_add_check_parent(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
630 struct schema_context
*sctx
;
632 if (!context
|| !ares
) {
633 ldb_set_errstring(ldb
, "NULL Context or Result in callback");
634 return LDB_ERR_OPERATIONS_ERROR
;
637 sctx
= talloc_get_type(context
, struct schema_context
);
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");
644 return LDB_ERR_OPERATIONS_ERROR
;
646 sctx
->parent_res
= talloc_steal(sctx
, ares
);
654 static int schema_add_build_parent_req(struct schema_context
*sctx
)
656 static const char * const parent_attrs
[] = { "objectClass", NULL
};
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
;
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
);
678 static struct schema_class_dlist
*schema_add_get_dlist_entry_with_class(struct schema_class_dlist
*list
, struct schema_class
*class)
680 struct schema_class_dlist
*temp
;
682 for (temp
= list
; temp
&& (temp
->class != class); temp
= temp
->next
) /* noop */ ;
686 static int schema_add_class_to_dlist(struct schema_class_dlist
*list
, struct schema_class
*class, enum schema_class_type role
)
688 struct schema_class_dlist
*entry
;
689 struct schema_class_dlist
*temp
;
692 /* see if this class already exist in the class list */
693 if (schema_add_get_dlist_entry_with_class(list
, class)) {
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
;
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
;
711 DLIST_ADD_AFTER(list
, entry
, list
);
713 DLIST_ADD_END(list
, entry
, struct schema_class_dlist
*);
718 /* search if parent has already been added */
719 temp
= schema_add_get_dlist_entry_with_class(list
->next
, class->parent
);
721 ret
= schema_add_class_to_dlist(list
, class->parent
, role
);
722 if (ret
!= LDB_SUCCESS
) {
725 temp
= schema_add_get_dlist_entry_with_class(list
->next
, class->parent
);
727 if (!temp
) { /* parent not found !? */
728 return LDB_ERR_OPERATIONS_ERROR
;
731 DLIST_ADD_AFTER(list
, entry
, temp
);
732 if (role
== SCHEMA_CT_STRUCTURAL
|| role
== SCHEMA_CT_AUXILIARY
) {
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);
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
;
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
;
751 /* we have to move this hierarchy of classes
752 * so that the base of the structural hierarchy is right after top */
756 /* now hfirst - hlast are the boundaries of the structural hierarchy */
758 /* extract the structural hierachy from the list */
759 hfirst
->prev
->next
= hlast
->next
;
760 if (hlast
->next
) hlast
->next
->prev
= hfirst
->prev
;
762 /* insert the structural hierarchy just after top */
763 list
->next
->prev
= hlast
;
764 hlast
->next
= list
->next
;
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
)
776 struct schema_class
**list
= *dest
;
780 if (list
) for (n
= 0; list
[n
]; n
++) /* noop */ ;
783 for (i
= 0; source
[i
]; i
++) {
784 for (j
= 0; j
< f
; j
++) {
785 if (list
[j
] == source
[i
]) {
789 if (j
< f
) { /* duplicate found */
793 list
= talloc_realloc(mem_ctx
, list
, struct schema_class
*, n
+ 2);
795 return LDB_ERR_OPERATIONS_ERROR
;
807 /* validate and modify the objectclass attribute to sort and add parents */
808 static int schema_add_build_objectclass_list(struct schema_context
*sctx
)
810 struct schema_class_dlist
*temp
;
811 struct ldb_message_element
* el
;
812 struct schema_class
*class;
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
;
819 sctx
->class_list
->class = schema_store_find(sctx
->data
->class_store
, "top");
820 if (!sctx
->class_list
->class) return LDB_ERR_OPERATIONS_ERROR
;
822 el
= ldb_msg_find_element(sctx
->orig_req
->op
.add
.message
, "objectClass");
824 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
827 for (i
= 0; i
< el
->num_values
; i
++) {
829 class = schema_store_find(sctx
->data
->class_store
, (char *)el
->values
[i
].data
);
831 return LDB_ERR_NO_SUCH_OBJECT
;
834 ret
= schema_add_class_to_dlist(sctx
->class_list
, class, class->type
);
835 if (ret
!= LDB_SUCCESS
) {
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 */
846 if (temp
->role
== SCHEMA_CT_ABSTRACT
|| temp
->role
== SCHEMA_CT_88
) {
847 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
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
;
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
;
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
;
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
;
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
;
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
;
892 if (!sctx
->sup_list
) return LDB_ERR_NAMING_VIOLATION
;
897 static int schema_add_check_container_constraints(struct schema_context
*sctx
)
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
;
905 el
= ldb_msg_find_element(sctx
->parent_res
->message
, "objectClass");
908 return LDB_ERR_OPERATIONS_ERROR
;
911 parent_classes
= talloc_array(sctx
, struct schema_class
*, el
->num_values
+ 1);
913 for (i
= 0; i
< el
->num_values
; i
++) {
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
;
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
;
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
;
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
;
946 /* foreach parent objectclass,
947 * check parent possible inferiors match all of the child objectclasses
949 * poss Superiors of the child objectclasses mathes one of the parent classes
952 temp
= sctx
->class_list
->next
; /* skip top it is special */
955 for (i
= 0; parent_possinf
[i
]; i
++) {
956 if (temp
->class == parent_possinf
[i
]) {
960 if (parent_possinf
[i
] == NULL
) {
961 /* class not found in possible inferiors */
962 return LDB_ERR_NAMING_VIOLATION
;
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
]) {
974 if (sctx
->sup_list
[j
]) { /* possible Superiors match one of the parent classes */
979 /* no parent classes matched superiors */
980 return LDB_ERR_NAMING_VIOLATION
;
983 static int schema_add_build_down_req(struct schema_context
*sctx
)
985 struct schema_class_dlist
*temp
;
986 struct ldb_message
*msg
;
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
;
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
);
998 ldb_set_errstring(sctx
->module
->ldb
, "Out of memory!");
999 return LDB_ERR_OPERATIONS_ERROR
;
1002 ldb_msg_remove_attr(msg
, "objectClass");
1003 ret
= ldb_msg_add_empty(msg
, "objectClass", 0);
1004 if (ret
!= LDB_SUCCESS
) {
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
) {
1016 sctx
->down_req
->op
.add
.message
= msg
;
1021 static int schema_add_continue(struct ldb_handle
*h
)
1023 struct schema_context
*sctx
;
1026 sctx
= talloc_get_type(h
->private_data
, struct schema_context
);
1028 switch (sctx
->step
) {
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
) {
1037 sctx
->step
= SC_ADD_CHECK_PARENT
;
1038 return ldb_next_request(sctx
->module
, sctx
->parent_req
);
1040 case SC_ADD_CHECK_PARENT
:
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
;
1049 /* Check objectclasses are ok */
1050 ret
= schema_add_build_objectclass_list(sctx
);
1051 if (ret
!= LDB_SUCCESS
) {
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
) {
1061 /* check attributes syntax */
1063 ret = schema_check_attributes_syntax(sctx);
1064 if (ret != LDB_SUCCESS) {
1069 ret
= schema_add_build_down_req(sctx
);
1070 if (ret
!= LDB_SUCCESS
) {
1073 sctx
->step
= SC_ADD_TEMP
;
1075 return ldb_next_request(sctx
->module
, sctx
->down_req
);
1078 ret
= LDB_ERR_OPERATIONS_ERROR
;
1082 /* this is reached only in case of error */
1083 /* FIXME: fire an async reply ? */
1085 h
->state
= LDB_ASYNC_DONE
;
1089 static int schema_add(struct ldb_module
*module
, struct ldb_request
*req
)
1091 struct schema_context
*sctx
;
1092 struct ldb_handle
*h
;
1094 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
1095 return ldb_next_request(module
, req
);
1098 h
= schema_init_handle(req
, module
, SC_ADD
);
1100 return LDB_ERR_OPERATIONS_ERROR
;
1103 sctx
= talloc_get_type(h
->private_data
, struct schema_context
);
1104 sctx
->orig_req
->handle
= h
;
1105 return schema_add_continue(h
);
1109 static int schema_modify(struct ldb_module
*module
, struct ldb_request
*req
)
1111 struct ldb_handle
*h
;
1112 struct schema_context
*sctx
;
1114 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
1115 return ldb_next_request(module
, req
);
1118 return ldb_next_request(module
, req
);
1121 static int schema_delete(struct ldb_module
*module
, struct ldb_request
*req
)
1123 struct ldb_handle
*h
;
1124 struct schema_context
*sctx
;
1126 if (ldb_dn_is_special(req
->op
.del
.dn
)) { /* do not manipulate our control entries */
1127 return ldb_next_request(module
, req
);
1130 /* First of all check no children exists for this entry */
1132 return ldb_next_request(module
, req
);
1135 static int schema_rename(struct ldb_module
*module
, struct ldb_request
*req
)
1137 struct ldb_handle
*h
;
1138 struct schema_context
*sctx
;
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
);
1145 return ldb_next_request(module
, req
);
1148 static int schema_wait_loop(struct ldb_handle
*handle
) {
1149 struct schema_context
*sctx
;
1152 if (!handle
|| !handle
->private_data
) {
1153 return LDB_ERR_OPERATIONS_ERROR
;
1156 if (handle
->state
== LDB_ASYNC_DONE
) {
1157 return handle
->status
;
1160 handle
->state
= LDB_ASYNC_PENDING
;
1161 handle
->status
= LDB_SUCCESS
;
1163 sctx
= talloc_get_type(handle
->private_data
, struct schema_context
);
1165 switch (sctx
->step
) {
1166 case SC_ADD_CHECK_PARENT
:
1167 ret
= ldb_wait(sctx
->parent_req
->handle
, LDB_WAIT_NONE
);
1169 if (ret
!= LDB_SUCCESS
) {
1170 handle
->status
= ret
;
1173 if (sctx
->parent_req
->handle
->status
!= LDB_SUCCESS
) {
1174 handle
->status
= sctx
->parent_req
->handle
->status
;
1178 if (sctx
->parent_req
->handle
->state
!= LDB_ASYNC_DONE
) {
1182 return schema_add_continue(handle
);
1185 ret
= ldb_wait(sctx
->down_req
->handle
, LDB_WAIT_NONE
);
1187 if (ret
!= LDB_SUCCESS
) {
1188 handle
->status
= ret
;
1191 if (sctx
->down_req
->handle
->status
!= LDB_SUCCESS
) {
1192 handle
->status
= sctx
->down_req
->handle
->status
;
1196 if (sctx
->down_req
->handle
->state
!= LDB_ASYNC_DONE
) {
1203 ret
= LDB_ERR_OPERATIONS_ERROR
;
1210 handle
->state
= LDB_ASYNC_DONE
;
1214 static int schema_wait_all(struct ldb_handle
*handle
) {
1218 while (handle
->state
!= LDB_ASYNC_DONE
) {
1219 ret
= schema_wait_loop(handle
);
1220 if (ret
!= LDB_SUCCESS
) {
1225 return handle
->status
;
1228 static int schema_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
1230 if (type
== LDB_WAIT_ALL
) {
1231 return schema_wait_all(handle
);
1233 return schema_wait_loop(handle
);
1237 static int schema_init(struct ldb_module
*module
)
1239 static const char *schema_attrs
[] = { "schemaNamingContext", NULL
};
1240 struct schema_private_data
*data
;
1241 struct ldb_result
*res
;
1244 /* need to let the partiorion module to register first */
1245 ret
= ldb_next_init(module
);
1246 if (ret
!= LDB_SUCCESS
) {
1250 data
= talloc_zero(module
, struct schema_private_data
);
1252 return LDB_ERR_OPERATIONS_ERROR
;
1255 /* find the schema partition */
1256 ret
= ldb_search(module
->ldb
,
1263 if (res
->count
!= 1) {
1264 /* FIXME: return a clear error string */
1267 return LDB_ERR_OPERATIONS_ERROR
;
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 */
1275 return LDB_ERR_OPERATIONS_ERROR
;
1280 ret
= schema_init_attrs(module
, data
);
1281 if (ret
!= LDB_SUCCESS
) {
1286 ret
= schema_init_classes(module
, data
);
1287 if (ret
!= LDB_SUCCESS
) {
1292 module
->private_data
= data
;
1296 static const struct ldb_module_ops schema_ops
= {
1298 .init_context
= schema_init
,
1300 .modify
= schema_modify
,
1301 .del
= schema_delete
,
1302 .rename
= schema_rename
,
1306 int ldb_schema_init(void)
1308 return ldb_register_module(&schema_ops
);