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