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