r6470: Remove ldb_search_free() it is not needed anymore.
[ira/wip.git] / source / lib / ldb / modules / schema.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
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.
14
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.
19
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
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb schema module
29  *
30  *  Description: add schema check functionality
31  *
32  *  Author: Simo Sorce
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38
39 #define SCHEMA_FLAG_RESET       0
40 #define SCHEMA_FLAG_MOD_MASK    0x003
41 #define SCHEMA_FLAG_MOD_ADD     0x001
42 #define SCHEMA_FLAG_MOD_REPLACE 0x002
43 #define SCHEMA_FLAG_MOD_DELETE  0x003
44 #define SCHEMA_FLAG_AUXILIARY   0x010
45 #define SCHEMA_FLAG_ABSTRACT    0x020
46 #define SCHEMA_FLAG_STRUCTURAL  0x040
47 #define SCHEMA_FLAG_CHECKED     0x100
48
49
50 /* TODO: check attributes syntaxes
51          check there's only one structrual class (or a chain of structural classes)
52 */
53
54 struct private_data {
55         const char *error_string;
56 };
57
58 struct schema_attribute {
59         int flags;
60         char *name;
61 };
62
63 struct schema_attribute_list {
64         struct schema_attribute *attr;
65         int num;
66 };
67
68 struct schema_structures {
69         struct schema_attribute_list entry_attrs;
70         struct schema_attribute_list objectclasses;
71         struct schema_attribute_list required_attrs;
72         struct schema_attribute_list optional_attrs;
73 };
74
75 /* This function embedds the knowledge of aliased names.
76    Currently it handles only dn vs distinguishedNAme as a special case as AD
77    only have this special alias case, in future we should read the schema
78    to find out which names have an alias and check for them */
79 static int schema_attr_cmp(const char *attr1, const char *attr2)
80 {
81         int ret;
82
83         ret = ldb_attr_cmp(attr1, attr2);
84         if (ret != 0) {
85                 if ((ldb_attr_cmp("dn", attr1) == 0) &&
86                     (ldb_attr_cmp("distinguishedName", attr2) == 0)) {
87                         return 0;
88                 }
89                 if ((ldb_attr_cmp("dn", attr2) == 0) &&
90                     (ldb_attr_cmp("distinguishedName", attr1) == 0)) {
91                         return 0;
92                 }
93         }
94         return ret;
95 }
96
97 static struct schema_attribute *schema_find_attribute(struct schema_attribute_list *list, const char *attr_name)
98 {
99         unsigned int i;
100         for (i = 0; i < list->num; i++) {
101                 if (ldb_attr_cmp(list->attr[i].name, attr_name) == 0) {
102                         return &(list->attr[i]);
103                 }
104         }
105         return NULL;
106 }
107
108 /* get all the attributes and objectclasses found in msg and put them in schema_structure
109    attributes go in the entry_attrs structure for later checking
110    objectclasses go in the objectclasses structure */
111 static int get_msg_attributes(struct schema_structures *ss, const struct ldb_message *msg, int flag_mask)
112 {
113         int i, j, k, l;
114
115         ss->entry_attrs.attr = talloc_realloc(ss, ss->entry_attrs.attr,
116                                               struct schema_attribute,
117                                               ss->entry_attrs.num + msg->num_elements);
118         if (ss->entry_attrs.attr == NULL) {
119                 return -1;
120         }
121
122         for (i = 0, j = ss->entry_attrs.num; i < msg->num_elements; i++) {
123
124                 if (schema_attr_cmp(msg->elements[i].name, "objectclass") == 0) {
125
126                         ss->objectclasses.attr = talloc_realloc(ss, ss->objectclasses.attr,
127                                                                 struct schema_attribute,
128                                                                 ss->objectclasses.num + msg->elements[i].num_values);
129                         if (ss->objectclasses.attr == NULL) {
130                                 return -1;
131                         }
132
133                         for (k = 0, l = ss->objectclasses.num; k < msg->elements[i].num_values; k++) {
134                                 ss->objectclasses.attr[l].name = msg->elements[i].values[k].data;
135                                 ss->objectclasses.attr[l].flags = msg->elements[i].flags & flag_mask;
136                                 l++;
137                         }
138                         ss->objectclasses.num += msg->elements[i].num_values;
139                 }
140
141                 ss->entry_attrs.attr[j].flags = msg->elements[i].flags & flag_mask;
142                 ss->entry_attrs.attr[j].name = talloc_reference(ss->entry_attrs.attr,
143                                                             msg->elements[i].name);
144                 if (ss->entry_attrs.attr[j].name == NULL) {
145                         return -1;
146                 }
147                 j++;
148         }
149         ss->entry_attrs.num += msg->num_elements;
150
151         return 0;
152 }
153
154 static int get_entry_attributes(struct ldb_context *ldb, const char *dn, struct schema_structures *ss)
155 {
156         char *filter = talloc_asprintf(ss, "dn=%s", dn);
157         struct ldb_message **srch;
158         int ret;
159
160         ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
161         if (ret != 1) {
162                 return ret;
163         }
164         talloc_steal(ss, srch);
165
166         /* set flags to 0 as flags on search have undefined values */
167         ret = get_msg_attributes(ss, *srch, 0);
168         if (ret != 0) {
169                 talloc_free(srch);
170                 return ret;
171         }
172
173         return 0;
174 }
175
176 /* add all attributes in el avoiding duplicates in schema_attribute_list */
177 static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list, int flags, struct ldb_message_element *el)
178 {
179         int i, j, vals;
180
181         vals = el->num_values;
182         list->attr = talloc_realloc(mem_ctx, list->attr, struct schema_attribute, list->num + vals);
183         if (list->attr == NULL) {
184                 return -1;
185         }
186         for (i = 0, j = 0; i < vals; i++) {
187                 int c, found, len;
188
189                 found = 0;
190                 for (c = 0; c < list->num; c++) {
191                         len = strlen(list->attr[c].name);
192                         if (len == el->values[i].length) {
193                                 if (schema_attr_cmp(list->attr[c].name, el->values[i].data) == 0) {
194                                         found = 1;
195                                         break;
196                                 }
197                         }
198                 }
199                 if (!found) {
200                         list->attr[j + list->num].name = el->values[i].data;
201                         list->attr[j + list->num].flags = flags;
202                         j++;
203                 }
204         }
205         list->num += j;
206
207         return 0;
208 }
209
210
211 /* we need to get all attributes referenced by the entry objectclasses,
212    recursively get parent objectlasses attributes */
213 static int get_attr_list_recursive(struct ldb_module *module, struct schema_structures *schema_struct)
214 {
215         struct private_data *data = (struct private_data *)module->private_data;
216         struct ldb_message **srch;
217         int i, j;
218         int ret;
219
220         for (i = 0; i < schema_struct->objectclasses.num; i++) {
221                 char *filter;
222
223                 if ((schema_struct->objectclasses.attr[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) {
224                         continue;
225                 }
226                 filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclasses.attr[i].name);
227                 if (filter == NULL) {
228                         return -1;
229                 }
230
231                 ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
232                 if (ret != 1) {
233                         return ret;
234                 }
235                 talloc_steal(schema_struct, srch);
236
237                 if (ret <= 0) {
238                         /* Schema DB Error: Error occurred retrieving Object Class Description */
239                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
240                         data->error_string = "Internal error. Error retrieving schema objectclass";
241                         return -1;
242                 }
243                 if (ret > 1) {
244                         /* Schema DB Error: Too Many Records */
245                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Too many records found retrieving Objectclass %s.\n", schema_struct->objectclasses.attr[i].name);
246                         data->error_string = "Internal error. Too many records searching for schema objectclass";
247                         return -1;
248                 }
249
250                 /* Add inherited classes eliminating duplicates */
251                 /* fill in required_attrs and optional_attrs attribute lists */
252                 for (j = 0; j < (*srch)->num_elements; j++) {
253                         int is_aux, is_class;
254
255                         is_aux = 0;
256                         is_class = 0;
257                         if (schema_attr_cmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
258                                 is_aux = SCHEMA_FLAG_AUXILIARY;
259                                 is_class = 1;
260                         }
261                         if (schema_attr_cmp((*srch)->elements[j].name, "subClassOf") == 0) {
262                                 is_class = 1;
263                         }
264
265                         if (is_class) {
266                                 if (add_attribute_uniq(schema_struct,
267                                                         &schema_struct->objectclasses,
268                                                         is_aux,
269                                                         &(*srch)->elements[j]) != 0) {
270                                         return -1;
271                                 }
272                         } else {
273
274                                 if (schema_attr_cmp((*srch)->elements[j].name, "mustContain") == 0 ||
275                                         schema_attr_cmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
276                                         if (add_attribute_uniq(schema_struct,
277                                                                 &schema_struct->required_attrs,
278                                                                 SCHEMA_FLAG_RESET,
279                                                                 &(*srch)->elements[j]) != 0) {
280                                                 return -1;
281                                         }
282                                 }
283
284                                 if (schema_attr_cmp((*srch)->elements[j].name, "mayContain") == 0 ||
285                                     schema_attr_cmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
286
287                                         if (add_attribute_uniq(schema_struct,
288                                                                 &schema_struct->optional_attrs,
289                                                                 SCHEMA_FLAG_RESET,
290                                                                 &(*srch)->elements[j]) != 0) {
291                                                 return -1;
292                                         }
293                                 }
294                         }
295                 }
296         }
297
298         return 0;
299 }
300
301 /* search */
302 static int schema_search(struct ldb_module *module, const char *base,
303                        enum ldb_scope scope, const char *expression,
304                        const char * const *attrs, struct ldb_message ***res)
305 {
306         return ldb_next_search(module, base, scope, expression, attrs, res); 
307 }
308
309 /* add_record */
310 static int schema_add_record(struct ldb_module *module, const struct ldb_message *msg)
311 {
312         struct private_data *data = (struct private_data *)module->private_data;
313         struct schema_structures *entry_structs;
314         unsigned int i;
315         int ret;
316
317         /* First implementation:
318                 Build up a list of required_attrs and optional_attrs attributes from each objectclass
319                 Check all the required_attrs attributes are present and all the other attributes
320                 are optional_attrs attributes
321                 Throw an error in case a check fail
322                 Free all structures and commit the change
323         */
324
325         if (msg->dn[0] == '@') { /* do not check on our control entries */
326                 return ldb_next_add_record(module, msg);
327         }
328
329         entry_structs = talloc_zero(module, struct schema_structures);
330         if (!entry_structs) {
331                 return -1;
332         }
333
334         ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
335         if (ret != 0) {
336                 talloc_free(entry_structs);
337                 return ret;
338         }
339
340         ret = get_attr_list_recursive(module, entry_structs);
341         if (ret != 0) {
342                 talloc_free(entry_structs);
343                 return ret;
344         }
345
346         /* now check all required_attrs attributes are present */
347         for (i = 0; i < entry_structs->required_attrs.num; i++) {
348                 struct schema_attribute *attr;
349
350                 attr = schema_find_attribute(&entry_structs->entry_attrs,
351                                              entry_structs->required_attrs.attr[i].name);
352
353                 if (attr == NULL) { /* not found */
354                         ldb_debug(module->ldb, LDB_DEBUG_ERROR,
355                                   "The required_attrs attribute %s is missing.\n",
356                                   entry_structs->required_attrs.attr[i].name);
357
358                         data->error_string = "Objectclass violation, a required attribute is missing";
359                         talloc_free(entry_structs);
360                         return -1;
361                 }
362
363                 /* mark the attribute as checked */
364                 attr->flags = SCHEMA_FLAG_CHECKED;
365         }
366
367         /* now check all others atribs are at least optional_attrs */
368         for (i = 0; i < entry_structs->entry_attrs.num; i++) {
369
370                 if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
371                         struct schema_attribute *attr;
372
373                         attr = schema_find_attribute(&entry_structs->optional_attrs,
374                                                      entry_structs->entry_attrs.attr[i].name);
375
376                         if (attr == NULL) { /* not found */
377                                 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
378                                           "The attribute %s is not referenced by any objectclass.\n",
379                                           entry_structs->entry_attrs.attr[i].name);
380
381                                 data->error_string = "Objectclass violation, an invalid attribute name was found";
382                                 talloc_free(entry_structs);
383                                 return -1;
384                         }
385                 }
386         }
387
388         talloc_free(entry_structs);
389
390         return ldb_next_add_record(module, msg);
391 }
392
393 /* modify_record */
394 static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
395 {
396         struct private_data *data = (struct private_data *)module->private_data;
397         struct schema_structures *entry_structs;
398         unsigned int i;
399         int ret;
400
401         /* First implementation:
402                 Retrieve the ldap entry and get the objectclasses,
403                 add msg contained objectclasses if any.
404                 Build up a list of required_attrs and optional_attrs attributes from each objectclass
405                 Check all the attributes are optional_attrs or required_attrs.
406                 Throw an error in case a check fail.
407                 Free all structures and commit the change.
408         */
409
410         if (msg->dn[0] == '@') { /* do not check on our control entries */
411                 return ldb_next_modify_record(module, msg);
412         }
413
414         /* allocate object structs */
415         entry_structs = talloc_zero(module, struct schema_structures);
416         if (!entry_structs) {
417                 return -1;
418         }
419
420         /* now search for the stored entry objectclasses and attributes*/
421         ret = get_entry_attributes(module->ldb, msg->dn, entry_structs);
422         if (ret != 0) {
423                 talloc_free(entry_structs);
424                 return ret;
425         }
426
427         /* get list of values to modify */
428         ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK);
429         if (ret != 0) {
430                 talloc_free(entry_structs);
431                 return ret;
432         }
433
434         ret = get_attr_list_recursive(module, entry_structs);
435         if (ret != 0) {
436                 talloc_free(entry_structs);
437                 return ret;
438         }
439
440         /* now check all required_attrs attributes are present */
441         for (i = 0; i < entry_structs->required_attrs.num; i++) {
442                 struct schema_attribute *attr;
443
444                 attr = schema_find_attribute(&entry_structs->entry_attrs,
445                                              entry_structs->required_attrs.attr[i].name);
446
447                 if (attr == NULL) { /* not found */
448                         ldb_debug(module->ldb, LDB_DEBUG_ERROR,
449                                   "The required_attrs attribute %s is missing.\n",
450                                   entry_structs->required_attrs.attr[i].name);
451
452                         data->error_string = "Objectclass violation, a required attribute is missing";
453                         talloc_free(entry_structs);
454                         return -1;
455                 }
456
457                 /* check we are not trying to delete a required attribute */
458                 /* TODO: consider multivalued attrs */
459                 if ((attr->flags & SCHEMA_FLAG_MOD_DELETE) != 0) {
460                         ldb_debug(module->ldb, LDB_DEBUG_ERROR,
461                                   "Trying to delete the required attribute %s.\n",
462                                   attr->name);
463
464                         data->error_string = "Objectclass violation, a required attribute cannot be removed";
465                         talloc_free(entry_structs);
466                         return -1;
467                 }
468
469                 /* mark the attribute as checked */
470                 attr->flags = SCHEMA_FLAG_CHECKED;
471         }
472
473         /* now check all others atribs are at least optional_attrs */
474         for (i = 0; i < entry_structs->entry_attrs.num; i++) {
475
476                 if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) {
477                         struct schema_attribute *attr;
478
479                         attr = schema_find_attribute(&entry_structs->optional_attrs,
480                                                      entry_structs->entry_attrs.attr[i].name);
481
482                         if (attr == NULL) { /* not found */
483                                 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
484                                           "The attribute %s is not referenced by any objectclass.\n",
485                                           entry_structs->entry_attrs.attr[i].name);
486
487                                 data->error_string = "Objectclass violation, an invalid attribute name was found";
488                                 talloc_free(entry_structs);
489                                 return -1;
490                         }
491                 }
492         }
493
494         talloc_free(entry_structs);
495
496         return ldb_next_modify_record(module, msg);
497 }
498
499 /* delete_record */
500 static int schema_delete_record(struct ldb_module *module, const char *dn)
501 {
502 /*      struct private_data *data = (struct private_data *)module->private_data; */
503         return ldb_next_delete_record(module, dn);
504 }
505
506 /* rename_record */
507 static int schema_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
508 {
509         return ldb_next_rename_record(module, olddn, newdn);
510 }
511
512 static int schema_named_lock(struct ldb_module *module, const char *name) {
513         return ldb_next_named_lock(module, name);
514 }
515
516 static int schema_named_unlock(struct ldb_module *module, const char *name) {
517         return ldb_next_named_unlock(module, name);
518 }
519
520 /* return extended error information */
521 static const char *schema_errstring(struct ldb_module *module)
522 {
523         struct private_data *data = (struct private_data *)module->private_data;
524
525         if (data->error_string) {
526                 const char *error;
527
528                 error = data->error_string;
529                 data->error_string = NULL;
530                 return error;
531         }
532
533         return ldb_next_errstring(module);
534 }
535
536 static int schema_destructor(void *module_ctx)
537 {
538 /*      struct ldb_module *ctx = module_ctx; */
539         /* put your clean-up functions here */
540         return 0;
541 }
542
543 static const struct ldb_module_ops schema_ops = {
544         "schema",
545         schema_search,
546         schema_add_record,
547         schema_modify_record,
548         schema_delete_record,
549         schema_rename_record,
550         schema_named_lock,
551         schema_named_unlock,
552         schema_errstring,
553 };
554
555 #ifdef HAVE_DLOPEN_DISABLED
556 struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
557 #else
558 struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
559 #endif
560 {
561         struct ldb_module *ctx;
562         struct private_data *data;
563
564         ctx = talloc(ldb, struct ldb_module);
565         if (!ctx) {
566                 return NULL;
567         }
568
569         data = talloc(ctx, struct private_data);
570         if (data == NULL) {
571                 talloc_free(ctx);
572                 return NULL;
573         }
574
575         data->error_string = NULL;
576         ctx->private_data = data;
577         ctx->ldb = ldb;
578         ctx->prev = ctx->next = NULL;
579         ctx->ops = &schema_ops;
580
581         talloc_set_destructor (ctx, schema_destructor);
582
583         return ctx;
584 }