dsdb: reset schema->{classes,attributes}_to_remove_size to 0
[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->classes_to_remove);
342         schema->classes_to_remove_size = 0;
343         TALLOC_FREE(schema->attributes_to_remove);
344         schema->attributes_to_remove_size = 0;
345
346         /* free all caches */
347         dsdb_sorted_accessors_free(schema);
348
349         /* count the classes */
350         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) /* noop */ ;
351         schema->num_classes = i;
352
353         /* setup classes_by_* */
354         schema->classes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_class *, i);
355         schema->classes_by_governsID_id    = talloc_array(schema, struct dsdb_class *, i);
356         schema->classes_by_governsID_oid   = talloc_array(schema, struct dsdb_class *, i);
357         schema->classes_by_cn              = talloc_array(schema, struct dsdb_class *, i);
358         if (schema->classes_by_lDAPDisplayName == NULL ||
359             schema->classes_by_governsID_id == NULL ||
360             schema->classes_by_governsID_oid == NULL ||
361             schema->classes_by_cn == NULL) {
362                 goto failed;
363         }
364
365         for (i=0, cur=schema->classes; cur; i++, cur=cur->next) {
366                 schema->classes_by_lDAPDisplayName[i] = cur;
367                 schema->classes_by_governsID_id[i]    = cur;
368                 schema->classes_by_governsID_oid[i]   = cur;
369                 schema->classes_by_cn[i]              = cur;
370         }
371
372         /* sort the arrays */
373         TYPESAFE_QSORT(schema->classes_by_lDAPDisplayName, schema->num_classes, dsdb_compare_class_by_lDAPDisplayName);
374         TYPESAFE_QSORT(schema->classes_by_governsID_id, schema->num_classes, dsdb_compare_class_by_governsID_id);
375         TYPESAFE_QSORT(schema->classes_by_governsID_oid, schema->num_classes, dsdb_compare_class_by_governsID_oid);
376         TYPESAFE_QSORT(schema->classes_by_cn, schema->num_classes, dsdb_compare_class_by_cn);
377
378         /* now build the attribute accessor arrays */
379
380         /* count the attributes
381          * and attributes with msDS-IntId set */
382         num_int_id = 0;
383         for (i=0, a=schema->attributes; a; i++, a=a->next) {
384                 if (a->msDS_IntId != 0) {
385                         num_int_id++;
386                 }
387         }
388         schema->num_attributes = i;
389         schema->num_int_id_attr = num_int_id;
390
391         /* setup attributes_by_* */
392         schema->attributes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_attribute *, i);
393         schema->attributes_by_attributeID_id    = talloc_array(schema, struct dsdb_attribute *, i);
394         schema->attributes_by_msDS_IntId        = talloc_array(schema,
395                                                                struct dsdb_attribute *, num_int_id);
396         schema->attributes_by_attributeID_oid   = talloc_array(schema, struct dsdb_attribute *, i);
397         schema->attributes_by_linkID              = talloc_array(schema, struct dsdb_attribute *, i);
398         if (schema->attributes_by_lDAPDisplayName == NULL ||
399             schema->attributes_by_attributeID_id == NULL ||
400             schema->attributes_by_msDS_IntId == NULL ||
401             schema->attributes_by_attributeID_oid == NULL ||
402             schema->attributes_by_linkID == NULL) {
403                 goto failed;
404         }
405
406         num_int_id = 0;
407         for (i=0, a=schema->attributes; a; i++, a=a->next) {
408                 schema->attributes_by_lDAPDisplayName[i] = a;
409                 schema->attributes_by_attributeID_id[i]    = a;
410                 schema->attributes_by_attributeID_oid[i]   = a;
411                 schema->attributes_by_linkID[i]          = a;
412                 /* append attr-by-msDS-IntId values */
413                 if (a->msDS_IntId != 0) {
414                         schema->attributes_by_msDS_IntId[num_int_id] = a;
415                         num_int_id++;
416                 }
417         }
418         SMB_ASSERT(num_int_id == schema->num_int_id_attr);
419
420         /* sort the arrays */
421         TYPESAFE_QSORT(schema->attributes_by_lDAPDisplayName, schema->num_attributes, dsdb_compare_attribute_by_lDAPDisplayName);
422         TYPESAFE_QSORT(schema->attributes_by_attributeID_id, schema->num_attributes, dsdb_compare_attribute_by_attributeID_id);
423         TYPESAFE_QSORT(schema->attributes_by_msDS_IntId, schema->num_int_id_attr, dsdb_compare_attribute_by_msDS_IntId);
424         TYPESAFE_QSORT(schema->attributes_by_attributeID_oid, schema->num_attributes, dsdb_compare_attribute_by_attributeID_oid);
425         TYPESAFE_QSORT(schema->attributes_by_linkID, schema->num_attributes, dsdb_compare_attribute_by_linkID);
426
427         dsdb_setup_attribute_shortcuts(ldb, schema);
428
429         ret = schema_fill_constructed(schema);
430         if (ret != LDB_SUCCESS) {
431                 dsdb_sorted_accessors_free(schema);
432                 return ret;
433         }
434
435         return LDB_SUCCESS;
436
437 failed:
438         dsdb_sorted_accessors_free(schema);
439         return ldb_oom(ldb);
440 }
441
442 /**
443  * Attach the schema to an opaque pointer on the ldb,
444  * so ldb modules can find it
445  */
446 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
447 {
448         struct dsdb_schema *old_schema;
449         int ret;
450
451         ret = dsdb_setup_sorted_accessors(ldb, schema);
452         if (ret != LDB_SUCCESS) {
453                 return ret;
454         }
455
456         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
457
458         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
459         if (ret != LDB_SUCCESS) {
460                 return ret;
461         }
462
463         /* Remove the reference to the schema we just overwrote - if there was
464          * none, NULL is harmless here */
465         if (old_schema != schema) {
466                 talloc_unlink(ldb, old_schema);
467                 talloc_steal(ldb, schema);
468         }
469
470         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
471         if (ret != LDB_SUCCESS) {
472                 return ret;
473         }
474
475         /* Set the new attributes based on the new schema */
476         ret = dsdb_schema_set_indices_and_attributes(ldb, schema, true);
477         if (ret != LDB_SUCCESS) {
478                 return ret;
479         }
480
481         return LDB_SUCCESS;
482 }
483
484 /**
485  * Global variable to hold one copy of the schema, used to avoid memory bloat
486  */
487 static struct dsdb_schema *global_schema;
488
489 /**
490  * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
491  *
492  * The write_indices_and_attributes controls writing of the @ records
493  * because we cannot write to a database that does not yet exist on
494  * disk.
495  */
496 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
497                           bool write_indices_and_attributes)
498 {
499         int ret;
500         struct dsdb_schema *old_schema;
501         old_schema = ldb_get_opaque(ldb, "dsdb_schema");
502         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
503         if (ret != LDB_SUCCESS) {
504                 return ret;
505         }
506
507         /* Remove the reference to the schema we just overwrote - if there was
508          * none, NULL is harmless here */
509         talloc_unlink(ldb, old_schema);
510
511         if (talloc_reference(ldb, schema) == NULL) {
512                 return ldb_oom(ldb);
513         }
514
515         /* Make this ldb use local schema preferably */
516         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL);
517         if (ret != LDB_SUCCESS) {
518                 return ret;
519         }
520
521         ret = dsdb_schema_set_indices_and_attributes(ldb, schema, write_indices_and_attributes);
522         if (ret != LDB_SUCCESS) {
523                 return ret;
524         }
525
526         return LDB_SUCCESS;
527 }
528
529 /**
530  * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
531  */
532 int dsdb_set_global_schema(struct ldb_context *ldb)
533 {
534         int ret;
535         void *use_global_schema = (void *)1;
536         if (!global_schema) {
537                 return LDB_SUCCESS;
538         }
539         ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", use_global_schema);
540         if (ret != LDB_SUCCESS) {
541                 return ret;
542         }
543
544         /* Set the new attributes based on the new schema */
545         ret = dsdb_schema_set_indices_and_attributes(ldb, global_schema, false /* Don't write indices and attributes, it's expensive */);
546         if (ret == LDB_SUCCESS) {
547                 /* Keep a reference to this schema, just in case the original copy is replaced */
548                 if (talloc_reference(ldb, global_schema) == NULL) {
549                         return ldb_oom(ldb);
550                 }
551         }
552
553         return ret;
554 }
555
556 bool dsdb_uses_global_schema(struct ldb_context *ldb)
557 {
558         return (ldb_get_opaque(ldb, "dsdb_use_global_schema") != NULL);
559 }
560
561 /**
562  * Find the schema object for this ldb
563  *
564  * If reference_ctx is not NULL, then talloc_reference onto that context
565  */
566
567 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *reference_ctx)
568 {
569         const void *p;
570         struct dsdb_schema *schema_out;
571         struct dsdb_schema *schema_in;
572         bool use_global_schema;
573         TALLOC_CTX *tmp_ctx = talloc_new(reference_ctx);
574         if (!tmp_ctx) {
575                 return NULL;
576         }
577
578         /* see if we have a cached copy */
579         use_global_schema = dsdb_uses_global_schema(ldb);
580         if (use_global_schema) {
581                 schema_in = global_schema;
582         } else {
583                 p = ldb_get_opaque(ldb, "dsdb_schema");
584
585                 schema_in = talloc_get_type(p, struct dsdb_schema);
586                 if (!schema_in) {
587                         talloc_free(tmp_ctx);
588                         return NULL;
589                 }
590         }
591
592         if (schema_in->refresh_fn && !schema_in->refresh_in_progress) {
593                 if (!talloc_reference(tmp_ctx, schema_in)) {
594                         /*
595                          * ensure that the schema_in->refresh_in_progress
596                          * remains valid for the right amount of time
597                          */
598                         talloc_free(tmp_ctx);
599                         return NULL;
600                 }
601                 schema_in->refresh_in_progress = true;
602                 /* This may change schema, if it needs to reload it from disk */
603                 schema_out = schema_in->refresh_fn(schema_in->loaded_from_module,
604                                                    schema_in,
605                                                    use_global_schema);
606                 schema_in->refresh_in_progress = false;
607         } else {
608                 schema_out = schema_in;
609         }
610
611         /* This removes the extra reference above */
612         talloc_free(tmp_ctx);
613         if (!reference_ctx) {
614                 return schema_out;
615         } else {
616                 return talloc_reference(reference_ctx, schema_out);
617         }
618 }
619
620 /**
621  * Make the schema found on this ldb the 'global' schema
622  */
623
624 void dsdb_make_schema_global(struct ldb_context *ldb, struct dsdb_schema *schema)
625 {
626         if (!schema) {
627                 return;
628         }
629
630         if (global_schema) {
631                 talloc_unlink(talloc_autofree_context(), global_schema);
632         }
633
634         /* we want the schema to be around permanently */
635         talloc_reparent(ldb, talloc_autofree_context(), schema);
636         global_schema = schema;
637
638         /* This calls the talloc_reference() of the global schema back onto the ldb */
639         dsdb_set_global_schema(ldb);
640 }
641
642 /**
643  * When loading the schema from LDIF files, we don't get the extended DNs.
644  *
645  * We need to set these up, so that from the moment we start the provision,
646  * the defaultObjectCategory links are set up correctly.
647  */
648 int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *schema)
649 {
650         struct dsdb_class *cur;
651         const struct dsdb_class *target_class;
652         for (cur = schema->classes; cur; cur = cur->next) {
653                 const struct ldb_val *rdn;
654                 struct ldb_val guid;
655                 NTSTATUS status;
656                 struct ldb_dn *dn = ldb_dn_new(NULL, ldb, cur->defaultObjectCategory);
657
658                 if (!dn) {
659                         return LDB_ERR_INVALID_DN_SYNTAX;
660                 }
661                 rdn = ldb_dn_get_component_val(dn, 0);
662                 if (!rdn) {
663                         talloc_free(dn);
664                         return LDB_ERR_INVALID_DN_SYNTAX;
665                 }
666                 target_class = dsdb_class_by_cn_ldb_val(schema, rdn);
667                 if (!target_class) {
668                         talloc_free(dn);
669                         return LDB_ERR_CONSTRAINT_VIOLATION;
670                 }
671
672                 status = GUID_to_ndr_blob(&target_class->objectGUID, dn, &guid);
673                 if (!NT_STATUS_IS_OK(status)) {
674                         talloc_free(dn);
675                         return ldb_operr(ldb);
676                 }
677                 ldb_dn_set_extended_component(dn, "GUID", &guid);
678
679                 cur->defaultObjectCategory = ldb_dn_get_extended_linearized(cur, dn, 1);
680                 talloc_free(dn);
681         }
682         return LDB_SUCCESS;
683 }
684
685 /**
686  * @brief Add a new element to the schema and checks if it's a duplicate
687  *
688  * This function will add a new element to the schema and checks for existing
689  * duplicates.
690  *
691  * @param[in]  ldb                A pointer to an LDB context
692  *
693  * @param[in]  schema             A pointer to the dsdb_schema where the element
694  *                                will be added.
695  *
696  * @param[in]  msg                The ldb_message object representing the element
697  *                                to add.
698  *
699  * @param[in]  checkdups          A boolean to indicate if checks for duplicates
700  *                                should be done.
701  *
702  * @return                        A WERROR code
703  */
704 WERROR dsdb_schema_set_el_from_ldb_msg_dups(struct ldb_context *ldb, struct dsdb_schema *schema,
705                                             struct ldb_message *msg, bool checkdups)
706 {
707         const char* tstring;
708         time_t ts;
709         tstring = ldb_msg_find_attr_as_string(msg, "whenChanged", NULL);
710         /* keep a trace of the ts of the most recently changed object */
711         if (tstring) {
712                 ts = ldb_string_to_time(tstring);
713                 if (ts > schema->ts_last_change) {
714                         schema->ts_last_change = ts;
715                 }
716         }
717         if (samdb_find_attribute(ldb, msg,
718                                  "objectclass", "attributeSchema") != NULL) {
719
720                 return dsdb_set_attribute_from_ldb_dups(ldb, schema, msg, checkdups);
721         } else if (samdb_find_attribute(ldb, msg,
722                                  "objectclass", "classSchema") != NULL) {
723                 return dsdb_set_class_from_ldb_dups(schema, msg, checkdups);
724         }
725         /* Don't fail on things not classes or attributes */
726         return WERR_OK;
727 }
728
729 WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb,
730                                        struct dsdb_schema *schema,
731                                        struct ldb_message *msg)
732 {
733         return dsdb_schema_set_el_from_ldb_msg_dups(ldb, schema, msg, false);
734 }
735
736 /**
737  * Rather than read a schema from the LDB itself, read it from an ldif
738  * file.  This allows schema to be loaded and used while adding the
739  * schema itself to the directory.
740  */
741
742 WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb,
743                                  const char *pf, const char *df,
744                                  const char *dn)
745 {
746         struct ldb_ldif *ldif;
747         struct ldb_message *msg;
748         TALLOC_CTX *mem_ctx;
749         WERROR status;
750         int ret;
751         struct dsdb_schema *schema;
752         const struct ldb_val *prefix_val;
753         const struct ldb_val *info_val;
754         struct ldb_val info_val_default;
755
756
757         mem_ctx = talloc_new(ldb);
758         if (!mem_ctx) {
759                 goto nomem;
760         }
761
762         schema = dsdb_new_schema(mem_ctx);
763         if (!schema) {
764                 goto nomem;
765         }
766         schema->base_dn = ldb_dn_new(schema, ldb, dn);
767         if (!schema->base_dn) {
768                 goto nomem;
769         }
770         schema->fsmo.we_are_master = true;
771         schema->fsmo.update_allowed = true;
772         schema->fsmo.master_dn = ldb_dn_new(schema, ldb, "@PROVISION_SCHEMA_MASTER");
773         if (!schema->fsmo.master_dn) {
774                 goto nomem;
775         }
776
777         /*
778          * load the prefixMap attribute from pf
779          */
780         ldif = ldb_ldif_read_string(ldb, &pf);
781         if (!ldif) {
782                 status = WERR_INVALID_PARAM;
783                 goto failed;
784         }
785         talloc_steal(mem_ctx, ldif);
786
787         ret = ldb_msg_normalize(ldb, mem_ctx, ldif->msg, &msg);
788         if (ret != LDB_SUCCESS) {
789                 goto nomem;
790         }
791         talloc_free(ldif);
792
793         prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
794         if (!prefix_val) {
795                 status = WERR_INVALID_PARAM;
796                 goto failed;
797         }
798
799         info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
800         if (!info_val) {
801                 status = dsdb_schema_info_blob_new(mem_ctx, &info_val_default);
802                 W_ERROR_NOT_OK_GOTO(status, failed);
803                 info_val = &info_val_default;
804         }
805
806         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
807         if (!W_ERROR_IS_OK(status)) {
808                 DEBUG(0,("ERROR: dsdb_load_oid_mappings_ldb() failed with %s\n", win_errstr(status)));
809                 goto failed;
810         }
811
812         schema->ts_last_change = 0;
813         /* load the attribute and class definitions out of df */
814         while ((ldif = ldb_ldif_read_string(ldb, &df))) {
815                 talloc_steal(mem_ctx, ldif);
816
817                 ret = ldb_msg_normalize(ldb, ldif, ldif->msg, &msg);
818                 if (ret != LDB_SUCCESS) {
819                         goto nomem;
820                 }
821
822                 status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, msg);
823                 talloc_free(ldif);
824                 if (!W_ERROR_IS_OK(status)) {
825                         goto failed;
826                 }
827         }
828
829         ret = dsdb_set_schema(ldb, schema);
830         if (ret != LDB_SUCCESS) {
831                 status = WERR_FOOBAR;
832                 goto failed;
833         }
834
835         ret = dsdb_schema_fill_extended_dn(ldb, schema);
836         if (ret != LDB_SUCCESS) {
837                 status = WERR_FOOBAR;
838                 goto failed;
839         }
840
841         goto done;
842
843 nomem:
844         status = WERR_NOMEM;
845 failed:
846 done:
847         talloc_free(mem_ctx);
848         return status;
849 }