4 Copyright (C) Simo Sorce 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb schema module
30 * Description: add schema check functionality
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
39 struct attribute_syntax {
41 const char *syntax_id;
44 static struct attribute_syntax attrsyn[] = {
45 { "Object(DS-DN)", "2.5.5.1"},
46 { "String(Object-Identifier)", "2.5.5.2"},
48 { "String(Teletex)", "2.5.5.4"},
49 { "String(IA5)", "2.5.5.5"}, /* Also String(Printable) */
50 { "String(Numeric)", "2.5.5.6"},
51 { "Object(DN-Binary)", "2.5.5.7"}, /* Also Object(OR-Name) */
52 { "Boolean", "2.5.5.8"},
53 { "Integer", "2.5.5.9"}, /* Also Enumeration (3 types ?) ... */
54 { "String(Octet)", "2.5.5.10"}, /* Also Object(Replica-Link) */
55 { "String(UTC-Time)", "2.5.5.11"}, /* Also String(Generalized-Time) */
56 { "String(Unicode)", "2.5.5.12"},
57 { "Object(Presentation-Address)", "2.5.5.13"},
58 { "Object(DN-String)", "2.5.5.14"}, /* Also Object(Access-Point) */
59 { "String(NT-Sec-Desc))", "2.5.5.15"},
60 { "LargeInteger", "2.5.5.16"}, /* Also Interval ... */
61 { "String(Sid)", "2.5.5.17"}
64 #define SCHEMA_TALLOC_CHECK(root, mem, ret) do { if (!mem) { talloc_free(root); return ret;} } while(0);
66 #define SA_FLAG_RESET 0
67 #define SA_FLAG_AUXCLASS 1
68 #define SA_FLAG_CHECKED 2
71 struct ldb_context *schema_db;
72 const char *error_string;
76 static int schema_close(struct ldb_module *module)
78 return ldb_next_close(module);
82 static int schema_search(struct ldb_module *module, const char *base,
83 enum ldb_scope scope, const char *expression,
84 const char * const *attrs, struct ldb_message ***res)
86 return ldb_next_search(module, base, scope, expression, attrs, res);
90 static int schema_search_free(struct ldb_module *module, struct ldb_message **res)
92 return ldb_next_search_free(module, res);
95 struct attribute_list {
100 struct schema_structures {
101 struct attribute_list *check_list;
102 struct attribute_list *objectclass_list;
103 struct attribute_list *must;
104 struct attribute_list *may;
106 int objectclass_list_num;
111 static int get_object_objectclasses(struct ldb_context *ldb, const char *dn, struct schema_structures *schema_struct)
113 char *filter = talloc_asprintf(schema_struct, "dn=%s", dn);
114 const char *attrs[] = {"objectClass", NULL};
115 struct ldb_message **srch;
118 schema_struct->objectclass_list = NULL;
119 schema_struct->objectclass_list_num = 0;
120 ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, attrs, &srch);
122 for (i = 0; i < (*srch)->num_elements; i++) {
123 schema_struct->objectclass_list_num = (*srch)->elements[i].num_values;
124 schema_struct->objectclass_list = talloc_array(schema_struct,
125 struct attribute_list,
126 schema_struct->objectclass_list_num);
127 if (schema_struct->objectclass_list == 0) {
128 ldb_search_free(ldb, srch);
131 for (j = 0; j < schema_struct->objectclass_list_num; j++) {
132 schema_struct->objectclass_list[j].name = talloc_strndup(schema_struct->objectclass_list,
133 (*srch)->elements[i].values[j].data,
134 (*srch)->elements[i].values[j].length);
135 if (schema_struct->objectclass_list[j].name == 0) {
136 ldb_search_free(ldb, srch);
139 schema_struct->objectclass_list[j].flags = SA_FLAG_RESET;
142 ldb_search_free(ldb, srch);
144 ldb_search_free(ldb, srch);
151 static int get_check_list(struct ldb_module *module, struct schema_structures *schema_struct, const struct ldb_message *msg)
155 schema_struct->objectclass_list = NULL;
156 schema_struct->objectclass_list_num = 0;
157 schema_struct->check_list_num = msg->num_elements;
158 schema_struct->check_list = talloc_array(schema_struct,
159 struct attribute_list,
160 schema_struct->check_list_num);
161 if (schema_struct->check_list == 0) {
164 for (i = 0, j = 0; i < msg->num_elements; i++) {
165 if (strcasecmp(msg->elements[i].name, "objectclass") == 0) {
166 schema_struct->objectclass_list_num = msg->elements[i].num_values;
167 schema_struct->objectclass_list = talloc_array(schema_struct,
168 struct attribute_list,
169 schema_struct->objectclass_list_num);
170 if (schema_struct->objectclass_list == 0) {
173 for (k = 0; k < schema_struct->objectclass_list_num; k++) {
174 schema_struct->objectclass_list[k].name = talloc_strndup(schema_struct->objectclass_list,
175 msg->elements[i].values[k].data,
176 msg->elements[i].values[k].length);
177 if (schema_struct->objectclass_list[k].name == 0) {
180 schema_struct->objectclass_list[k].flags = SA_FLAG_RESET;
184 schema_struct->check_list[j].flags = SA_FLAG_RESET;
185 schema_struct->check_list[j].name = talloc_strdup(schema_struct->check_list,
186 msg->elements[i].name);
187 if (schema_struct->check_list[j].name == 0) {
196 static int add_attribute_uniq(struct attribute_list **list, int *list_num, int flags, struct ldb_message_element *el, void *mem_ctx)
200 vals = el->num_values;
201 *list = talloc_realloc(mem_ctx, *list, struct attribute_list, *list_num + vals);
205 for (i = 0, j = 0; i < vals; i++) {
209 for (c = 0; c < *list_num; c++) {
210 len = strlen((*list)[c].name);
211 if (len == el->values[i].length) {
212 if (strncasecmp((*list)[c].name, el->values[i].data, len) == 0) {
219 (*list)[j + *list_num].name = talloc_strndup(*list, el->values[i].data, el->values[i].length);
220 if ((*list)[j + *list_num].name == 0) {
223 (*list)[j + *list_num].flags = flags;
232 static int get_attr_list_recursive(struct ldb_module *module, struct ldb_context *ldb, struct schema_structures *schema_struct)
234 struct private_data *data = (struct private_data *)module->private_data;
235 struct ldb_message **srch;
239 schema_struct->must = NULL;
240 schema_struct->may = NULL;
241 schema_struct->must_num = 0;
242 schema_struct->may_num = 0;
243 for (i = 0; i < schema_struct->objectclass_list_num; i++) {
246 filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclass_list[i].name);
247 SCHEMA_TALLOC_CHECK(schema_struct, filter, -1);
248 ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
253 /* suppose auxiliary classeschema_struct are not required */
254 if (schema_struct->objectclass_list[i].flags & SA_FLAG_AUXCLASS) {
257 schema_struct->objectclass_list_num -= 1;
258 for (d = i; d < schema_struct->objectclass_list_num; d++) {
259 schema_struct->objectclass_list[d] = schema_struct->objectclass_list[d + 1];
264 /* Schema Violation: Object Class Description Not Found */
265 data->error_string = "ObjectClass not found";
271 /* Schema DB Error: Error occurred retrieving Object Class Description */
272 data->error_string = "Internal error. Error retrieving schema objectclass";
276 /* Schema DB Error: Too Many Records */
277 data->error_string = "Internal error. Too many records searching for schema objectclass";
282 /* Add inherited classes eliminating duplicates */
283 /* fill in kust and may attribute lists */
284 for (j = 0; j < (*srch)->num_elements; j++) {
285 int is_aux, is_class;
289 if (strcasecmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
290 is_aux = SA_FLAG_AUXCLASS;
293 if (strcasecmp((*srch)->elements[j].name, "subClassOf") == 0) {
298 if (add_attribute_uniq(&schema_struct->objectclass_list,
299 &schema_struct->objectclass_list_num,
301 &(*srch)->elements[j],
302 schema_struct) != 0) {
307 if (strcasecmp((*srch)->elements[j].name, "mustContain") == 0 ||
308 strcasecmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
309 if (add_attribute_uniq(&schema_struct->must,
310 &schema_struct->must_num,
312 &(*srch)->elements[j],
313 schema_struct) != 0) {
318 if (strcasecmp((*srch)->elements[j].name, "mayContain") == 0 ||
319 strcasecmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
321 if (add_attribute_uniq(&schema_struct->may,
322 &schema_struct->may_num,
324 &(*srch)->elements[j],
325 schema_struct) != 0) {
332 ldb_search_free(ldb, srch);
339 static int schema_add_record(struct ldb_module *module, const struct ldb_message *msg)
341 struct private_data *data = (struct private_data *)module->private_data;
342 struct schema_structures *entry_structs;
346 /* First implementation:
347 Build up a list of must and mays from each objectclass
348 Check all the musts are there and all the other attributes are mays
349 Throw an error in case a check fail
350 Free all structures and commit the change
353 entry_structs = talloc(module, struct schema_structures);
354 if (!entry_structs) {
358 ret = get_check_list(module, entry_structs, msg);
360 talloc_free(entry_structs);
364 /* find all other objectclasses recursively */
365 ret = get_attr_list_recursive(module, data->schema_db, entry_structs);
367 talloc_free(entry_structs);
371 /* now check all musts are present */
372 for (i = 0; i < entry_structs->must_num; i++) {
376 for (j = 0; j < entry_structs->check_list_num; j++) {
377 if (strcasecmp(entry_structs->must[i].name, entry_structs->check_list[j].name) == 0) {
378 entry_structs->check_list[j].flags = SA_FLAG_CHECKED;
385 /* TODO: set the error string */
386 data->error_string = "Objectclass violation, a required attribute is mischema_structing";
387 talloc_free(entry_structs);
392 /* now check all others atribs are found in mays */
393 for (i = 0; i < entry_structs->check_list_num; i++) {
395 if (entry_structs->check_list[i].flags != SA_FLAG_CHECKED) {
399 for (j = 0; j < entry_structs->may_num; j++) {
400 if (strcasecmp(entry_structs->may[j].name, entry_structs->check_list[i].name) == 0) {
401 entry_structs->check_list[i].flags = SA_FLAG_CHECKED;
408 data->error_string = "Objectclass violation, an invalid attribute name was found";
409 talloc_free(entry_structs);
415 talloc_free(entry_structs);
417 return ldb_next_add_record(module, msg);
421 static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
423 struct private_data *data = (struct private_data *)module->private_data;
424 struct schema_structures *entry_structs, *modify_structs;
428 /* First implementation:
429 Retrieve the ldap entry and get the objectclasses,
430 add msg contained objectclasses if any.
431 Build up a list of must and mays from each objectclass
432 Check all musts for the defined objectclass and it's specific
433 inheritance are there.
434 Check all other the attributes are mays or musts.
435 Throw an error in case a check fail.
436 Free all structures and commit the change.
439 /* allocate object structs */
440 entry_structs = talloc(module, struct schema_structures);
441 if (!entry_structs) {
445 /* allocate modification entry structs */
446 modify_structs = talloc(entry_structs, struct schema_structures);
447 if (!modify_structs) {
448 talloc_free(entry_structs);
452 /* get list of values to modify */
453 ret = get_check_list(module, modify_structs, msg);
455 talloc_free(entry_structs);
459 /* find all modify objectclasses recursively if any objectclass is being added */
460 ret = get_attr_list_recursive(module, data->schema_db, modify_structs);
462 talloc_free(entry_structs);
466 /* now search for the original object objectclasses */
467 ret = get_object_objectclasses(module->ldb, msg->dn, entry_structs);
469 talloc_free(entry_structs);
473 /* find all other objectclasses recursively */
474 ret = get_attr_list_recursive(module, data->schema_db, entry_structs);
476 talloc_free(entry_structs);
480 /* now check all entries are present either as musts or mays of curent objectclasses */
481 /* do not return errors there may be attirbutes defined in new objectclasses */
482 /* just mark them as being proved valid attribs */
483 for (i = 0; i < modify_structs->check_list_num; i++) {
487 for (j = 0; j < entry_structs->may_num; j++) {
488 if (strcasecmp(entry_structs->may[j].name, modify_structs->check_list[i].name) == 0) {
489 modify_structs->check_list[i].flags = SA_FLAG_CHECKED;
495 for (j = 0; j < entry_structs->must_num; j++) {
496 if (strcasecmp(entry_structs->must[j].name, modify_structs->check_list[i].name) == 0) {
497 modify_structs->check_list[i].flags = SA_FLAG_CHECKED;
504 /* now check all new objectclasses musts are present */
505 for (i = 0; i < modify_structs->must_num; i++) {
509 for (j = 0; j < modify_structs->check_list_num; j++) {
510 if (strcasecmp(modify_structs->must[i].name, modify_structs->check_list[j].name) == 0) {
511 modify_structs->check_list[j].flags = SA_FLAG_CHECKED;
518 /* TODO: set the error string */
519 data->error_string = "Objectclass violation, a required attribute is missing";
520 talloc_free(entry_structs);
525 /* now check all others atribs are found in mays */
526 for (i = 0; i < modify_structs->check_list_num; i++) {
528 if (modify_structs->check_list[i].flags != SA_FLAG_CHECKED) {
532 for (j = 0; j < modify_structs->may_num; j++) {
533 if (strcasecmp(modify_structs->may[j].name, modify_structs->check_list[i].name) == 0) {
534 modify_structs->check_list[i].flags = SA_FLAG_CHECKED;
541 data->error_string = "Objectclass violation, an invalid attribute name was found";
542 talloc_free(entry_structs);
548 talloc_free(entry_structs);
550 return ldb_next_modify_record(module, msg);
554 static int schema_delete_record(struct ldb_module *module, const char *dn)
556 /* struct private_data *data = (struct private_data *)module->private_data; */
557 return ldb_next_delete_record(module, dn);
561 static int schema_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
563 return ldb_next_rename_record(module, olddn, newdn);
566 static int schema_named_lock(struct ldb_module *module, const char *name) {
567 return ldb_next_named_lock(module, name);
570 static int schema_named_unlock(struct ldb_module *module, const char *name) {
571 return ldb_next_named_unlock(module, name);
574 /* return extended error information */
575 static const char *schema_errstring(struct ldb_module *module)
577 struct private_data *data = (struct private_data *)module->private_data;
579 if (data->error_string) {
582 error = data->error_string;
583 data->error_string = NULL;
587 return ldb_next_errstring(module);
590 static const struct ldb_module_ops schema_ops = {
596 schema_modify_record,
597 schema_delete_record,
598 schema_rename_record,
604 #define SCHEMA_PREFIX "schema:"
605 #define SCHEMA_PREFIX_LEN 7
607 #ifdef HAVE_DLOPEN_DISABLED
608 struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
610 struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
613 struct ldb_module *ctx;
614 struct private_data *data;
618 ctx = talloc(ldb, struct ldb_module);
624 for (i = 0; options[i] != NULL; i++) {
625 if (strncmp(options[i], SCHEMA_PREFIX, SCHEMA_PREFIX_LEN) == 0) {
626 db_url = talloc_strdup(ctx, &options[i][SCHEMA_PREFIX_LEN]);
627 SCHEMA_TALLOC_CHECK(ctx, db_url, NULL);
632 if (!db_url) { /* search if it is defined in the calling ldb */
634 const char * attrs[] = { "@SCHEMADB", NULL };
635 struct ldb_message **msgs;
637 ret = ldb_search(ldb, "", LDB_SCOPE_BASE, "dn=@MODULES", (const char * const *)attrs, &msgs);
639 ldb_debug(ldb, LDB_DEBUG_TRACE, "Schema DB not found\n");
640 ldb_search_free(ldb, msgs);
644 ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for schema db, bailing out!\n", ldb_errstring(ldb));
645 ldb_search_free(ldb, msgs);
649 ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found, bailing out\n");
650 ldb_search_free(ldb, msgs);
654 db_url = talloc_strndup(ctx, msgs[0]->elements[0].values[0].data, msgs[0]->elements[0].values[0].length);
655 SCHEMA_TALLOC_CHECK(ctx, db_url, NULL);
658 ldb_search_free(ldb, msgs);
661 data = talloc(ctx, struct private_data);
662 SCHEMA_TALLOC_CHECK(ctx, data, NULL);
664 data->schema_db = ldb_connect(db_url, 0, NULL);
665 SCHEMA_TALLOC_CHECK(ctx, data->schema_db, NULL);
667 data->error_string = NULL;
668 ctx->private_data = data;
670 ctx->prev = ctx->next = NULL;
671 ctx->ops = &schema_ops;