s4:dsdb/schema: add "dsdb:schema update allowed" option to enable schema updates
[samba.git] / source4 / dsdb / schema / schema_set.c
1 /*
2    Unix SMB/CIFS implementation.
3    DSDB schema header
4
5    Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
7    Copyright (C) Matthieu Patou <mat@matws.net> 2011
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 */
23
24 #include "includes.h"
25 #include "lib/util/dlinklist.h"
26 #include "dsdb/samdb/samdb.h"
27 #include <ldb_module.h>
28 #include "param/param.h"
29 #include "librpc/ndr/libndr.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "lib/util/tsort.h"
32
33 /* change this when we change something in our schema code that
34  * requires a re-index of the database
35  */
36 #define SAMDB_INDEXING_VERSION "2"
37
38 /*
39   override the name to attribute handler function
40  */
41 const struct ldb_schema_attribute *dsdb_attribute_handler_override(struct ldb_context *ldb,
42                                                                    void *private_data,
43                                                                    const char *name)
44 {
45         struct dsdb_schema *schema = talloc_get_type_abort(private_data, struct dsdb_schema);
46         const struct dsdb_attribute *a = dsdb_attribute_by_lDAPDisplayName(schema, name);
47         if (a == NULL) {
48                 /* this will fall back to ldb internal handling */
49                 return NULL;
50         }
51         return a->ldb_schema_attribute;
52 }
53
54 static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
55 {
56         int ret = LDB_SUCCESS;
57         struct ldb_result *res;
58         struct ldb_result *res_idx;
59         struct dsdb_attribute *attr;
60         struct ldb_message *mod_msg;
61         TALLOC_CTX *mem_ctx;
62         struct ldb_message *msg;
63         struct ldb_message *msg_idx;
64
65         /* setup our own attribute name to schema handler */
66         ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);
67
68         if (!write_attributes) {
69                 return ret;
70         }
71
72         mem_ctx = talloc_new(ldb);
73         if (!mem_ctx) {
74                 return ldb_oom(ldb);
75         }
76
77         msg = ldb_msg_new(mem_ctx);
78         if (!msg) {
79                 ldb_oom(ldb);
80                 goto op_error;
81         }
82         msg_idx = ldb_msg_new(mem_ctx);
83         if (!msg_idx) {
84                 ldb_oom(ldb);
85                 goto op_error;
86         }
87         msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
88         if (!msg->dn) {
89                 ldb_oom(ldb);
90                 goto op_error;
91         }
92         msg_idx->dn = ldb_dn_new(msg_idx, ldb, "@INDEXLIST");
93         if (!msg_idx->dn) {
94                 ldb_oom(ldb);
95                 goto op_error;
96         }
97
98         ret = ldb_msg_add_string(msg_idx, "@IDXONE", "1");
99         if (ret != LDB_SUCCESS) {
100                 goto op_error;
101         }
102
103
104         ret = ldb_msg_add_string(msg_idx, "@IDXVERSION", SAMDB_INDEXING_VERSION);
105         if (ret != LDB_SUCCESS) {
106                 goto op_error;
107         }
108
109         for (attr = schema->attributes; attr; attr = attr->next) {
110                 const char *syntax = attr->syntax->ldb_syntax;
111
112                 if (!syntax) {
113                         syntax = attr->syntax->ldap_oid;
114                 }
115
116                 /*
117                  * Write out a rough approximation of the schema
118                  * as an @ATTRIBUTES value, for bootstrapping
119                  */
120                 if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) {
121                         ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER");
122                 } else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) {
123                         ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE");
124                 }
125                 if (ret != LDB_SUCCESS) {
126                         break;
127                 }
128
129                 if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) {
130                         ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName);
131                         if (ret != LDB_SUCCESS) {
132                                 break;
133                         }
134                 }
135         }
136
137         if (ret != LDB_SUCCESS) {
138                 talloc_free(mem_ctx);
139                 return ret;
140         }
141
142         /*
143          * Try to avoid churning the attributes too much,
144          * we only want to do this if they have changed
145          */
146         ret = ldb_search(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL,
147                          NULL);
148         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
149                 ret = ldb_add(ldb, msg);
150         } else if (ret != LDB_SUCCESS) {
151         } else if (res->count != 1) {
152                 ret = ldb_add(ldb, msg);
153         } else {
154                 ret = LDB_SUCCESS;
155                 /* Annoyingly added to our search results */
156                 ldb_msg_remove_attr(res->msgs[0], "distinguishedName");
157
158                 ret = ldb_msg_difference(ldb, mem_ctx,
159                                          res->msgs[0], msg, &mod_msg);
160                 if (ret != LDB_SUCCESS) {
161                         goto op_error;
162                 }
163                 if (mod_msg->num_elements > 0) {
164                         ret = dsdb_replace(ldb, mod_msg, 0);
165                 }
166                 talloc_free(mod_msg);
167         }
168
169         if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
170                 /* We might be on a read-only DB or LDAP */
171                 ret = LDB_SUCCESS;
172         }
173         if (ret != LDB_SUCCESS) {
174                 talloc_free(mem_ctx);
175                 return ret;
176         }
177
178         /* Now write out the indexes, as found in the schema (if they have changed) */
179
180         ret = ldb_search(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE,
181                          NULL, NULL);
182         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
183                 ret = ldb_add(ldb, msg_idx);
184         } else if (ret != LDB_SUCCESS) {
185         } else if (res_idx->count != 1) {
186                 ret = ldb_add(ldb, msg_idx);
187         } else {
188                 ret = LDB_SUCCESS;
189                 /* Annoyingly added to our search results */
190                 ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName");
191
192                 ret = ldb_msg_difference(ldb, mem_ctx,
193                                          res_idx->msgs[0], msg_idx, &mod_msg);
194                 if (ret != LDB_SUCCESS) {
195                         goto op_error;
196                 }
197                 if (mod_msg->num_elements > 0) {
198                         ret = dsdb_replace(ldb, mod_msg, 0);
199                 }
200                 talloc_free(mod_msg);
201         }
202         if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
203                 /* We might be on a read-only DB */
204                 ret = LDB_SUCCESS;
205         }
206         talloc_free(mem_ctx);
207         return ret;
208
209 op_error:
210         talloc_free(mem_ctx);
211         return ldb_operr(ldb);
212 }
213
214
215 /*
216   create extra attribute shortcuts
217  */
218 static void dsdb_setup_attribute_shortcuts(struct ldb_context *ldb, struct dsdb_schema *schema)
219 {
220         struct dsdb_attribute *attribute;
221
222         /* setup fast access to one_way_link and DN format */
223         for (attribute=schema->attributes; attribute; attribute=attribute->next) {
224                 attribute->dn_format = dsdb_dn_oid_to_format(attribute->syntax->ldap_oid);
225
226                 if (attribute->dn_format == DSDB_INVALID_DN) {
227                         attribute->one_way_link = false;
228                         continue;
229                 }
230
231                 /* these are not considered to be one way links for
232                    the purpose of DN link fixups */
233                 if (ldb_attr_cmp("distinguishedName", attribute->lDAPDisplayName) == 0 ||
234                     ldb_attr_cmp("objectCategory", attribute->lDAPDisplayName) == 0) {
235                         attribute->one_way_link = false;
236                         continue;
237                 }
238
239                 if (attribute->linkID == 0) {
240                         attribute->one_way_link = true;
241                         continue;
242                 }
243                 /* handle attributes with a linkID but no backlink */
244                 if ((attribute->linkID & 1) == 0 &&
245                     dsdb_attribute_by_linkID(schema, attribute->linkID + 1) == NULL) {
246                         attribute->one_way_link = true;
247                         continue;
248                 }
249                 attribute->one_way_link = false;
250         }
251 }
252
253 static int uint32_cmp(uint32_t c1, uint32_t c2)
254 {
255         if (c1 == c2) return 0;
256         return c1 > c2 ? 1 : -1;
257 }
258
259 static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
260 {
261         return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
262 }
263 static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
264 {
265         return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id);
266 }
267 static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
268 {
269         return strcasecmp((*c1)->governsID_oid, (*c2)->governsID_oid);
270 }
271 static int dsdb_compare_class_by_cn(struct dsdb_class **c1, struct dsdb_class **c2)
272 {
273         return strcasecmp((*c1)->cn, (*c2)->cn);
274 }
275
276 static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
277 {
278         return strcasecmp((*a1)->lDAPDisplayName, (*a2)->lDAPDisplayName);
279 }
280 static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
281 {
282         return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id);
283 }
284 static int dsdb_compare_attribute_by_msDS_IntId(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
285 {
286         return uint32_cmp((*a1)->msDS_IntId, (*a2)->msDS_IntId);
287 }
288 static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
289 {
290         return strcasecmp((*a1)->attributeID_oid, (*a2)->attributeID_oid);
291 }
292 static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
293 {
294         return uint32_cmp((*a1)->linkID, (*a2)->linkID);
295 }
296
297 /**
298  * Clean up Classes and Attributes accessor arrays
299  */
300 static void dsdb_sorted_accessors_free(struct dsdb_schema *schema)
301 {
302         /* free classes accessors */
303         TALLOC_FREE(schema->classes_by_lDAPDisplayName);
304         TALLOC_FREE(schema->classes_by_governsID_id);
305         TALLOC_FREE(schema->classes_by_governsID_oid);
306         TALLOC_FREE(schema->classes_by_cn);
307         /* free attribute accessors */
308         TALLOC_FREE(schema->attributes_by_lDAPDisplayName);
309         TALLOC_FREE(schema->attributes_by_attributeID_id);
310         TALLOC_FREE(schema->attributes_by_msDS_IntId);
311         TALLOC_FREE(schema->attributes_by_attributeID_oid);
312         TALLOC_FREE(schema->attributes_by_linkID);
313 }
314
315 /*
316   create the sorted accessor arrays for the schema
317  */
318 int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
319                                 struct dsdb_schema *schema)
320 {
321         struct dsdb_class *cur;
322         struct dsdb_attribute *a;
323         unsigned int i;
324         unsigned int num_int_id;
325         int ret;
326
327         /* free all caches */
328         dsdb_sorted_accessors_free(schema);
329
330         /* count the classes */
331         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) /* noop */ ;
332         schema->num_classes = i;
333
334         /* setup classes_by_* */
335         schema->classes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_class *, i);
336         schema->classes_by_governsID_id    = talloc_array(schema, struct dsdb_class *, i);
337         schema->classes_by_governsID_oid   = talloc_array(schema, struct dsdb_class *, i);
338         schema->classes_by_cn              = talloc_array(schema, struct dsdb_class *, i);
339         if (schema->classes_by_lDAPDisplayName == NULL ||
340             schema->classes_by_governsID_id == NULL ||
341             schema->classes_by_governsID_oid == NULL ||
342             schema->classes_by_cn == NULL) {
343                 goto failed;
344         }
345
346         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) {
347                 schema->classes_by_lDAPDisplayName[i] = cur;
348                 schema->classes_by_governsID_id[i]    = cur;
349                 schema->classes_by_governsID_oid[i]   = cur;
350                 schema->classes_by_cn[i]              = cur;
351         }
352
353         /* sort the arrays */
354         TYPESAFE_QSORT(schema->classes_by_lDAPDisplayName, schema->num_classes, dsdb_compare_class_by_lDAPDisplayName);
355         TYPESAFE_QSORT(schema->classes_by_governsID_id, schema->num_classes, dsdb_compare_class_by_governsID_id);
356         TYPESAFE_QSORT(schema->classes_by_governsID_oid, schema->num_classes, dsdb_compare_class_by_governsID_oid);
357         TYPESAFE_QSORT(schema->classes_by_cn, schema->num_classes, dsdb_compare_class_by_cn);
358
359         /* now build the attribute accessor arrays */
360
361         /* count the attributes
362          * and attributes with msDS-IntId set */
363         num_int_id = 0;
364         for (i=0, a=schema->attributes; a; i++, a=a->next) {
365                 if (a->msDS_IntId != 0) {
366                         num_int_id++;
367                 }
368         }
369         schema->num_attributes = i;
370         schema->num_int_id_attr = num_int_id;
371
372         /* setup attributes_by_* */
373         schema->attributes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_attribute *, i);
374         schema->attributes_by_attributeID_id    = talloc_array(schema, struct dsdb_attribute *, i);
375         schema->attributes_by_msDS_IntId        = talloc_array(schema,
376                                                                struct dsdb_attribute *, num_int_id);
377         schema->attributes_by_attributeID_oid   = talloc_array(schema, struct dsdb_attribute *, i);
378         schema->attributes_by_linkID              = talloc_array(schema, struct dsdb_attribute *, i);
379         if (schema->attributes_by_lDAPDisplayName == NULL ||
380             schema->attributes_by_attributeID_id == NULL ||
381             schema->attributes_by_msDS_IntId == NULL ||
382             schema->attributes_by_attributeID_oid == NULL ||
383             schema->attributes_by_linkID == NULL) {
384                 goto failed;
385         }
386
387         num_int_id = 0;
388         for (i=0, a=schema->attributes; a; i++, a=a->next) {
389                 schema->attributes_by_lDAPDisplayName[i] = a;
390                 schema->attributes_by_attributeID_id[i]    = a;
391                 schema->attributes_by_attributeID_oid[i]   = a;
392                 schema->attributes_by_linkID[i]          = a;
393                 /* append attr-by-msDS-IntId values */
394                 if (a->msDS_IntId != 0) {
395                         schema->attributes_by_msDS_IntId[num_int_id] = a;
396                         num_int_id++;
397                 }
398         }
399         SMB_ASSERT(num_int_id == schema->num_int_id_attr);
400
401         /* sort the arrays */
402         TYPESAFE_QSORT(schema->attributes_by_lDAPDisplayName, schema->num_attributes, dsdb_compare_attribute_by_lDAPDisplayName);
403         TYPESAFE_QSORT(schema->attributes_by_attributeID_id, schema->num_attributes, dsdb_compare_attribute_by_attributeID_id);
404         TYPESAFE_QSORT(schema->attributes_by_msDS_IntId, schema->num_int_id_attr, dsdb_compare_attribute_by_msDS_IntId);
405         TYPESAFE_QSORT(schema->attributes_by_attributeID_oid, schema->num_attributes, dsdb_compare_attribute_by_attributeID_oid);
406         TYPESAFE_QSORT(schema->attributes_by_linkID, schema->num_attributes, dsdb_compare_attribute_by_linkID);
407
408         dsdb_setup_attribute_shortcuts(ldb, schema);
409
410         ret = schema_fill_constructed(schema);
411         if (ret != LDB_SUCCESS) {
412                 dsdb_sorted_accessors_free(schema);
413                 return ret;
414         }
415
416         return LDB_SUCCESS;
417
418 failed:
419         dsdb_sorted_accessors_free(schema);
420         return ldb_oom(ldb);
421 }
422
423 /**
424  * Attach the schema to an opaque pointer on the ldb,
425  * so ldb modules can find it
426  */
427 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
428 {
429         struct dsdb_schema *old_schema;
430         int ret;
431
432         ret = dsdb_setup_sorted_accessors(ldb, schema);
433         if (ret != LDB_SUCCESS) {
434                 return ret;
435         }
436
437         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
438
439         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
440         if (ret != LDB_SUCCESS) {
441                 return ret;
442         }
443
444         /* Remove the reference to the schema we just overwrote - if there was
445          * none, NULL is harmless here */
446         if (old_schema != schema) {
447                 talloc_unlink(ldb, old_schema);
448                 talloc_steal(ldb, schema);
449         }
450
451         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
452         if (ret != LDB_SUCCESS) {
453                 return ret;
454         }
455
456         /* Set the new attributes based on the new schema */
457         ret = dsdb_schema_set_attributes(ldb, schema, true);
458         if (ret != LDB_SUCCESS) {
459                 return ret;
460         }
461
462         return LDB_SUCCESS;
463 }
464
465 /**
466  * Global variable to hold one copy of the schema, used to avoid memory bloat
467  */
468 static struct dsdb_schema *global_schema;
469
470 /**
471  * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
472  */
473 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
474                           bool write_attributes)
475 {
476         int ret;
477         struct dsdb_schema *old_schema;
478         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
479         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
480         if (ret != LDB_SUCCESS) {
481                 return ret;
482         }
483
484         /* Remove the reference to the schema we just overwrote - if there was
485          * none, NULL is harmless here */
486         talloc_unlink(ldb, old_schema);
487
488         if (talloc_reference(ldb, schema) == NULL) {
489                 return ldb_oom(ldb);
490         }
491
492         /* Make this ldb use local schema preferably */
493         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
494         if (ret != LDB_SUCCESS) {
495                 return ret;
496         }
497
498         ret = dsdb_schema_set_attributes(ldb, schema, write_attributes);
499         if (ret != LDB_SUCCESS) {
500                 return ret;
501         }
502
503         return LDB_SUCCESS;
504 }
505
506 /**
507  * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
508  */
509 int dsdb_set_global_schema(struct ldb_context *ldb)
510 {
511         int ret;
512         void *use_global_schema = (void *)1;
513         if (!global_schema) {
514                 return LDB_SUCCESS;
515         }
516         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", use_global_schema);
517         if (ret != LDB_SUCCESS) {
518                 return ret;
519         }
520
521         /* Set the new attributes based on the new schema */
522         ret = dsdb_schema_set_attributes(ldb, global_schema, false /* Don't write attributes, it's expensive */);
523         if (ret == LDB_SUCCESS) {
524                 /* Keep a reference to this schema, just in case the original copy is replaced */
525                 if (talloc_reference(ldb, global_schema) == NULL) {
526                         return ldb_oom(ldb);
527                 }
528         }
529
530         return ret;
531 }
532
533 bool dsdb_uses_global_schema(struct ldb_context *ldb)
534 {
535         return (ldb_get_opaque(ldb, "dsdb_use_global_schema") != NULL);
536 }
537
538 /**
539  * Find the schema object for this ldb
540  *
541  * If reference_ctx is not NULL, then talloc_reference onto that context
542  */
543
544 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *reference_ctx)
545 {
546         const void *p;
547         struct dsdb_schema *schema_out;
548         struct dsdb_schema *schema_in;
549         bool use_global_schema;
550         TALLOC_CTX *tmp_ctx = talloc_new(reference_ctx);
551         if (!tmp_ctx) {
552                 return NULL;
553         }
554
555         /* see if we have a cached copy */
556         use_global_schema = dsdb_uses_global_schema(ldb);
557         if (use_global_schema) {
558                 schema_in = global_schema;
559         } else {
560                 p = ldb_get_opaque(ldb, "dsdb_schema");
561
562                 schema_in = talloc_get_type(p, struct dsdb_schema);
563                 if (!schema_in) {
564                         talloc_free(tmp_ctx);
565                         return NULL;
566                 }
567         }
568
569         if (schema_in->refresh_fn && !schema_in->refresh_in_progress) {
570                 if (!talloc_reference(tmp_ctx, schema_in)) {
571                         /*
572                          * ensure that the schema_in->refresh_in_progress
573                          * remains valid for the right amount of time
574                          */
575                         talloc_free(tmp_ctx);
576                         return NULL;
577                 }
578                 schema_in->refresh_in_progress = true;
579                 /* This may change schema, if it needs to reload it from disk */
580                 schema_out = schema_in->refresh_fn(schema_in->loaded_from_module,
581                                                    schema_in,
582                                                    use_global_schema);
583                 schema_in->refresh_in_progress = false;
584         } else {
585                 schema_out = schema_in;
586         }
587
588         /* This removes the extra reference above */
589         talloc_free(tmp_ctx);
590         if (!reference_ctx) {
591                 return schema_out;
592         } else {
593                 return talloc_reference(reference_ctx, schema_out);
594         }
595 }
596
597 /**
598  * Make the schema found on this ldb the 'global' schema
599  */
600
601 void dsdb_make_schema_global(struct ldb_context *ldb, struct dsdb_schema *schema)
602 {
603         if (!schema) {
604                 return;
605         }
606
607         if (global_schema) {
608                 talloc_unlink(talloc_autofree_context(), global_schema);
609         }
610
611         /* we want the schema to be around permanently */
612         talloc_reparent(ldb, talloc_autofree_context(), schema);
613         global_schema = schema;
614
615         /* This calls the talloc_reference() of the global schema back onto the ldb */
616         dsdb_set_global_schema(ldb);
617 }
618
619 /**
620  * When loading the schema from LDIF files, we don't get the extended DNs.
621  *
622  * We need to set these up, so that from the moment we start the provision,
623  * the defaultObjectCategory links are set up correctly.
624  */
625 int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *schema)
626 {
627         struct dsdb_class *cur;
628         const struct dsdb_class *target_class;
629         for (cur = schema->classes; cur; cur = cur->next) {
630                 const struct ldb_val *rdn;
631                 struct ldb_val guid;
632                 NTSTATUS status;
633                 struct ldb_dn *dn = ldb_dn_new(NULL, ldb, cur->defaultObjectCategory);
634
635                 if (!dn) {
636                         return LDB_ERR_INVALID_DN_SYNTAX;
637                 }
638                 rdn = ldb_dn_get_component_val(dn, 0);
639                 if (!rdn) {
640                         talloc_free(dn);
641                         return LDB_ERR_INVALID_DN_SYNTAX;
642                 }
643                 target_class = dsdb_class_by_cn_ldb_val(schema, rdn);
644                 if (!target_class) {
645                         talloc_free(dn);
646                         return LDB_ERR_CONSTRAINT_VIOLATION;
647                 }
648
649                 status = GUID_to_ndr_blob(&target_class->objectGUID, dn, &guid);
650                 if (!NT_STATUS_IS_OK(status)) {
651                         talloc_free(dn);
652                         return ldb_operr(ldb);
653                 }
654                 ldb_dn_set_extended_component(dn, "GUID", &guid);
655
656                 cur->defaultObjectCategory = ldb_dn_get_extended_linearized(cur, dn, 1);
657                 talloc_free(dn);
658         }
659         return LDB_SUCCESS;
660 }
661
662 /**
663  * Add an element to the schema (attribute or class) from an LDB message
664  */
665 WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema,
666                                        struct ldb_message *msg)
667 {
668         if (samdb_find_attribute(ldb, msg,
669                                  "objectclass", "attributeSchema") != NULL) {
670                 return dsdb_attribute_from_ldb(ldb, schema, msg);
671         } else if (samdb_find_attribute(ldb, msg,
672                                  "objectclass", "classSchema") != NULL) {
673                 return dsdb_class_from_ldb(schema, msg);
674         }
675
676         /* Don't fail on things not classes or attributes */
677         return WERR_OK;
678 }
679
680 /**
681  * Rather than read a schema from the LDB itself, read it from an ldif
682  * file.  This allows schema to be loaded and used while adding the
683  * schema itself to the directory.
684  */
685
686 WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb,
687                                  const char *pf, const char *df,
688                                  const char *dn)
689 {
690         struct ldb_ldif *ldif;
691         struct ldb_message *msg;
692         TALLOC_CTX *mem_ctx;
693         WERROR status;
694         int ret;
695         struct dsdb_schema *schema;
696         const struct ldb_val *prefix_val;
697         const struct ldb_val *info_val;
698         struct ldb_val info_val_default;
699
700
701         mem_ctx = talloc_new(ldb);
702         if (!mem_ctx) {
703                 goto nomem;
704         }
705
706         schema = dsdb_new_schema(mem_ctx);
707         if (!schema) {
708                 goto nomem;
709         }
710         schema->base_dn = ldb_dn_new(schema, ldb, dn);
711         if (!schema->base_dn) {
712                 goto nomem;
713         }
714         schema->fsmo.we_are_master = true;
715         schema->fsmo.update_allowed = true;
716         schema->fsmo.master_dn = ldb_dn_new(schema, ldb, "@PROVISION_SCHEMA_MASTER");
717         if (!schema->fsmo.master_dn) {
718                 goto nomem;
719         }
720
721         /*
722          * load the prefixMap attribute from pf
723          */
724         ldif = ldb_ldif_read_string(ldb, &pf);
725         if (!ldif) {
726                 status = WERR_INVALID_PARAM;
727                 goto failed;
728         }
729         talloc_steal(mem_ctx, ldif);
730
731         ret = ldb_msg_normalize(ldb, mem_ctx, ldif->msg, &msg);
732         if (ret != LDB_SUCCESS) {
733                 goto nomem;
734         }
735         talloc_free(ldif);
736
737         prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
738         if (!prefix_val) {
739                 status = WERR_INVALID_PARAM;
740                 goto failed;
741         }
742
743         info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
744         if (!info_val) {
745                 status = dsdb_schema_info_blob_new(mem_ctx, &info_val_default);
746                 W_ERROR_NOT_OK_GOTO(status, failed);
747                 info_val = &info_val_default;
748         }
749
750         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
751         if (!W_ERROR_IS_OK(status)) {
752                 DEBUG(0,("ERROR: dsdb_load_oid_mappings_ldb() failed with %s\n", win_errstr(status)));
753                 goto failed;
754         }
755
756         /* load the attribute and class definitions out of df */
757         while ((ldif = ldb_ldif_read_string(ldb, &df))) {
758                 talloc_steal(mem_ctx, ldif);
759
760                 ret = ldb_msg_normalize(ldb, ldif, ldif->msg, &msg);
761                 if (ret != LDB_SUCCESS) {
762                         goto nomem;
763                 }
764
765                 status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, msg);
766                 talloc_free(ldif);
767                 if (!W_ERROR_IS_OK(status)) {
768                         goto failed;
769                 }
770         }
771
772         ret = dsdb_set_schema(ldb, schema);
773         if (ret != LDB_SUCCESS) {
774                 status = WERR_FOOBAR;
775                 goto failed;
776         }
777
778         ret = dsdb_schema_fill_extended_dn(ldb, schema);
779         if (ret != LDB_SUCCESS) {
780                 status = WERR_FOOBAR;
781                 goto failed;
782         }
783
784         goto done;
785
786 nomem:
787         status = WERR_NOMEM;
788 failed:
789 done:
790         talloc_free(mem_ctx);
791         return status;
792 }