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