r4714: move the ldb code to the new talloc interface (eg remove _p suffix)
[ambi/samba-autobuild/.git] / source4 / 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 struct attribute_syntax {
40         const char *name;
41         const char *syntax_id;
42 };
43
44 static struct attribute_syntax attrsyn[] = {
45                 { "Object(DS-DN)", "2.5.5.1"},
46                 { "String(Object-Identifier)", "2.5.5.2"},
47                 { "", "2.5.5.3"},
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"}
62         };
63
64 #define SCHEMA_TALLOC_CHECK(root, mem, ret) do { if (!mem) { talloc_free(root); return ret;} } while(0);
65
66 #define SA_FLAG_RESET           0
67 #define SA_FLAG_AUXCLASS        1
68 #define SA_FLAG_CHECKED         2
69
70 struct private_data {
71         struct ldb_context *schema_db;
72         const char *error_string;
73 };
74
75 /* close */
76 static int schema_close(struct ldb_module *module)
77 {
78         return ldb_next_close(module);
79 }
80
81 /* search */
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)
85 {
86         return ldb_next_search(module, base, scope, expression, attrs, res); 
87 }
88
89 /* search_free */
90 static int schema_search_free(struct ldb_module *module, struct ldb_message **res)
91 {
92         return ldb_next_search_free(module, res);
93 }
94
95 struct attribute_list {
96         int flags;
97         char *name;
98 };
99
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;
105         int check_list_num;
106         int objectclass_list_num;
107         int must_num;
108         int may_num;
109 };
110
111 static int get_object_objectclasses(struct ldb_context *ldb, const char *dn, struct schema_structures *schema_struct)
112 {
113         char *filter = talloc_asprintf(schema_struct, "dn=%s", dn);
114         const char *attrs[] = {"objectClass", NULL};
115         struct ldb_message **srch;
116         int i, j, ret;
117
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);
121         if (ret == 1) {
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);
129                                 return -1;
130                         }
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);
137                                         return -1;
138                                 }
139                                 schema_struct->objectclass_list[j].flags = SA_FLAG_RESET;
140                         }
141                 }
142                 ldb_search_free(ldb, srch);
143         } else {
144                 ldb_search_free(ldb, srch);
145                 return -1;
146         }
147
148         return 0;
149 }
150
151 static int get_check_list(struct ldb_module *module, struct schema_structures *schema_struct, const struct ldb_message *msg)
152 {
153         int i, j, k;
154
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) {
162                 return -1;
163         }
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) {
171                                 return -1;
172                         }
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) {
178                                         return -1;
179                                 }
180                                 schema_struct->objectclass_list[k].flags = SA_FLAG_RESET;
181                         }
182                 }
183
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) {
188                         return -1;
189                 }
190                 j++;
191         }
192
193         return 0;
194 }
195
196 static int add_attribute_uniq(struct attribute_list **list, int *list_num, int flags, struct ldb_message_element *el, void *mem_ctx)
197 {
198         int i, j, vals;
199
200         vals = el->num_values;
201         *list = talloc_realloc(mem_ctx, *list, struct attribute_list, *list_num + vals);
202         if (list == 0) {
203                 return -1;
204         }
205         for (i = 0, j = 0; i < vals; i++) {
206                 int c, found, len;
207
208                 found = 0;
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) {
213                                         found = 1;
214                                         break;
215                                 }
216                         }
217                 }
218                 if (!found) {
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) {
221                                 return -1;
222                         }
223                         (*list)[j + *list_num].flags = flags;
224                         j++;
225                 }
226         }
227         *list_num += j;
228
229         return 0;
230 }
231
232 static int get_attr_list_recursive(struct ldb_module *module, struct ldb_context *ldb, struct schema_structures *schema_struct)
233 {
234         struct private_data *data = (struct private_data *)module->private_data;
235         struct ldb_message **srch;
236         int i, j;
237         int ret;
238
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++) {
244                 char *filter;
245
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);
249                 if (ret == 0) {
250                         int ok;
251
252                         ok = 0;
253                         /* suppose auxiliary classeschema_struct are not required */
254                         if (schema_struct->objectclass_list[i].flags & SA_FLAG_AUXCLASS) {
255                                 int d;
256                                 ok = 1;
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];
260                                 }
261                                 i -= 1;
262                         }
263                         if (!ok) {
264                                 /* Schema Violation: Object Class Description Not Found */
265                                 data->error_string = "ObjectClass not found";
266                                 return -1;
267                         }
268                         continue;
269                 } else {
270                         if (ret < 0) {
271                                 /* Schema DB Error: Error occurred retrieving Object Class Description */
272                                 data->error_string = "Internal error. Error retrieving schema objectclass";
273                                 return -1;
274                         }
275                         if (ret > 1) {
276                                 /* Schema DB Error: Too Many Records */
277                                 data->error_string = "Internal error. Too many records searching for schema objectclass";
278                                 return -1;
279                         }
280                 }
281
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;
286
287                         is_aux = 0;
288                         is_class = 0;
289                         if (strcasecmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
290                                 is_aux = SA_FLAG_AUXCLASS;
291                                 is_class = 1;
292                         }
293                         if (strcasecmp((*srch)->elements[j].name, "subClassOf") == 0) {
294                                 is_class = 1;
295                         }
296
297                         if (is_class) {
298                                 if (add_attribute_uniq(&schema_struct->objectclass_list,
299                                                         &schema_struct->objectclass_list_num,
300                                                         is_aux,
301                                                         &(*srch)->elements[j],
302                                                         schema_struct) != 0) {
303                                         return -1;
304                                 }
305                         } else {
306
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,
311                                                                 SA_FLAG_RESET,
312                                                                 &(*srch)->elements[j],
313                                                                 schema_struct) != 0) {
314                                                 return -1;
315                                         }
316                                 }
317
318                                 if (strcasecmp((*srch)->elements[j].name, "mayContain") == 0 ||
319                                     strcasecmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
320
321                                         if (add_attribute_uniq(&schema_struct->may,
322                                                                 &schema_struct->may_num,
323                                                                 SA_FLAG_RESET,
324                                                                 &(*srch)->elements[j],
325                                                                 schema_struct) != 0) {
326                                                 return -1;
327                                         }
328                                 }
329                         }
330                 }
331
332                 ldb_search_free(ldb, srch);
333         }
334
335         return 0;
336 }
337
338 /* add_record */
339 static int schema_add_record(struct ldb_module *module, const struct ldb_message *msg)
340 {
341         struct private_data *data = (struct private_data *)module->private_data;
342         struct schema_structures *entry_structs;
343         int i, j;
344         int ret;
345
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
351         */
352
353         entry_structs = talloc(module, struct schema_structures);
354         if (!entry_structs) {
355                 return -1;
356         }
357
358         ret = get_check_list(module, entry_structs, msg);
359         if (ret != 0) {
360                 talloc_free(entry_structs);
361                 return ret;
362         }
363
364         /* find all other objectclasses recursively */
365         ret = get_attr_list_recursive(module, data->schema_db, entry_structs);
366         if (ret != 0) {
367                 talloc_free(entry_structs);
368                 return ret;
369         }
370
371         /* now check all musts are present */
372         for (i = 0; i < entry_structs->must_num; i++) {
373                 int found;
374
375                 found = 0;
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;
379                                 found = 1;
380                                 break;
381                         }
382                 }
383
384                 if ( ! found ) {
385                         /* TODO: set the error string */
386                         data->error_string = "Objectclass violation, a required attribute is mischema_structing";
387                         talloc_free(entry_structs);
388                         return -1;
389                 }
390         }
391
392         /* now check all others atribs are found in mays */
393         for (i = 0; i < entry_structs->check_list_num; i++) {
394
395                 if (entry_structs->check_list[i].flags != SA_FLAG_CHECKED) {
396                         int found;
397
398                         found = 0;
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;
402                                         found = 1;
403                                         break;
404                                 }
405                         }
406
407                         if ( ! found ) {
408                                 data->error_string = "Objectclass violation, an invalid attribute name was found";
409                                 talloc_free(entry_structs);
410                                 return -1;
411                         }
412                 }
413         }
414
415         talloc_free(entry_structs);
416
417         return ldb_next_add_record(module, msg);
418 }
419
420 /* modify_record */
421 static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
422 {
423         struct private_data *data = (struct private_data *)module->private_data;
424         struct schema_structures *entry_structs, *modify_structs;
425         int i, j;
426         int ret;
427
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.
437         */
438
439         /* allocate object structs */
440         entry_structs = talloc(module, struct schema_structures);
441         if (!entry_structs) {
442                 return -1;
443         }
444
445         /* allocate modification entry structs */
446         modify_structs = talloc(entry_structs, struct schema_structures);
447         if (!modify_structs) {
448                 talloc_free(entry_structs);
449                 return -1;
450         }
451
452         /* get list of values to modify */
453         ret = get_check_list(module, modify_structs, msg);
454         if (ret != 0) {
455                 talloc_free(entry_structs);
456                 return ret;
457         }
458
459         /* find all modify objectclasses recursively if any objectclass is being added */
460         ret = get_attr_list_recursive(module, data->schema_db, modify_structs);
461         if (ret != 0) {
462                 talloc_free(entry_structs);
463                 return ret;
464         }
465
466         /* now search for the original object objectclasses */
467         ret = get_object_objectclasses(module->ldb, msg->dn, entry_structs);
468         if (ret != 0) {
469                 talloc_free(entry_structs);
470                 return ret;
471         }
472
473         /* find all other objectclasses recursively */
474         ret = get_attr_list_recursive(module, data->schema_db, entry_structs);
475         if (ret != 0) {
476                 talloc_free(entry_structs);
477                 return ret;
478         }
479
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++) {
484                 int found;
485
486                 found = 0;
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;
490                                 found = 1;
491                                 break;
492                         }
493                 }
494                 if ( ! found) {
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;
498                                         break;
499                                 }
500                         }
501                 }
502         }
503
504         /* now check all new objectclasses musts are present */
505         for (i = 0; i < modify_structs->must_num; i++) {
506                 int found;
507
508                 found = 0;
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;
512                                 found = 1;
513                                 break;
514                         }
515                 }
516
517                 if ( ! found ) {
518                         /* TODO: set the error string */
519                         data->error_string = "Objectclass violation, a required attribute is missing";
520                         talloc_free(entry_structs);
521                         return -1;
522                 }
523         }
524
525         /* now check all others atribs are found in mays */
526         for (i = 0; i < modify_structs->check_list_num; i++) {
527
528                 if (modify_structs->check_list[i].flags != SA_FLAG_CHECKED) {
529                         int found;
530
531                         found = 0;
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;
535                                         found = 1;
536                                         break;
537                                 }
538                         }
539
540                         if ( ! found ) {
541                                 data->error_string = "Objectclass violation, an invalid attribute name was found";
542                                 talloc_free(entry_structs);
543                                 return -1;
544                         }
545                 }
546         }
547
548         talloc_free(entry_structs);
549
550         return ldb_next_modify_record(module, msg);
551 }
552
553 /* delete_record */
554 static int schema_delete_record(struct ldb_module *module, const char *dn)
555 {
556 /*      struct private_data *data = (struct private_data *)module->private_data; */
557         return ldb_next_delete_record(module, dn);
558 }
559
560 /* rename_record */
561 static int schema_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
562 {
563         return ldb_next_rename_record(module, olddn, newdn);
564 }
565
566 static int schema_named_lock(struct ldb_module *module, const char *name) {
567         return ldb_next_named_lock(module, name);
568 }
569
570 static int schema_named_unlock(struct ldb_module *module, const char *name) {
571         return ldb_next_named_unlock(module, name);
572 }
573
574 /* return extended error information */
575 static const char *schema_errstring(struct ldb_module *module)
576 {
577         struct private_data *data = (struct private_data *)module->private_data;
578
579         if (data->error_string) {
580                 const char *error;
581
582                 error = data->error_string;
583                 data->error_string = NULL;
584                 return error;
585         }
586
587         return ldb_next_errstring(module);
588 }
589
590 static const struct ldb_module_ops schema_ops = {
591         "schema",
592         schema_close, 
593         schema_search,
594         schema_search_free,
595         schema_add_record,
596         schema_modify_record,
597         schema_delete_record,
598         schema_rename_record,
599         schema_named_lock,
600         schema_named_unlock,
601         schema_errstring,
602 };
603
604 #define SCHEMA_PREFIX           "schema:"
605 #define SCHEMA_PREFIX_LEN       7
606
607 #ifdef HAVE_DLOPEN_DISABLED
608 struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
609 #else
610 struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
611 #endif
612 {
613         struct ldb_module *ctx;
614         struct private_data *data;
615         char *db_url = NULL;
616         int i;
617
618         ctx = talloc(ldb, struct ldb_module);
619         if (!ctx) {
620                 return NULL;
621         }
622
623         if (options) {
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);
628                         }
629                 }
630         }
631
632         if (!db_url) { /* search if it is defined in the calling ldb */
633                 int ret;
634                 const char * attrs[] = { "@SCHEMADB", NULL };
635                 struct ldb_message **msgs;
636
637                 ret = ldb_search(ldb, "", LDB_SCOPE_BASE, "dn=@MODULES", (const char * const *)attrs, &msgs);
638                 if (ret == 0) {
639                         ldb_debug(ldb, LDB_DEBUG_TRACE, "Schema DB not found\n");
640                         ldb_search_free(ldb, msgs);
641                         return NULL;
642                 } else {
643                         if (ret < 0) {
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);
646                                 return NULL;
647                         }
648                         if (ret > 1) {
649                                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found, bailing out\n");
650                                 ldb_search_free(ldb, msgs);
651                                 return NULL;
652                         }
653
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);
656                 }
657
658                 ldb_search_free(ldb, msgs);
659         }
660
661         data = talloc(ctx, struct private_data);
662         SCHEMA_TALLOC_CHECK(ctx, data, NULL);
663
664         data->schema_db = ldb_connect(db_url, 0, NULL); 
665         SCHEMA_TALLOC_CHECK(ctx, data->schema_db, NULL);
666
667         data->error_string = NULL;
668         ctx->private_data = data;
669         ctx->ldb = ldb;
670         ctx->prev = ctx->next = NULL;
671         ctx->ops = &schema_ops;
672
673         return ctx;
674 }