s4-dsdb: use ldb_operr() in the dsdb code
[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_oom(ldb);
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_operr(ldb);
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         return ldb_oom(ldb);
343 }
344
345 int dsdb_setup_schema_inversion(struct ldb_context *ldb, struct dsdb_schema *schema)
346 {
347         /* Walk the list of schema classes */
348
349         /*  For each subClassOf, add us to subclasses of the parent */
350
351         /* collect these subclasses into a recursive list of total subclasses, preserving order */
352
353         /* For each subclass under 'top', write the index from it's
354          * order as an integer in the dsdb_class (for sorting
355          * objectClass lists efficiently) */
356
357         /* Walk the list of scheam classes */
358         
359         /*  Create a 'total possible superiors' on each class */
360         return LDB_SUCCESS;
361 }
362
363 /**
364  * Attach the schema to an opaque pointer on the ldb, so ldb modules
365  * can find it 
366  */
367
368 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
369 {
370         struct dsdb_schema *old_schema;
371         int ret;
372
373         ret = dsdb_setup_sorted_accessors(ldb, schema);
374         if (ret != LDB_SUCCESS) {
375                 return ret;
376         }
377
378         ret = schema_fill_constructed(schema);
379         if (ret != LDB_SUCCESS) {
380                 return ret;
381         }
382
383         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
384
385         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
386         if (ret != LDB_SUCCESS) {
387                 return ret;
388         }
389
390         /* Remove the reference to the schema we just overwrote - if there was
391          * none, NULL is harmless here */
392         if (old_schema != schema) {
393                 talloc_unlink(ldb, old_schema);
394                 talloc_steal(ldb, schema);
395         }
396
397         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
398         if (ret != LDB_SUCCESS) {
399                 return ret;
400         }
401
402         /* Set the new attributes based on the new schema */
403         ret = dsdb_schema_set_attributes(ldb, schema, true);
404         if (ret != LDB_SUCCESS) {
405                 return ret;
406         }
407
408         return LDB_SUCCESS;
409 }
410
411 /**
412  * Global variable to hold one copy of the schema, used to avoid memory bloat
413  */
414 static struct dsdb_schema *global_schema;
415
416 /**
417  * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
418  */
419 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
420                           bool write_attributes)
421 {
422         int ret;
423         struct dsdb_schema *old_schema;
424         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
425         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
426         if (ret != LDB_SUCCESS) {
427                 return ret;
428         }
429
430         /* Remove the reference to the schema we just overwrote - if there was
431          * none, NULL is harmless here */
432         talloc_unlink(ldb, old_schema);
433
434         if (talloc_reference(ldb, schema) == NULL) {
435                 return ldb_oom(ldb);
436         }
437
438         ret = dsdb_schema_set_attributes(ldb, schema, write_attributes);
439         if (ret != LDB_SUCCESS) {
440                 return ret;
441         }
442
443         return LDB_SUCCESS;
444 }
445
446 /**
447  * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
448  */
449 int dsdb_set_global_schema(struct ldb_context *ldb)
450 {
451         int ret;
452         void *use_global_schema = (void *)1;
453         if (!global_schema) {
454                 return LDB_SUCCESS;
455         }
456         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", use_global_schema);
457         if (ret != LDB_SUCCESS) {
458                 return ret;
459         }
460
461         /* Set the new attributes based on the new schema */
462         ret = dsdb_schema_set_attributes(ldb, global_schema, false /* Don't write attributes, it's expensive */);
463         if (ret == LDB_SUCCESS) {
464                 /* Keep a reference to this schema, just incase the original copy is replaced */
465                 if (talloc_reference(ldb, global_schema) == NULL) {
466                         return ldb_oom(ldb);
467                 }
468         }
469
470         return ret;
471 }
472
473 /**
474  * Find the schema object for this ldb
475  *
476  * If reference_ctx is not NULL, then talloc_reference onto that context
477  */
478
479 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *reference_ctx)
480 {
481         const void *p;
482         struct dsdb_schema *schema_out;
483         struct dsdb_schema *schema_in;
484         bool use_global_schema;
485         TALLOC_CTX *tmp_ctx = talloc_new(reference_ctx);
486         if (!tmp_ctx) {
487                 return NULL;
488         }
489
490         /* see if we have a cached copy */
491         use_global_schema = (ldb_get_opaque(ldb, "dsdb_use_global_schema") != NULL);
492         if (use_global_schema) {
493                 schema_in = global_schema;
494         } else {
495                 p = ldb_get_opaque(ldb, "dsdb_schema");
496
497                 schema_in = talloc_get_type(p, struct dsdb_schema);
498                 if (!schema_in) {
499                         talloc_free(tmp_ctx);
500                         return NULL;
501                 }
502         }
503
504         if (schema_in->refresh_fn && !schema_in->refresh_in_progress) {
505                 if (!talloc_reference(tmp_ctx, schema_in)) {
506                         /* ensure that the schema_in->refresh_in_progress remains valid for the right amount of time */
507                         talloc_free(tmp_ctx);
508                         return NULL;
509                 }
510                 schema_in->refresh_in_progress = true;
511                 /* This may change schema, if it needs to reload it from disk */
512                 schema_out = schema_in->refresh_fn(schema_in->loaded_from_module,
513                                                    schema_in,
514                                                    use_global_schema);
515                 schema_in->refresh_in_progress = false;
516         } else {
517                 schema_out = schema_in;
518         }
519
520         /* This removes the extra reference above */
521         talloc_free(tmp_ctx);
522         if (!reference_ctx) {
523                 return schema_out;
524         } else {
525                 return talloc_reference(reference_ctx, schema_out);
526         }
527 }
528
529 /**
530  * Make the schema found on this ldb the 'global' schema
531  */
532
533 void dsdb_make_schema_global(struct ldb_context *ldb, struct dsdb_schema *schema)
534 {
535         if (!schema) {
536                 return;
537         }
538
539         if (global_schema) {
540                 talloc_unlink(talloc_autofree_context(), global_schema);
541         }
542
543         /* we want the schema to be around permanently */
544         talloc_reparent(ldb, talloc_autofree_context(), schema);
545         global_schema = schema;
546
547         /* This calls the talloc_reference() of the global schema back onto the ldb */
548         dsdb_set_global_schema(ldb);
549 }
550
551 /* When loading the schema from LDIF files, we don't get the extended DNs. 
552    
553    We need to set these up, so that from the moment we start the provision, the defaultObjectCategory links are set up correctly. 
554  */
555 int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *schema)
556 {
557         struct dsdb_class *cur;
558         const struct dsdb_class *target_class;
559         for (cur = schema->classes; cur; cur = cur->next) {
560                 const struct ldb_val *rdn;
561                 struct ldb_val guid;
562                 NTSTATUS status;
563                 struct ldb_dn *dn = ldb_dn_new(NULL, ldb, cur->defaultObjectCategory);
564
565                 if (!dn) {
566                         return LDB_ERR_INVALID_DN_SYNTAX;
567                 }
568                 rdn = ldb_dn_get_component_val(dn, 0);
569                 if (!rdn) {
570                         talloc_free(dn);
571                         return LDB_ERR_INVALID_DN_SYNTAX;
572                 }
573                 target_class = dsdb_class_by_cn_ldb_val(schema, rdn);
574                 if (!target_class) {
575                         talloc_free(dn);
576                         return LDB_ERR_CONSTRAINT_VIOLATION;
577                 }
578                 
579                 status = GUID_to_ndr_blob(&target_class->objectGUID, dn, &guid);
580                 if (!NT_STATUS_IS_OK(status)) {
581                         talloc_free(dn);
582                         return ldb_operr(ldb);
583                 }
584                 ldb_dn_set_extended_component(dn, "GUID", &guid);
585
586                 cur->defaultObjectCategory = ldb_dn_get_extended_linearized(cur, dn, 1);
587                 talloc_free(dn);
588         }
589         return LDB_SUCCESS;
590 }
591
592 /** 
593  * Add an element to the schema (attribute or class) from an LDB message
594  */
595 WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema, 
596                                        struct ldb_message *msg) 
597 {
598         if (samdb_find_attribute(ldb, msg,
599                                  "objectclass", "attributeSchema") != NULL) {
600                 return dsdb_attribute_from_ldb(ldb, schema, msg);
601         } else if (samdb_find_attribute(ldb, msg,
602                                  "objectclass", "classSchema") != NULL) {
603                 return dsdb_class_from_ldb(schema, msg);
604         }
605
606         /* Don't fail on things not classes or attributes */
607         return WERR_OK;
608 }
609
610 /**
611  * Rather than read a schema from the LDB itself, read it from an ldif
612  * file.  This allows schema to be loaded and used while adding the
613  * schema itself to the directory.
614  */
615
616 WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df)
617 {
618         struct ldb_ldif *ldif;
619         struct ldb_message *msg;
620         TALLOC_CTX *mem_ctx;
621         WERROR status;
622         int ret;
623         struct dsdb_schema *schema;
624         const struct ldb_val *prefix_val;
625         const struct ldb_val *info_val;
626         struct ldb_val info_val_default;
627
628
629         mem_ctx = talloc_new(ldb);
630         if (!mem_ctx) {
631                 goto nomem;
632         }
633
634         schema = dsdb_new_schema(mem_ctx);
635
636         schema->fsmo.we_are_master = true;
637         schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
638         if (!schema->fsmo.master_dn) {
639                 goto nomem;
640         }
641
642         /*
643          * load the prefixMap attribute from pf
644          */
645         ldif = ldb_ldif_read_string(ldb, &pf);
646         if (!ldif) {
647                 status = WERR_INVALID_PARAM;
648                 goto failed;
649         }
650         talloc_steal(mem_ctx, ldif);
651
652         msg = ldb_msg_canonicalize(ldb, ldif->msg);
653         if (!msg) {
654                 goto nomem;
655         }
656         talloc_steal(mem_ctx, msg);
657         talloc_free(ldif);
658
659         prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
660         if (!prefix_val) {
661                 status = WERR_INVALID_PARAM;
662                 goto failed;
663         }
664
665         info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
666         if (!info_val) {
667                 status = dsdb_schema_info_blob_new(mem_ctx, &info_val_default);
668                 W_ERROR_NOT_OK_GOTO(status, failed);
669                 info_val = &info_val_default;
670         }
671
672         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
673         if (!W_ERROR_IS_OK(status)) {
674                 DEBUG(0,("ERROR: dsdb_load_oid_mappings_ldb() failed with %s\n", win_errstr(status)));
675                 goto failed;
676         }
677
678         /*
679          * load the attribute and class definitions outof df
680          */
681         while ((ldif = ldb_ldif_read_string(ldb, &df))) {
682                 talloc_steal(mem_ctx, ldif);
683
684                 msg = ldb_msg_canonicalize(ldb, ldif->msg);
685                 if (!msg) {
686                         goto nomem;
687                 }
688
689                 status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, msg);
690                 talloc_free(ldif);
691                 if (!W_ERROR_IS_OK(status)) {
692                         goto failed;
693                 }
694         }
695
696         ret = dsdb_set_schema(ldb, schema);
697         if (ret != LDB_SUCCESS) {
698                 status = WERR_FOOBAR;
699                 goto failed;
700         }
701
702         ret = dsdb_schema_fill_extended_dn(ldb, schema);
703         if (ret != LDB_SUCCESS) {
704                 status = WERR_FOOBAR;
705                 goto failed;
706         }
707
708         goto done;
709
710 nomem:
711         status = WERR_NOMEM;
712 failed:
713 done:
714         talloc_free(mem_ctx);
715         return status;
716 }