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