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