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