73264f9545a6906fcebbfacd67f83c0befabd969
[metze/samba/wip.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    Copyright (C) Matthieu Patou <mat@matws.net> 2011
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 */
23
24 #include "includes.h"
25 #include "lib/util/dlinklist.h"
26 #include "dsdb/samdb/samdb.h"
27 #include <ldb_module.h>
28 #include "param/param.h"
29 #include "librpc/ndr/libndr.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "lib/util/tsort.h"
32
33 /* change this when we change something in our schema code that
34  * requires a re-index of the database
35  */
36 #define SAMDB_INDEXING_VERSION "2"
37
38 /*
39   override the name to attribute handler function
40  */
41 const struct ldb_schema_attribute *dsdb_attribute_handler_override(struct ldb_context *ldb,
42                                                                    void *private_data,
43                                                                    const char *name)
44 {
45         struct dsdb_schema *schema = talloc_get_type_abort(private_data, struct dsdb_schema);
46         const struct dsdb_attribute *a = dsdb_attribute_by_lDAPDisplayName(schema, name);
47         if (a == NULL) {
48                 /* this will fall back to ldb internal handling */
49                 return NULL;
50         }
51         return a->ldb_schema_attribute;
52 }
53 /*
54  * Set the attribute handlers onto the LDB, and potentially write the
55  * @INDEXLIST, @IDXONE and @ATTRIBUTES records.  The @ATTRIBUTES records
56  * are required so we can operate on a schema-less database (say the
57  * backend during emergency fixes) and during the schema load.
58  */
59 static int dsdb_schema_set_indices_and_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_indices_and_attributes)
60 {
61         int ret = LDB_SUCCESS;
62         struct ldb_result *res;
63         struct ldb_result *res_idx;
64         struct dsdb_attribute *attr;
65         struct ldb_message *mod_msg;
66         TALLOC_CTX *mem_ctx;
67         struct ldb_message *msg;
68         struct ldb_message *msg_idx;
69
70         /* setup our own attribute name to schema handler */
71         ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);
72
73         if (!write_indices_and_attributes) {
74                 return ret;
75         }
76
77         mem_ctx = talloc_new(ldb);
78         if (!mem_ctx) {
79                 return ldb_oom(ldb);
80         }
81
82         msg = ldb_msg_new(mem_ctx);
83         if (!msg) {
84                 ldb_oom(ldb);
85                 goto op_error;
86         }
87         msg_idx = ldb_msg_new(mem_ctx);
88         if (!msg_idx) {
89                 ldb_oom(ldb);
90                 goto op_error;
91         }
92         msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
93         if (!msg->dn) {
94                 ldb_oom(ldb);
95                 goto op_error;
96         }
97         msg_idx->dn = ldb_dn_new(msg_idx, ldb, "@INDEXLIST");
98         if (!msg_idx->dn) {
99                 ldb_oom(ldb);
100                 goto op_error;
101         }
102
103         ret = ldb_msg_add_string(msg_idx, "@IDXONE", "1");
104         if (ret != LDB_SUCCESS) {
105                 goto op_error;
106         }
107
108
109         ret = ldb_msg_add_string(msg_idx, "@IDXVERSION", SAMDB_INDEXING_VERSION);
110         if (ret != LDB_SUCCESS) {
111                 goto op_error;
112         }
113
114         for (attr = schema->attributes; attr; attr = attr->next) {
115                 const char *syntax = attr->syntax->ldb_syntax;
116
117                 if (!syntax) {
118                         syntax = attr->syntax->ldap_oid;
119                 }
120
121                 /*
122                  * Write out a rough approximation of the schema
123                  * as an @ATTRIBUTES value, for bootstrapping
124                  */
125                 if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) {
126                         ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER");
127                 } else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) {
128                         ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE");
129                 }
130                 if (ret != LDB_SUCCESS) {
131                         break;
132                 }
133
134                 if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) {
135                         ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName);
136                         if (ret != LDB_SUCCESS) {
137                                 break;
138                         }
139                 }
140         }
141
142         if (ret != LDB_SUCCESS) {
143                 talloc_free(mem_ctx);
144                 return ret;
145         }
146
147         /*
148          * Try to avoid churning the attributes too much,
149          * we only want to do this if they have changed
150          */
151         ret = ldb_search(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL,
152                          NULL);
153         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
154                 ret = ldb_add(ldb, msg);
155         } else if (ret != LDB_SUCCESS) {
156         } else if (res->count != 1) {
157                 ret = ldb_add(ldb, msg);
158         } else {
159                 ret = LDB_SUCCESS;
160                 /* Annoyingly added to our search results */
161                 ldb_msg_remove_attr(res->msgs[0], "distinguishedName");
162
163                 ret = ldb_msg_difference(ldb, mem_ctx,
164                                          res->msgs[0], msg, &mod_msg);
165                 if (ret != LDB_SUCCESS) {
166                         goto op_error;
167                 }
168                 if (mod_msg->num_elements > 0) {
169                         ret = dsdb_replace(ldb, mod_msg, 0);
170                 }
171                 talloc_free(mod_msg);
172         }
173
174         if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
175                 /* We might be on a read-only DB or LDAP */
176                 ret = LDB_SUCCESS;
177         }
178         if (ret != LDB_SUCCESS) {
179                 talloc_free(mem_ctx);
180                 return ret;
181         }
182
183         /* Now write out the indexes, as found in the schema (if they have changed) */
184
185         ret = ldb_search(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE,
186                          NULL, NULL);
187         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
188                 ret = ldb_add(ldb, msg_idx);
189         } else if (ret != LDB_SUCCESS) {
190         } else if (res_idx->count != 1) {
191                 ret = ldb_add(ldb, msg_idx);
192         } else {
193                 ret = LDB_SUCCESS;
194                 /* Annoyingly added to our search results */
195                 ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName");
196
197                 ret = ldb_msg_difference(ldb, mem_ctx,
198                                          res_idx->msgs[0], msg_idx, &mod_msg);
199                 if (ret != LDB_SUCCESS) {
200                         goto op_error;
201                 }
202                 if (mod_msg->num_elements > 0) {
203                         ret = dsdb_replace(ldb, mod_msg, 0);
204                 }
205                 talloc_free(mod_msg);
206         }
207         if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
208                 /* We might be on a read-only DB */
209                 ret = LDB_SUCCESS;
210         }
211         talloc_free(mem_ctx);
212         return ret;
213
214 op_error:
215         talloc_free(mem_ctx);
216         return ldb_operr(ldb);
217 }
218
219
220 /*
221   create extra attribute shortcuts
222  */
223 static void dsdb_setup_attribute_shortcuts(struct ldb_context *ldb, struct dsdb_schema *schema)
224 {
225         struct dsdb_attribute *attribute;
226
227         /* setup fast access to one_way_link and DN format */
228         for (attribute=schema->attributes; attribute; attribute=attribute->next) {
229                 attribute->dn_format = dsdb_dn_oid_to_format(attribute->syntax->ldap_oid);
230
231                 if (attribute->dn_format == DSDB_INVALID_DN) {
232                         attribute->one_way_link = false;
233                         continue;
234                 }
235
236                 /* these are not considered to be one way links for
237                    the purpose of DN link fixups */
238                 if (ldb_attr_cmp("distinguishedName", attribute->lDAPDisplayName) == 0 ||
239                     ldb_attr_cmp("objectCategory", attribute->lDAPDisplayName) == 0) {
240                         attribute->one_way_link = false;
241                         continue;
242                 }
243
244                 if (attribute->linkID == 0) {
245                         attribute->one_way_link = true;
246                         continue;
247                 }
248                 /* handle attributes with a linkID but no backlink */
249                 if ((attribute->linkID & 1) == 0 &&
250                     dsdb_attribute_by_linkID(schema, attribute->linkID + 1) == NULL) {
251                         attribute->one_way_link = true;
252                         continue;
253                 }
254                 attribute->one_way_link = false;
255         }
256 }
257
258 static int uint32_cmp(uint32_t c1, uint32_t c2)
259 {
260         if (c1 == c2) return 0;
261         return c1 > c2 ? 1 : -1;
262 }
263
264 static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
265 {
266         return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
267 }
268 static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
269 {
270         return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id);
271 }
272 static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
273 {
274         return strcasecmp((*c1)->governsID_oid, (*c2)->governsID_oid);
275 }
276 static int dsdb_compare_class_by_cn(struct dsdb_class **c1, struct dsdb_class **c2)
277 {
278         return strcasecmp((*c1)->cn, (*c2)->cn);
279 }
280
281 static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
282 {
283         return strcasecmp((*a1)->lDAPDisplayName, (*a2)->lDAPDisplayName);
284 }
285 static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
286 {
287         return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id);
288 }
289 static int dsdb_compare_attribute_by_msDS_IntId(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
290 {
291         return uint32_cmp((*a1)->msDS_IntId, (*a2)->msDS_IntId);
292 }
293 static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
294 {
295         return strcasecmp((*a1)->attributeID_oid, (*a2)->attributeID_oid);
296 }
297 static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
298 {
299         return uint32_cmp((*a1)->linkID, (*a2)->linkID);
300 }
301
302 /**
303  * Clean up Classes and Attributes accessor arrays
304  */
305 static void dsdb_sorted_accessors_free(struct dsdb_schema *schema)
306 {
307         /* free classes accessors */
308         TALLOC_FREE(schema->classes_by_lDAPDisplayName);
309         TALLOC_FREE(schema->classes_by_governsID_id);
310         TALLOC_FREE(schema->classes_by_governsID_oid);
311         TALLOC_FREE(schema->classes_by_cn);
312         /* free attribute accessors */
313         TALLOC_FREE(schema->attributes_by_lDAPDisplayName);
314         TALLOC_FREE(schema->attributes_by_attributeID_id);
315         TALLOC_FREE(schema->attributes_by_msDS_IntId);
316         TALLOC_FREE(schema->attributes_by_attributeID_oid);
317         TALLOC_FREE(schema->attributes_by_linkID);
318 }
319
320 /*
321   create the sorted accessor arrays for the schema
322  */
323 int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
324                                 struct dsdb_schema *schema)
325 {
326         struct dsdb_class *cur;
327         struct dsdb_attribute *a;
328         unsigned int i;
329         unsigned int num_int_id;
330         int ret;
331
332         for (i=0; i < schema->classes_to_remove_size; i++) {
333                 DLIST_REMOVE(schema->classes, schema->classes_to_remove[i]);
334                 TALLOC_FREE(schema->classes_to_remove[i]);
335         }
336         for (i=0; i < schema->attributes_to_remove_size; i++) {
337                 DLIST_REMOVE(schema->attributes, schema->attributes_to_remove[i]);
338                 TALLOC_FREE(schema->attributes_to_remove[i]);
339         }
340
341         TALLOC_FREE(schema->attributes_to_remove);
342         TALLOC_FREE(schema->classes_to_remove);
343
344         /* free all caches */
345         dsdb_sorted_accessors_free(schema);
346
347         /* count the classes */
348         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) /* noop */ ;
349         schema->num_classes = i;
350
351         /* setup classes_by_* */
352         schema->classes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_class *, i);
353         schema->classes_by_governsID_id    = talloc_array(schema, struct dsdb_class *, i);
354         schema->classes_by_governsID_oid   = talloc_array(schema, struct dsdb_class *, i);
355         schema->classes_by_cn              = talloc_array(schema, struct dsdb_class *, i);
356         if (schema->classes_by_lDAPDisplayName == NULL ||
357             schema->classes_by_governsID_id == NULL ||
358             schema->classes_by_governsID_oid == NULL ||
359             schema->classes_by_cn == NULL) {
360                 goto failed;
361         }
362
363         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) {
364                 schema->classes_by_lDAPDisplayName[i] = cur;
365                 schema->classes_by_governsID_id[i]    = cur;
366                 schema->classes_by_governsID_oid[i]   = cur;
367                 schema->classes_by_cn[i]              = cur;
368         }
369
370         /* sort the arrays */
371         TYPESAFE_QSORT(schema->classes_by_lDAPDisplayName, schema->num_classes, dsdb_compare_class_by_lDAPDisplayName);
372         TYPESAFE_QSORT(schema->classes_by_governsID_id, schema->num_classes, dsdb_compare_class_by_governsID_id);
373         TYPESAFE_QSORT(schema->classes_by_governsID_oid, schema->num_classes, dsdb_compare_class_by_governsID_oid);
374         TYPESAFE_QSORT(schema->classes_by_cn, schema->num_classes, dsdb_compare_class_by_cn);
375
376         /* now build the attribute accessor arrays */
377
378         /* count the attributes
379          * and attributes with msDS-IntId set */
380         num_int_id = 0;
381         for (i=0, a=schema->attributes; a; i++, a=a->next) {
382                 if (a->msDS_IntId != 0) {
383                         num_int_id++;
384                 }
385         }
386         schema->num_attributes = i;
387         schema->num_int_id_attr = num_int_id;
388
389         /* setup attributes_by_* */
390         schema->attributes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_attribute *, i);
391         schema->attributes_by_attributeID_id    = talloc_array(schema, struct dsdb_attribute *, i);
392         schema->attributes_by_msDS_IntId        = talloc_array(schema,
393                                                                struct dsdb_attribute *, num_int_id);
394         schema->attributes_by_attributeID_oid   = talloc_array(schema, struct dsdb_attribute *, i);
395         schema->attributes_by_linkID              = talloc_array(schema, struct dsdb_attribute *, i);
396         if (schema->attributes_by_lDAPDisplayName == NULL ||
397             schema->attributes_by_attributeID_id == NULL ||
398             schema->attributes_by_msDS_IntId == NULL ||
399             schema->attributes_by_attributeID_oid == NULL ||
400             schema->attributes_by_linkID == NULL) {
401                 goto failed;
402         }
403
404         num_int_id = 0;
405         for (i=0, a=schema->attributes; a; i++, a=a->next) {
406                 schema->attributes_by_lDAPDisplayName[i] = a;
407                 schema->attributes_by_attributeID_id[i]    = a;
408                 schema->attributes_by_attributeID_oid[i]   = a;
409                 schema->attributes_by_linkID[i]          = a;
410                 /* append attr-by-msDS-IntId values */
411                 if (a->msDS_IntId != 0) {
412                         schema->attributes_by_msDS_IntId[num_int_id] = a;
413                         num_int_id++;
414                 }
415         }
416         SMB_ASSERT(num_int_id == schema->num_int_id_attr);
417
418         /* sort the arrays */
419         TYPESAFE_QSORT(schema->attributes_by_lDAPDisplayName, schema->num_attributes, dsdb_compare_attribute_by_lDAPDisplayName);
420         TYPESAFE_QSORT(schema->attributes_by_attributeID_id, schema->num_attributes, dsdb_compare_attribute_by_attributeID_id);
421         TYPESAFE_QSORT(schema->attributes_by_msDS_IntId, schema->num_int_id_attr, dsdb_compare_attribute_by_msDS_IntId);
422         TYPESAFE_QSORT(schema->attributes_by_attributeID_oid, schema->num_attributes, dsdb_compare_attribute_by_attributeID_oid);
423         TYPESAFE_QSORT(schema->attributes_by_linkID, schema->num_attributes, dsdb_compare_attribute_by_linkID);
424
425         dsdb_setup_attribute_shortcuts(ldb, schema);
426
427         ret = schema_fill_constructed(schema);
428         if (ret != LDB_SUCCESS) {
429                 dsdb_sorted_accessors_free(schema);
430                 return ret;
431         }
432
433         return LDB_SUCCESS;
434
435 failed:
436         dsdb_sorted_accessors_free(schema);
437         return ldb_oom(ldb);
438 }
439
440 /**
441  * Attach the schema to an opaque pointer on the ldb,
442  * so ldb modules can find it
443  */
444 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
445 {
446         struct dsdb_schema *old_schema;
447         int ret;
448
449         ret = dsdb_setup_sorted_accessors(ldb, schema);
450         if (ret != LDB_SUCCESS) {
451                 return ret;
452         }
453
454         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
455
456         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
457         if (ret != LDB_SUCCESS) {
458                 return ret;
459         }
460
461         /* Remove the reference to the schema we just overwrote - if there was
462          * none, NULL is harmless here */
463         if (old_schema != schema) {
464                 talloc_unlink(ldb, old_schema);
465                 talloc_steal(ldb, schema);
466         }
467
468         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
469         if (ret != LDB_SUCCESS) {
470                 return ret;
471         }
472
473         /* Set the new attributes based on the new schema */
474         ret = dsdb_schema_set_indices_and_attributes(ldb, schema, true);
475         if (ret != LDB_SUCCESS) {
476                 return ret;
477         }
478
479         return LDB_SUCCESS;
480 }
481
482 /**
483  * Global variable to hold one copy of the schema, used to avoid memory bloat
484  */
485 static struct dsdb_schema *global_schema;
486
487 /**
488  * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
489  *
490  * The write_indices_and_attributes controls writing of the @ records
491  * because we cannot write to a database that does not yet exist on
492  * disk.
493  */
494 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
495                           bool write_indices_and_attributes)
496 {
497         int ret;
498         struct dsdb_schema *old_schema;
499         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
500         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
501         if (ret != LDB_SUCCESS) {
502                 return ret;
503         }
504
505         /* Remove the reference to the schema we just overwrote - if there was
506          * none, NULL is harmless here */
507         talloc_unlink(ldb, old_schema);
508
509         if (talloc_reference(ldb, schema) == NULL) {
510                 return ldb_oom(ldb);
511         }
512
513         /* Make this ldb use local schema preferably */
514         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
515         if (ret != LDB_SUCCESS) {
516                 return ret;
517         }
518
519         ret = dsdb_schema_set_indices_and_attributes(ldb, schema, write_indices_and_attributes);
520         if (ret != LDB_SUCCESS) {
521                 return ret;
522         }
523
524         return LDB_SUCCESS;
525 }
526
527 /**
528  * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
529  */
530 int dsdb_set_global_schema(struct ldb_context *ldb)
531 {
532         int ret;
533         void *use_global_schema = (void *)1;
534         if (!global_schema) {
535                 return LDB_SUCCESS;
536         }
537         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", use_global_schema);
538         if (ret != LDB_SUCCESS) {
539                 return ret;
540         }
541
542         /* Set the new attributes based on the new schema */
543         ret = dsdb_schema_set_indices_and_attributes(ldb, global_schema, false /* Don't write indices and attributes, it's expensive */);
544         if (ret == LDB_SUCCESS) {
545                 /* Keep a reference to this schema, just in case the original copy is replaced */
546                 if (talloc_reference(ldb, global_schema) == NULL) {
547                         return ldb_oom(ldb);
548                 }
549         }
550
551         return ret;
552 }
553
554 bool dsdb_uses_global_schema(struct ldb_context *ldb)
555 {
556         return (ldb_get_opaque(ldb, "dsdb_use_global_schema") != NULL);
557 }
558
559 /**
560  * Find the schema object for this ldb
561  *
562  * If reference_ctx is not NULL, then talloc_reference onto that context
563  */
564
565 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *reference_ctx)
566 {
567         const void *p;
568         struct dsdb_schema *schema_out;
569         struct dsdb_schema *schema_in;
570         bool use_global_schema;
571         TALLOC_CTX *tmp_ctx = talloc_new(reference_ctx);
572         if (!tmp_ctx) {
573                 return NULL;
574         }
575
576         /* see if we have a cached copy */
577         use_global_schema = dsdb_uses_global_schema(ldb);
578         if (use_global_schema) {
579                 schema_in = global_schema;
580         } else {
581                 p = ldb_get_opaque(ldb, "dsdb_schema");
582
583                 schema_in = talloc_get_type(p, struct dsdb_schema);
584                 if (!schema_in) {
585                         talloc_free(tmp_ctx);
586                         return NULL;
587                 }
588         }
589
590         if (schema_in->refresh_fn && !schema_in->refresh_in_progress) {
591                 if (!talloc_reference(tmp_ctx, schema_in)) {
592                         /*
593                          * ensure that the schema_in->refresh_in_progress
594                          * remains valid for the right amount of time
595                          */
596                         talloc_free(tmp_ctx);
597                         return NULL;
598                 }
599                 schema_in->refresh_in_progress = true;
600                 /* This may change schema, if it needs to reload it from disk */
601                 schema_out = schema_in->refresh_fn(schema_in->loaded_from_module,
602                                                    schema_in,
603                                                    use_global_schema);
604                 schema_in->refresh_in_progress = false;
605         } else {
606                 schema_out = schema_in;
607         }
608
609         /* This removes the extra reference above */
610         talloc_free(tmp_ctx);
611         if (!reference_ctx) {
612                 return schema_out;
613         } else {
614                 return talloc_reference(reference_ctx, schema_out);
615         }
616 }
617
618 /**
619  * Make the schema found on this ldb the 'global' schema
620  */
621
622 void dsdb_make_schema_global(struct ldb_context *ldb, struct dsdb_schema *schema)
623 {
624         if (!schema) {
625                 return;
626         }
627
628         if (global_schema) {
629                 talloc_unlink(talloc_autofree_context(), global_schema);
630         }
631
632         /* we want the schema to be around permanently */
633         talloc_reparent(ldb, talloc_autofree_context(), schema);
634         global_schema = schema;
635
636         /* This calls the talloc_reference() of the global schema back onto the ldb */
637         dsdb_set_global_schema(ldb);
638 }
639
640 /**
641  * When loading the schema from LDIF files, we don't get the extended DNs.
642  *
643  * We need to set these up, so that from the moment we start the provision,
644  * the defaultObjectCategory links are set up correctly.
645  */
646 int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *schema)
647 {
648         struct dsdb_class *cur;
649         const struct dsdb_class *target_class;
650         for (cur = schema->classes; cur; cur = cur->next) {
651                 const struct ldb_val *rdn;
652                 struct ldb_val guid;
653                 NTSTATUS status;
654                 struct ldb_dn *dn = ldb_dn_new(NULL, ldb, cur->defaultObjectCategory);
655
656                 if (!dn) {
657                         return LDB_ERR_INVALID_DN_SYNTAX;
658                 }
659                 rdn = ldb_dn_get_component_val(dn, 0);
660                 if (!rdn) {
661                         talloc_free(dn);
662                         return LDB_ERR_INVALID_DN_SYNTAX;
663                 }
664                 target_class = dsdb_class_by_cn_ldb_val(schema, rdn);
665                 if (!target_class) {
666                         talloc_free(dn);
667                         return LDB_ERR_CONSTRAINT_VIOLATION;
668                 }
669
670                 status = GUID_to_ndr_blob(&target_class->objectGUID, dn, &guid);
671                 if (!NT_STATUS_IS_OK(status)) {
672                         talloc_free(dn);
673                         return ldb_operr(ldb);
674                 }
675                 ldb_dn_set_extended_component(dn, "GUID", &guid);
676
677                 cur->defaultObjectCategory = ldb_dn_get_extended_linearized(cur, dn, 1);
678                 talloc_free(dn);
679         }
680         return LDB_SUCCESS;
681 }
682
683 /**
684  * @brief Add a new element to the schema and checks if it's a duplicate
685  *
686  * This function will add a new element to the schema and checks for existing
687  * duplicates.
688  *
689  * @param[in]  ldb                A pointer to an LDB context
690  *
691  * @param[in]  schema             A pointer to the dsdb_schema where the element
692  *                                will be added.
693  *
694  * @param[in]  msg                The ldb_message object representing the element
695  *                                to add.
696  *
697  * @param[in]  checkdups          A boolean to indicate if checks for duplicates
698  *                                should be done.
699  *
700  * @return                        A WERROR code
701  */
702 WERROR dsdb_schema_set_el_from_ldb_msg_dups(struct ldb_context *ldb, struct dsdb_schema *schema,
703                                             struct ldb_message *msg, bool checkdups)
704 {
705         const char* tstring;
706         time_t ts;
707         tstring = ldb_msg_find_attr_as_string(msg, "whenChanged", NULL);
708         /* keep a trace of the ts of the most recently changed object */
709         if (tstring) {
710                 ts = ldb_string_to_time(tstring);
711                 if (ts > schema->ts_last_change) {
712                         schema->ts_last_change = ts;
713                 }
714         }
715         if (samdb_find_attribute(ldb, msg,
716                                  "objectclass", "attributeSchema") != NULL) {
717
718                 return dsdb_set_attribute_from_ldb_dups(ldb, schema, msg, checkdups);
719         } else if (samdb_find_attribute(ldb, msg,
720                                  "objectclass", "classSchema") != NULL) {
721                 return dsdb_set_class_from_ldb_dups(schema, msg, checkdups);
722         }
723         /* Don't fail on things not classes or attributes */
724         return WERR_OK;
725 }
726
727 WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb,
728                                        struct dsdb_schema *schema,
729                                        struct ldb_message *msg)
730 {
731         return dsdb_schema_set_el_from_ldb_msg_dups(ldb, schema, msg, false);
732 }
733
734 /**
735  * Rather than read a schema from the LDB itself, read it from an ldif
736  * file.  This allows schema to be loaded and used while adding the
737  * schema itself to the directory.
738  */
739
740 WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb,
741                                  const char *pf, const char *df,
742                                  const char *dn)
743 {
744         struct ldb_ldif *ldif;
745         struct ldb_message *msg;
746         TALLOC_CTX *mem_ctx;
747         WERROR status;
748         int ret;
749         struct dsdb_schema *schema;
750         const struct ldb_val *prefix_val;
751         const struct ldb_val *info_val;
752         struct ldb_val info_val_default;
753
754
755         mem_ctx = talloc_new(ldb);
756         if (!mem_ctx) {
757                 goto nomem;
758         }
759
760         schema = dsdb_new_schema(mem_ctx);
761         if (!schema) {
762                 goto nomem;
763         }
764         schema->base_dn = ldb_dn_new(schema, ldb, dn);
765         if (!schema->base_dn) {
766                 goto nomem;
767         }
768         schema->fsmo.we_are_master = true;
769         schema->fsmo.update_allowed = true;
770         schema->fsmo.master_dn = ldb_dn_new(schema, ldb, "@PROVISION_SCHEMA_MASTER");
771         if (!schema->fsmo.master_dn) {
772                 goto nomem;
773         }
774
775         /*
776          * load the prefixMap attribute from pf
777          */
778         ldif = ldb_ldif_read_string(ldb, &pf);
779         if (!ldif) {
780                 status = WERR_INVALID_PARAM;
781                 goto failed;
782         }
783         talloc_steal(mem_ctx, ldif);
784
785         ret = ldb_msg_normalize(ldb, mem_ctx, ldif->msg, &msg);
786         if (ret != LDB_SUCCESS) {
787                 goto nomem;
788         }
789         talloc_free(ldif);
790
791         prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
792         if (!prefix_val) {
793                 status = WERR_INVALID_PARAM;
794                 goto failed;
795         }
796
797         info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
798         if (!info_val) {
799                 status = dsdb_schema_info_blob_new(mem_ctx, &info_val_default);
800                 W_ERROR_NOT_OK_GOTO(status, failed);
801                 info_val = &info_val_default;
802         }
803
804         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
805         if (!W_ERROR_IS_OK(status)) {
806                 DEBUG(0,("ERROR: dsdb_load_oid_mappings_ldb() failed with %s\n", win_errstr(status)));
807                 goto failed;
808         }
809
810         schema->ts_last_change = 0;
811         /* load the attribute and class definitions out of df */
812         while ((ldif = ldb_ldif_read_string(ldb, &df))) {
813                 talloc_steal(mem_ctx, ldif);
814
815                 ret = ldb_msg_normalize(ldb, ldif, ldif->msg, &msg);
816                 if (ret != LDB_SUCCESS) {
817                         goto nomem;
818                 }
819
820                 status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, msg);
821                 talloc_free(ldif);
822                 if (!W_ERROR_IS_OK(status)) {
823                         goto failed;
824                 }
825         }
826
827         ret = dsdb_set_schema(ldb, schema);
828         if (ret != LDB_SUCCESS) {
829                 status = WERR_FOOBAR;
830                 goto failed;
831         }
832
833         ret = dsdb_schema_fill_extended_dn(ldb, schema);
834         if (ret != LDB_SUCCESS) {
835                 status = WERR_FOOBAR;
836                 goto failed;
837         }
838
839         goto done;
840
841 nomem:
842         status = WERR_NOMEM;
843 failed:
844 done:
845         talloc_free(mem_ctx);
846         return status;
847 }