2 Unix SMB/CIFS implementation.
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
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.
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.
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/>.
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"
33 /* change this when we change something in our schema code that
34 * requires a re-index of the database
36 #define SAMDB_INDEXING_VERSION "2"
39 override the name to attribute handler function
41 const struct ldb_schema_attribute
*dsdb_attribute_handler_override(struct ldb_context
*ldb
,
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
);
48 /* this will fall back to ldb internal handling */
51 return a
->ldb_schema_attribute
;
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.
59 static int dsdb_schema_set_indices_and_attributes(struct ldb_context
*ldb
, struct dsdb_schema
*schema
, bool write_indices_and_attributes
)
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
;
67 struct ldb_message
*msg
;
68 struct ldb_message
*msg_idx
;
70 /* setup our own attribute name to schema handler */
71 ldb_schema_attribute_set_override_handler(ldb
, dsdb_attribute_handler_override
, schema
);
73 if (!write_indices_and_attributes
) {
77 mem_ctx
= talloc_new(ldb
);
82 msg
= ldb_msg_new(mem_ctx
);
87 msg_idx
= ldb_msg_new(mem_ctx
);
92 msg
->dn
= ldb_dn_new(msg
, ldb
, "@ATTRIBUTES");
97 msg_idx
->dn
= ldb_dn_new(msg_idx
, ldb
, "@INDEXLIST");
103 ret
= ldb_msg_add_string(msg_idx
, "@IDXONE", "1");
104 if (ret
!= LDB_SUCCESS
) {
109 ret
= ldb_msg_add_string(msg_idx
, "@IDXVERSION", SAMDB_INDEXING_VERSION
);
110 if (ret
!= LDB_SUCCESS
) {
114 for (attr
= schema
->attributes
; attr
; attr
= attr
->next
) {
115 const char *syntax
= attr
->syntax
->ldb_syntax
;
118 syntax
= attr
->syntax
->ldap_oid
;
122 * Write out a rough approximation of the schema
123 * as an @ATTRIBUTES value, for bootstrapping
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");
130 if (ret
!= LDB_SUCCESS
) {
134 if (attr
->searchFlags
& SEARCH_FLAG_ATTINDEX
) {
135 ret
= ldb_msg_add_string(msg_idx
, "@IDXATTR", attr
->lDAPDisplayName
);
136 if (ret
!= LDB_SUCCESS
) {
142 if (ret
!= LDB_SUCCESS
) {
143 talloc_free(mem_ctx
);
148 * Try to avoid churning the attributes too much,
149 * we only want to do this if they have changed
151 ret
= ldb_search(ldb
, mem_ctx
, &res
, msg
->dn
, LDB_SCOPE_BASE
, 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
);
160 /* Annoyingly added to our search results */
161 ldb_msg_remove_attr(res
->msgs
[0], "distinguishedName");
163 ret
= ldb_msg_difference(ldb
, mem_ctx
,
164 res
->msgs
[0], msg
, &mod_msg
);
165 if (ret
!= LDB_SUCCESS
) {
168 if (mod_msg
->num_elements
> 0) {
169 ret
= dsdb_replace(ldb
, mod_msg
, 0);
171 talloc_free(mod_msg
);
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 */
178 if (ret
!= LDB_SUCCESS
) {
179 talloc_free(mem_ctx
);
183 /* Now write out the indexes, as found in the schema (if they have changed) */
185 ret
= ldb_search(ldb
, mem_ctx
, &res_idx
, msg_idx
->dn
, LDB_SCOPE_BASE
,
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
);
194 /* Annoyingly added to our search results */
195 ldb_msg_remove_attr(res_idx
->msgs
[0], "distinguishedName");
197 ret
= ldb_msg_difference(ldb
, mem_ctx
,
198 res_idx
->msgs
[0], msg_idx
, &mod_msg
);
199 if (ret
!= LDB_SUCCESS
) {
202 if (mod_msg
->num_elements
> 0) {
203 ret
= dsdb_replace(ldb
, mod_msg
, 0);
205 talloc_free(mod_msg
);
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 */
211 talloc_free(mem_ctx
);
215 talloc_free(mem_ctx
);
216 return ldb_operr(ldb
);
221 create extra attribute shortcuts
223 static void dsdb_setup_attribute_shortcuts(struct ldb_context
*ldb
, struct dsdb_schema
*schema
)
225 struct dsdb_attribute
*attribute
;
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
);
231 if (attribute
->dn_format
== DSDB_INVALID_DN
) {
232 attribute
->one_way_link
= false;
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;
244 if (attribute
->linkID
== 0) {
245 attribute
->one_way_link
= true;
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;
254 attribute
->one_way_link
= false;
258 static int uint32_cmp(uint32_t c1
, uint32_t c2
)
260 if (c1
== c2
) return 0;
261 return c1
> c2
? 1 : -1;
264 static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
266 return strcasecmp((*c1
)->lDAPDisplayName
, (*c2
)->lDAPDisplayName
);
268 static int dsdb_compare_class_by_governsID_id(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
270 return uint32_cmp((*c1
)->governsID_id
, (*c2
)->governsID_id
);
272 static int dsdb_compare_class_by_governsID_oid(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
274 return strcasecmp((*c1
)->governsID_oid
, (*c2
)->governsID_oid
);
276 static int dsdb_compare_class_by_cn(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
278 return strcasecmp((*c1
)->cn
, (*c2
)->cn
);
281 static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
283 return strcasecmp((*a1
)->lDAPDisplayName
, (*a2
)->lDAPDisplayName
);
285 static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
287 return uint32_cmp((*a1
)->attributeID_id
, (*a2
)->attributeID_id
);
289 static int dsdb_compare_attribute_by_msDS_IntId(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
291 return uint32_cmp((*a1
)->msDS_IntId
, (*a2
)->msDS_IntId
);
293 static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
295 return strcasecmp((*a1
)->attributeID_oid
, (*a2
)->attributeID_oid
);
297 static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
299 return uint32_cmp((*a1
)->linkID
, (*a2
)->linkID
);
303 * Clean up Classes and Attributes accessor arrays
305 static void dsdb_sorted_accessors_free(struct dsdb_schema
*schema
)
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
);
321 create the sorted accessor arrays for the schema
323 int dsdb_setup_sorted_accessors(struct ldb_context
*ldb
,
324 struct dsdb_schema
*schema
)
326 struct dsdb_class
*cur
;
327 struct dsdb_attribute
*a
;
329 unsigned int num_int_id
;
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
]);
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
]);
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;
346 /* free all caches */
347 dsdb_sorted_accessors_free(schema
);
349 /* count the classes */
350 for (i
=0, cur
=schema
->classes
; cur
; i
++, cur
=cur
->next
) /* noop */ ;
351 schema
->num_classes
= i
;
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
) {
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
;
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
);
378 /* now build the attribute accessor arrays */
380 /* count the attributes
381 * and attributes with msDS-IntId set */
383 for (i
=0, a
=schema
->attributes
; a
; i
++, a
=a
->next
) {
384 if (a
->msDS_IntId
!= 0) {
388 schema
->num_attributes
= i
;
389 schema
->num_int_id_attr
= num_int_id
;
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
) {
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
;
418 SMB_ASSERT(num_int_id
== schema
->num_int_id_attr
);
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
);
427 dsdb_setup_attribute_shortcuts(ldb
, schema
);
429 ret
= schema_fill_constructed(schema
);
430 if (ret
!= LDB_SUCCESS
) {
431 dsdb_sorted_accessors_free(schema
);
438 dsdb_sorted_accessors_free(schema
);
443 * Attach the schema to an opaque pointer on the ldb,
444 * so ldb modules can find it
446 int dsdb_set_schema_refresh_function(struct ldb_context
*ldb
,
447 dsdb_schema_refresh_fn refresh_fn
,
448 struct ldb_module
*module
)
450 int ret
= ldb_set_opaque(ldb
, "dsdb_schema_refresh_fn", refresh_fn
);
451 if (ret
!= LDB_SUCCESS
) {
455 ret
= ldb_set_opaque(ldb
, "dsdb_schema_refresh_fn_private_data", module
);
456 if (ret
!= LDB_SUCCESS
) {
463 * Attach the schema to an opaque pointer on the ldb,
464 * so ldb modules can find it
466 int dsdb_set_schema(struct ldb_context
*ldb
, struct dsdb_schema
*schema
)
468 struct dsdb_schema
*old_schema
;
471 ret
= dsdb_setup_sorted_accessors(ldb
, schema
);
472 if (ret
!= LDB_SUCCESS
) {
476 old_schema
= ldb_get_opaque(ldb
, "dsdb_schema");
478 ret
= ldb_set_opaque(ldb
, "dsdb_schema", schema
);
479 if (ret
!= LDB_SUCCESS
) {
483 /* Remove the reference to the schema we just overwrote - if there was
484 * none, NULL is harmless here */
485 if (old_schema
!= schema
) {
486 talloc_unlink(ldb
, old_schema
);
487 talloc_steal(ldb
, schema
);
490 talloc_steal(ldb
, schema
);
492 ret
= ldb_set_opaque(ldb
, "dsdb_use_global_schema", NULL
);
493 if (ret
!= LDB_SUCCESS
) {
497 /* Set the new attributes based on the new schema */
498 ret
= dsdb_schema_set_indices_and_attributes(ldb
, schema
, true);
499 if (ret
!= LDB_SUCCESS
) {
507 * Global variable to hold one copy of the schema, used to avoid memory bloat
509 static struct dsdb_schema
*global_schema
;
512 * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
514 * The write_indices_and_attributes controls writing of the @ records
515 * because we cannot write to a database that does not yet exist on
518 int dsdb_reference_schema(struct ldb_context
*ldb
, struct dsdb_schema
*schema
,
519 bool write_indices_and_attributes
)
522 struct dsdb_schema
*old_schema
;
523 old_schema
= ldb_get_opaque(ldb
, "dsdb_schema");
524 ret
= ldb_set_opaque(ldb
, "dsdb_schema", schema
);
525 if (ret
!= LDB_SUCCESS
) {
529 /* Remove the reference to the schema we just overwrote - if there was
530 * none, NULL is harmless here */
531 talloc_unlink(ldb
, old_schema
);
533 if (talloc_reference(ldb
, schema
) == NULL
) {
537 /* Make this ldb use local schema preferably */
538 ret
= ldb_set_opaque(ldb
, "dsdb_use_global_schema", NULL
);
539 if (ret
!= LDB_SUCCESS
) {
543 ret
= ldb_set_opaque(ldb
, "dsdb_refresh_fn", NULL
);
544 if (ret
!= LDB_SUCCESS
) {
548 ret
= ldb_set_opaque(ldb
, "dsdb_refresh_fn_private_data", NULL
);
549 if (ret
!= LDB_SUCCESS
) {
553 ret
= dsdb_schema_set_indices_and_attributes(ldb
, schema
, write_indices_and_attributes
);
554 if (ret
!= LDB_SUCCESS
) {
562 * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
564 int dsdb_set_global_schema(struct ldb_context
*ldb
)
567 void *use_global_schema
= (void *)1;
568 ret
= ldb_set_opaque(ldb
, "dsdb_use_global_schema", use_global_schema
);
569 if (ret
!= LDB_SUCCESS
) {
573 if (global_schema
== NULL
) {
577 /* Set the new attributes based on the new schema */
578 ret
= dsdb_schema_set_indices_and_attributes(ldb
, global_schema
, false /* Don't write indices and attributes, it's expensive */);
579 if (ret
== LDB_SUCCESS
) {
580 /* Keep a reference to this schema, just in case the original copy is replaced */
581 if (talloc_reference(ldb
, global_schema
) == NULL
) {
589 bool dsdb_uses_global_schema(struct ldb_context
*ldb
)
591 return (ldb_get_opaque(ldb
, "dsdb_use_global_schema") != NULL
);
595 * Find the schema object for this ldb
597 * If reference_ctx is not NULL, then talloc_reference onto that context
600 struct dsdb_schema
*dsdb_get_schema(struct ldb_context
*ldb
, TALLOC_CTX
*reference_ctx
)
603 struct dsdb_schema
*schema_out
= NULL
;
604 struct dsdb_schema
*schema_in
= NULL
;
605 dsdb_schema_refresh_fn refresh_fn
;
606 struct ldb_module
*loaded_from_module
;
607 bool use_global_schema
;
608 TALLOC_CTX
*tmp_ctx
= talloc_new(reference_ctx
);
609 if (tmp_ctx
== NULL
) {
613 /* see if we have a cached copy */
614 use_global_schema
= dsdb_uses_global_schema(ldb
);
615 if (use_global_schema
) {
616 schema_in
= global_schema
;
618 p
= ldb_get_opaque(ldb
, "dsdb_schema");
620 schema_in
= talloc_get_type_abort(p
, struct dsdb_schema
);
624 refresh_fn
= ldb_get_opaque(ldb
, "dsdb_schema_refresh_fn");
626 loaded_from_module
= ldb_get_opaque(ldb
, "dsdb_schema_refresh_fn_private_data");
628 SMB_ASSERT(loaded_from_module
&& (ldb_module_get_ctx(loaded_from_module
) == ldb
));
632 /* We need to guard against recurisve calls here */
633 if (ldb_set_opaque(ldb
, "dsdb_schema_refresh_fn", NULL
) != LDB_SUCCESS
) {
634 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
635 "dsdb_get_schema: clearing dsdb_schema_refresh_fn failed");
637 schema_out
= refresh_fn(loaded_from_module
,
638 ldb_get_event_context(ldb
),
642 if (ldb_set_opaque(ldb
, "dsdb_schema_refresh_fn", refresh_fn
) != LDB_SUCCESS
) {
643 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
644 "dsdb_get_schema: re-setting dsdb_schema_refresh_fn failed");
647 schema_out
= schema_in
;
648 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
649 "dsdb_get_schema: refresh_fn() failed");
652 schema_out
= schema_in
;
655 /* This removes the extra reference above */
656 talloc_free(tmp_ctx
);
657 if (!reference_ctx
) {
660 return talloc_reference(reference_ctx
, schema_out
);
665 * Make the schema found on this ldb the 'global' schema
668 void dsdb_make_schema_global(struct ldb_context
*ldb
, struct dsdb_schema
*schema
)
675 talloc_unlink(talloc_autofree_context(), global_schema
);
678 /* we want the schema to be around permanently */
679 talloc_reparent(ldb
, talloc_autofree_context(), schema
);
680 global_schema
= schema
;
682 /* This calls the talloc_reference() of the global schema back onto the ldb */
683 dsdb_set_global_schema(ldb
);
687 * When loading the schema from LDIF files, we don't get the extended DNs.
689 * We need to set these up, so that from the moment we start the provision,
690 * the defaultObjectCategory links are set up correctly.
692 int dsdb_schema_fill_extended_dn(struct ldb_context
*ldb
, struct dsdb_schema
*schema
)
694 struct dsdb_class
*cur
;
695 const struct dsdb_class
*target_class
;
696 for (cur
= schema
->classes
; cur
; cur
= cur
->next
) {
697 const struct ldb_val
*rdn
;
700 struct ldb_dn
*dn
= ldb_dn_new(NULL
, ldb
, cur
->defaultObjectCategory
);
703 return LDB_ERR_INVALID_DN_SYNTAX
;
705 rdn
= ldb_dn_get_component_val(dn
, 0);
708 return LDB_ERR_INVALID_DN_SYNTAX
;
710 target_class
= dsdb_class_by_cn_ldb_val(schema
, rdn
);
713 return LDB_ERR_CONSTRAINT_VIOLATION
;
716 status
= GUID_to_ndr_blob(&target_class
->objectGUID
, dn
, &guid
);
717 if (!NT_STATUS_IS_OK(status
)) {
719 return ldb_operr(ldb
);
721 ldb_dn_set_extended_component(dn
, "GUID", &guid
);
723 cur
->defaultObjectCategory
= ldb_dn_get_extended_linearized(cur
, dn
, 1);
730 * @brief Add a new element to the schema and checks if it's a duplicate
732 * This function will add a new element to the schema and checks for existing
735 * @param[in] ldb A pointer to an LDB context
737 * @param[in] schema A pointer to the dsdb_schema where the element
740 * @param[in] msg The ldb_message object representing the element
743 * @param[in] checkdups A boolean to indicate if checks for duplicates
746 * @return A WERROR code
748 WERROR
dsdb_schema_set_el_from_ldb_msg_dups(struct ldb_context
*ldb
, struct dsdb_schema
*schema
,
749 struct ldb_message
*msg
, bool checkdups
)
753 tstring
= ldb_msg_find_attr_as_string(msg
, "whenChanged", NULL
);
754 /* keep a trace of the ts of the most recently changed object */
756 ts
= ldb_string_to_time(tstring
);
757 if (ts
> schema
->ts_last_change
) {
758 schema
->ts_last_change
= ts
;
761 if (samdb_find_attribute(ldb
, msg
,
762 "objectclass", "attributeSchema") != NULL
) {
764 return dsdb_set_attribute_from_ldb_dups(ldb
, schema
, msg
, checkdups
);
765 } else if (samdb_find_attribute(ldb
, msg
,
766 "objectclass", "classSchema") != NULL
) {
767 return dsdb_set_class_from_ldb_dups(schema
, msg
, checkdups
);
769 /* Don't fail on things not classes or attributes */
773 WERROR
dsdb_schema_set_el_from_ldb_msg(struct ldb_context
*ldb
,
774 struct dsdb_schema
*schema
,
775 struct ldb_message
*msg
)
777 return dsdb_schema_set_el_from_ldb_msg_dups(ldb
, schema
, msg
, false);
781 * Rather than read a schema from the LDB itself, read it from an ldif
782 * file. This allows schema to be loaded and used while adding the
783 * schema itself to the directory.
786 WERROR
dsdb_set_schema_from_ldif(struct ldb_context
*ldb
,
787 const char *pf
, const char *df
,
790 struct ldb_ldif
*ldif
;
791 struct ldb_message
*msg
;
795 struct dsdb_schema
*schema
;
796 const struct ldb_val
*prefix_val
;
797 const struct ldb_val
*info_val
;
798 struct ldb_val info_val_default
;
801 mem_ctx
= talloc_new(ldb
);
806 schema
= dsdb_new_schema(mem_ctx
);
810 schema
->fsmo
.we_are_master
= true;
811 schema
->fsmo
.update_allowed
= true;
812 schema
->fsmo
.master_dn
= ldb_dn_new(schema
, ldb
, "@PROVISION_SCHEMA_MASTER");
813 if (!schema
->fsmo
.master_dn
) {
818 * load the prefixMap attribute from pf
820 ldif
= ldb_ldif_read_string(ldb
, &pf
);
822 status
= WERR_INVALID_PARAM
;
825 talloc_steal(mem_ctx
, ldif
);
827 ret
= ldb_msg_normalize(ldb
, mem_ctx
, ldif
->msg
, &msg
);
828 if (ret
!= LDB_SUCCESS
) {
833 prefix_val
= ldb_msg_find_ldb_val(msg
, "prefixMap");
835 status
= WERR_INVALID_PARAM
;
839 info_val
= ldb_msg_find_ldb_val(msg
, "schemaInfo");
841 status
= dsdb_schema_info_blob_new(mem_ctx
, &info_val_default
);
842 W_ERROR_NOT_OK_GOTO(status
, failed
);
843 info_val
= &info_val_default
;
846 status
= dsdb_load_oid_mappings_ldb(schema
, prefix_val
, info_val
);
847 if (!W_ERROR_IS_OK(status
)) {
848 DEBUG(0,("ERROR: dsdb_load_oid_mappings_ldb() failed with %s\n", win_errstr(status
)));
852 schema
->ts_last_change
= 0;
853 /* load the attribute and class definitions out of df */
854 while ((ldif
= ldb_ldif_read_string(ldb
, &df
))) {
855 talloc_steal(mem_ctx
, ldif
);
857 ret
= ldb_msg_normalize(ldb
, ldif
, ldif
->msg
, &msg
);
858 if (ret
!= LDB_SUCCESS
) {
862 status
= dsdb_schema_set_el_from_ldb_msg(ldb
, schema
, msg
);
864 if (!W_ERROR_IS_OK(status
)) {
869 ret
= dsdb_set_schema(ldb
, schema
);
870 if (ret
!= LDB_SUCCESS
) {
871 status
= WERR_FOOBAR
;
875 ret
= dsdb_schema_fill_extended_dn(ldb
, schema
);
876 if (ret
!= LDB_SUCCESS
) {
877 status
= WERR_FOOBAR
;
887 talloc_free(mem_ctx
);