s4/dsdb-schema: Index attributes on msDS-IntId value
[amitay/samba.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         unsigned int num_int_id;
234
235         talloc_free(schema->classes_by_lDAPDisplayName);
236         talloc_free(schema->classes_by_governsID_id);
237         talloc_free(schema->classes_by_governsID_oid);
238         talloc_free(schema->classes_by_cn);
239
240         /* count the classes */
241         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) /* noop */ ;
242         schema->num_classes = i;
243
244         /* setup classes_by_* */
245         schema->classes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_class *, i);
246         schema->classes_by_governsID_id    = talloc_array(schema, struct dsdb_class *, i);
247         schema->classes_by_governsID_oid   = talloc_array(schema, struct dsdb_class *, i);
248         schema->classes_by_cn              = talloc_array(schema, struct dsdb_class *, i);
249         if (schema->classes_by_lDAPDisplayName == NULL ||
250             schema->classes_by_governsID_id == NULL ||
251             schema->classes_by_governsID_oid == NULL ||
252             schema->classes_by_cn == NULL) {
253                 goto failed;
254         }
255
256         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) {
257                 schema->classes_by_lDAPDisplayName[i] = cur;
258                 schema->classes_by_governsID_id[i]    = cur;
259                 schema->classes_by_governsID_oid[i]   = cur;
260                 schema->classes_by_cn[i]              = cur;
261         }
262
263         /* sort the arrays */
264         TYPESAFE_QSORT(schema->classes_by_lDAPDisplayName, schema->num_classes, dsdb_compare_class_by_lDAPDisplayName);
265         TYPESAFE_QSORT(schema->classes_by_governsID_id, schema->num_classes, dsdb_compare_class_by_governsID_id);
266         TYPESAFE_QSORT(schema->classes_by_governsID_oid, schema->num_classes, dsdb_compare_class_by_governsID_oid);
267         TYPESAFE_QSORT(schema->classes_by_cn, schema->num_classes, dsdb_compare_class_by_cn);
268
269         /* now build the attribute accessor arrays */
270         talloc_free(schema->attributes_by_lDAPDisplayName);
271         talloc_free(schema->attributes_by_attributeID_id);
272         talloc_free(schema->attributes_by_msDS_IntId);
273         talloc_free(schema->attributes_by_attributeID_oid);
274         talloc_free(schema->attributes_by_linkID);
275
276         /* count the attributes
277          * and attributes with msDS-IntId set */
278         num_int_id = 0;
279         for (i=0, a=schema->attributes; a; i++, a=a->next) {
280                 if (a->msDS_IntId != 0) {
281                         num_int_id++;
282                 }
283         }
284         schema->num_attributes = i;
285         schema->num_int_id_attr = num_int_id;
286
287         /* setup attributes_by_* */
288         schema->attributes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_attribute *, i);
289         schema->attributes_by_attributeID_id    = talloc_array(schema, struct dsdb_attribute *, i);
290         schema->attributes_by_msDS_IntId        = talloc_array(schema,
291                                                                struct dsdb_attribute *, num_int_id);
292         schema->attributes_by_attributeID_oid   = talloc_array(schema, struct dsdb_attribute *, i);
293         schema->attributes_by_linkID              = talloc_array(schema, struct dsdb_attribute *, i);
294         if (schema->attributes_by_lDAPDisplayName == NULL ||
295             schema->attributes_by_attributeID_id == NULL ||
296             schema->attributes_by_msDS_IntId == NULL ||
297             schema->attributes_by_attributeID_oid == NULL ||
298             schema->attributes_by_linkID == NULL) {
299                 goto failed;
300         }
301
302         num_int_id = 0;
303         for (i=0, a=schema->attributes; a; i++, a=a->next) {
304                 schema->attributes_by_lDAPDisplayName[i] = a;
305                 schema->attributes_by_attributeID_id[i]    = a;
306                 schema->attributes_by_attributeID_oid[i]   = a;
307                 schema->attributes_by_linkID[i]          = a;
308                 /* append attr-by-msDS-IntId values */
309                 if (a->msDS_IntId != 0) {
310                         schema->attributes_by_msDS_IntId[num_int_id] = a;
311                         num_int_id++;
312                 }
313         }
314         SMB_ASSERT(num_int_id == schema->num_int_id_attr);
315
316         /* sort the arrays */
317         TYPESAFE_QSORT(schema->attributes_by_lDAPDisplayName, schema->num_attributes, dsdb_compare_attribute_by_lDAPDisplayName);
318         TYPESAFE_QSORT(schema->attributes_by_attributeID_id, schema->num_attributes, dsdb_compare_attribute_by_attributeID_id);
319         TYPESAFE_QSORT(schema->attributes_by_msDS_IntId, schema->num_int_id_attr, dsdb_compare_attribute_by_attributeID_id);
320         TYPESAFE_QSORT(schema->attributes_by_attributeID_oid, schema->num_attributes, dsdb_compare_attribute_by_attributeID_oid);
321         TYPESAFE_QSORT(schema->attributes_by_linkID, schema->num_attributes, dsdb_compare_attribute_by_linkID);
322
323         return LDB_SUCCESS;
324
325 failed:
326         schema->classes_by_lDAPDisplayName = NULL;
327         schema->classes_by_governsID_id = NULL;
328         schema->classes_by_governsID_oid = NULL;
329         schema->classes_by_cn = NULL;
330         schema->attributes_by_lDAPDisplayName = NULL;
331         schema->attributes_by_attributeID_id = NULL;
332         schema->attributes_by_msDS_IntId = NULL;
333         schema->attributes_by_attributeID_oid = NULL;
334         schema->attributes_by_linkID = NULL;
335         ldb_oom(ldb);
336         return LDB_ERR_OPERATIONS_ERROR;
337 }
338
339 int dsdb_setup_schema_inversion(struct ldb_context *ldb, struct dsdb_schema *schema)
340 {
341         /* Walk the list of schema classes */
342
343         /*  For each subClassOf, add us to subclasses of the parent */
344
345         /* collect these subclasses into a recursive list of total subclasses, preserving order */
346
347         /* For each subclass under 'top', write the index from it's
348          * order as an integer in the dsdb_class (for sorting
349          * objectClass lists efficiently) */
350
351         /* Walk the list of scheam classes */
352         
353         /*  Create a 'total possible superiors' on each class */
354         return LDB_SUCCESS;
355 }
356
357 /**
358  * Attach the schema to an opaque pointer on the ldb, so ldb modules
359  * can find it 
360  */
361
362 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
363 {
364         int ret;
365
366         ret = dsdb_setup_sorted_accessors(ldb, schema);
367         if (ret != LDB_SUCCESS) {
368                 return ret;
369         }
370
371         ret = schema_fill_constructed(schema);
372         if (ret != LDB_SUCCESS) {
373                 return ret;
374         }
375
376         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
377         if (ret != LDB_SUCCESS) {
378                 return ret;
379         }
380
381         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
382         if (ret != LDB_SUCCESS) {
383                 return ret;
384         }
385
386         /* Set the new attributes based on the new schema */
387         ret = dsdb_schema_set_attributes(ldb, schema, true);
388         if (ret != LDB_SUCCESS) {
389                 return ret;
390         }
391
392         talloc_steal(ldb, schema);
393
394         return LDB_SUCCESS;
395 }
396
397 /**
398  * Global variable to hold one copy of the schema, used to avoid memory bloat
399  */
400 static struct dsdb_schema *global_schema;
401
402 /**
403  * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
404  */
405 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
406                           bool write_attributes)
407 {
408         int ret;
409         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
410         if (ret != LDB_SUCCESS) {
411                 return ret;
412         }
413
414         if (talloc_reference(ldb, schema) == NULL) {
415                 return LDB_ERR_OPERATIONS_ERROR;
416         }
417
418         ret = dsdb_schema_set_attributes(ldb, schema, write_attributes);
419         if (ret != LDB_SUCCESS) {
420                 return ret;
421         }
422
423         return LDB_SUCCESS;
424 }
425
426 /**
427  * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
428  */
429 int dsdb_set_global_schema(struct ldb_context *ldb)
430 {
431         int ret;
432         void *use_global_schema = (void *)1;
433         if (!global_schema) {
434                 return LDB_SUCCESS;
435         }
436
437         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", use_global_schema);
438         if (ret != LDB_SUCCESS) {
439                 return ret;
440         }
441
442         /* Set the new attributes based on the new schema */
443         ret = dsdb_schema_set_attributes(ldb, global_schema, false /* Don't write attributes, it's expensive */);
444         if (ret == LDB_SUCCESS) {
445                 /* Keep a reference to this schema, just incase the original copy is replaced */
446                 if (talloc_reference(ldb, global_schema) == NULL) {
447                         return LDB_ERR_OPERATIONS_ERROR;
448                 }
449         }
450
451         return ret;
452 }
453
454 /**
455  * Find the schema object for this ldb
456  *
457  * If reference_ctx is not NULL, then talloc_reference onto that context
458  */
459
460 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *reference_ctx)
461 {
462         const void *p;
463         struct dsdb_schema *schema_out;
464         struct dsdb_schema *schema_in;
465         bool use_global_schema;
466
467         /* see if we have a cached copy */
468         use_global_schema = (ldb_get_opaque(ldb, "dsdb_use_global_schema") != NULL);
469         if (use_global_schema) {
470                 schema_in = global_schema;
471         } else {
472                 p = ldb_get_opaque(ldb, "dsdb_schema");
473
474                 schema_in = talloc_get_type(p, struct dsdb_schema);
475                 if (!schema_in) {
476                         return NULL;
477                 }
478         }
479
480         if (schema_in->refresh_fn && !schema_in->refresh_in_progress) {
481                 schema_in->refresh_in_progress = true;
482                 /* This may change schema, if it needs to reload it from disk */
483                 schema_out = schema_in->refresh_fn(schema_in->loaded_from_module,
484                                                    schema_in,
485                                                    use_global_schema);
486                 schema_in->refresh_in_progress = false;
487                 if (schema_out != schema_in) {
488                         talloc_unlink(schema_in, ldb);
489                 }
490         } else {
491                 schema_out = schema_in;
492         }
493
494         if (!reference_ctx) {
495                 return schema_out;
496         } else {
497                 return talloc_reference(reference_ctx, schema_out);
498         }
499 }
500
501 /**
502  * Make the schema found on this ldb the 'global' schema
503  */
504
505 void dsdb_make_schema_global(struct ldb_context *ldb, struct dsdb_schema *schema)
506 {
507         if (!schema) {
508                 return;
509         }
510
511         if (global_schema) {
512                 talloc_unlink(talloc_autofree_context(), global_schema);
513         }
514
515         /* Wipe any reference to the exact schema - we will set 'use the global schema' below */
516         ldb_set_opaque(ldb, "dsdb_schema", NULL);
517
518         /* we want the schema to be around permanently */
519         talloc_reparent(ldb, talloc_autofree_context(), schema);
520         global_schema = schema;
521
522         /* This calls the talloc_reference() of the global schema back onto the ldb */
523         dsdb_set_global_schema(ldb);
524 }
525
526 /* When loading the schema from LDIF files, we don't get the extended DNs. 
527    
528    We need to set these up, so that from the moment we start the provision, the defaultObjectCategory links are set up correctly. 
529  */
530 int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *schema)
531 {
532         struct dsdb_class *cur;
533         const struct dsdb_class *target_class;
534         for (cur = schema->classes; cur; cur = cur->next) {
535                 const struct ldb_val *rdn;
536                 struct ldb_val guid;
537                 NTSTATUS status;
538                 struct ldb_dn *dn = ldb_dn_new(NULL, ldb, cur->defaultObjectCategory);
539
540                 if (!dn) {
541                         return LDB_ERR_INVALID_DN_SYNTAX;
542                 }
543                 rdn = ldb_dn_get_component_val(dn, 0);
544                 if (!rdn) {
545                         talloc_free(dn);
546                         return LDB_ERR_INVALID_DN_SYNTAX;
547                 }
548                 target_class = dsdb_class_by_cn_ldb_val(schema, rdn);
549                 if (!target_class) {
550                         talloc_free(dn);
551                         return LDB_ERR_CONSTRAINT_VIOLATION;
552                 }
553                 
554                 status = GUID_to_ndr_blob(&target_class->objectGUID, dn, &guid);
555                 if (!NT_STATUS_IS_OK(status)) {
556                         talloc_free(dn);
557                         return LDB_ERR_OPERATIONS_ERROR;
558                 }
559                 ldb_dn_set_extended_component(dn, "GUID", &guid);
560
561                 cur->defaultObjectCategory = ldb_dn_get_extended_linearized(cur, dn, 1);
562                 talloc_free(dn);
563         }
564         return LDB_SUCCESS;
565 }
566
567 /** 
568  * Add an element to the schema (attribute or class) from an LDB message
569  */
570 WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema, 
571                                        struct ldb_message *msg) 
572 {
573         if (samdb_find_attribute(ldb, msg,
574                                  "objectclass", "attributeSchema") != NULL) {
575                 return dsdb_attribute_from_ldb(ldb, schema, msg);
576         } else if (samdb_find_attribute(ldb, msg,
577                                  "objectclass", "classSchema") != NULL) {
578                 return dsdb_class_from_ldb(schema, msg);
579         }
580
581         /* Don't fail on things not classes or attributes */
582         return WERR_OK;
583 }
584
585 /**
586  * Rather than read a schema from the LDB itself, read it from an ldif
587  * file.  This allows schema to be loaded and used while adding the
588  * schema itself to the directory.
589  */
590
591 WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df)
592 {
593         struct ldb_ldif *ldif;
594         struct ldb_message *msg;
595         TALLOC_CTX *mem_ctx;
596         WERROR status;
597         int ret;
598         struct dsdb_schema *schema;
599         const struct ldb_val *prefix_val;
600         const struct ldb_val *info_val;
601         struct ldb_val info_val_default;
602
603
604         mem_ctx = talloc_new(ldb);
605         if (!mem_ctx) {
606                 goto nomem;
607         }
608
609         schema = dsdb_new_schema(mem_ctx);
610
611         schema->fsmo.we_are_master = true;
612         schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
613         if (!schema->fsmo.master_dn) {
614                 goto nomem;
615         }
616
617         /*
618          * load the prefixMap attribute from pf
619          */
620         ldif = ldb_ldif_read_string(ldb, &pf);
621         if (!ldif) {
622                 status = WERR_INVALID_PARAM;
623                 goto failed;
624         }
625         talloc_steal(mem_ctx, ldif);
626
627         msg = ldb_msg_canonicalize(ldb, ldif->msg);
628         if (!msg) {
629                 goto nomem;
630         }
631         talloc_steal(mem_ctx, msg);
632         talloc_free(ldif);
633
634         prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
635         if (!prefix_val) {
636                 status = WERR_INVALID_PARAM;
637                 goto failed;
638         }
639
640         info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
641         if (!info_val) {
642                 status = dsdb_schema_info_blob_new(mem_ctx, &info_val_default);
643                 W_ERROR_NOT_OK_GOTO(status, failed);
644                 info_val = &info_val_default;
645         }
646
647         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
648         if (!W_ERROR_IS_OK(status)) {
649                 DEBUG(0,("ERROR: dsdb_load_oid_mappings_ldb() failed with %s\n", win_errstr(status)));
650                 goto failed;
651         }
652
653         /*
654          * load the attribute and class definitions outof df
655          */
656         while ((ldif = ldb_ldif_read_string(ldb, &df))) {
657                 talloc_steal(mem_ctx, ldif);
658
659                 msg = ldb_msg_canonicalize(ldb, ldif->msg);
660                 if (!msg) {
661                         goto nomem;
662                 }
663
664                 status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, msg);
665                 talloc_free(ldif);
666                 if (!W_ERROR_IS_OK(status)) {
667                         goto failed;
668                 }
669         }
670
671         ret = dsdb_set_schema(ldb, schema);
672         if (ret != LDB_SUCCESS) {
673                 status = WERR_FOOBAR;
674                 goto failed;
675         }
676
677         ret = dsdb_schema_fill_extended_dn(ldb, schema);
678         if (ret != LDB_SUCCESS) {
679                 status = WERR_FOOBAR;
680                 goto failed;
681         }
682
683         goto done;
684
685 nomem:
686         status = WERR_NOMEM;
687 failed:
688 done:
689         talloc_free(mem_ctx);
690         return status;
691 }