2 Unix SMB/CIFS mplementation.
5 Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/util/dlinklist.h"
25 #include "dsdb/samdb/samdb.h"
26 #include "lib/ldb/include/ldb_module.h"
27 #include "param/param.h"
30 override the name to attribute handler function
32 const struct ldb_schema_attribute
*dsdb_attribute_handler_override(struct ldb_context
*ldb
,
36 struct dsdb_schema
*schema
= talloc_get_type_abort(private_data
, struct dsdb_schema
);
37 const struct dsdb_attribute
*a
= dsdb_attribute_by_lDAPDisplayName(schema
, name
);
39 /* this will fall back to ldb internal handling */
42 return a
->ldb_schema_attribute
;
45 static int dsdb_schema_set_attributes(struct ldb_context
*ldb
, struct dsdb_schema
*schema
, bool write_attributes
)
47 int ret
= LDB_SUCCESS
;
48 struct ldb_result
*res
;
49 struct ldb_result
*res_idx
;
50 struct dsdb_attribute
*attr
;
51 struct ldb_message
*mod_msg
;
53 struct ldb_message
*msg
;
54 struct ldb_message
*msg_idx
;
56 /* setup our own attribute name to schema handler */
57 ldb_schema_attribute_set_override_handler(ldb
, dsdb_attribute_handler_override
, schema
);
59 if (!write_attributes
) {
63 mem_ctx
= talloc_new(ldb
);
65 return LDB_ERR_OPERATIONS_ERROR
;
68 msg
= ldb_msg_new(mem_ctx
);
73 msg_idx
= ldb_msg_new(mem_ctx
);
78 msg
->dn
= ldb_dn_new(msg
, ldb
, "@ATTRIBUTES");
83 msg_idx
->dn
= ldb_dn_new(msg
, ldb
, "@INDEXLIST");
89 ret
= ldb_msg_add_string(msg_idx
, "@IDXONE", "1");
90 if (ret
!= LDB_SUCCESS
) {
94 for (attr
= schema
->attributes
; attr
; attr
= attr
->next
) {
95 const char *syntax
= attr
->syntax
->ldb_syntax
;
98 syntax
= attr
->syntax
->ldap_oid
;
101 /* Write out a rough approximation of the schema as an @ATTRIBUTES value, for bootstrapping */
102 if (strcmp(syntax
, LDB_SYNTAX_INTEGER
) == 0) {
103 ret
= ldb_msg_add_string(msg
, attr
->lDAPDisplayName
, "INTEGER");
104 } else if (strcmp(syntax
, LDB_SYNTAX_DIRECTORY_STRING
) == 0) {
105 ret
= ldb_msg_add_string(msg
, attr
->lDAPDisplayName
, "CASE_INSENSITIVE");
107 if (ret
!= LDB_SUCCESS
) {
111 if (attr
->searchFlags
& SEARCH_FLAG_ATTINDEX
) {
112 ret
= ldb_msg_add_string(msg_idx
, "@IDXATTR", attr
->lDAPDisplayName
);
113 if (ret
!= LDB_SUCCESS
) {
119 if (ret
!= LDB_SUCCESS
) {
120 talloc_free(mem_ctx
);
124 /* Try to avoid churning the attributes too much - we only want to do this if they have changed */
125 ret
= ldb_search(ldb
, mem_ctx
, &res
, msg
->dn
, LDB_SCOPE_BASE
, NULL
, "dn=%s", ldb_dn_get_linearized(msg
->dn
));
126 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
127 ret
= ldb_add(ldb
, msg
);
128 } else if (ret
!= LDB_SUCCESS
) {
129 } else if (res
->count
!= 1) {
130 ret
= ldb_add(ldb
, msg
);
133 /* Annoyingly added to our search results */
134 ldb_msg_remove_attr(res
->msgs
[0], "distinguishedName");
136 mod_msg
= ldb_msg_diff(ldb
, res
->msgs
[0], msg
);
137 if (mod_msg
->num_elements
> 0) {
138 ret
= samdb_replace(ldb
, mem_ctx
, mod_msg
);
142 if (ret
== LDB_ERR_OPERATIONS_ERROR
|| ret
== LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
) {
143 /* We might be on a read-only DB */
146 if (ret
!= LDB_SUCCESS
) {
147 talloc_free(mem_ctx
);
151 /* Now write out the indexs, as found in the schema (if they have changed) */
153 ret
= ldb_search(ldb
, mem_ctx
, &res_idx
, msg_idx
->dn
, LDB_SCOPE_BASE
, NULL
, "dn=%s", ldb_dn_get_linearized(msg_idx
->dn
));
154 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
155 ret
= ldb_add(ldb
, msg_idx
);
156 } else if (ret
!= LDB_SUCCESS
) {
157 } else if (res_idx
->count
!= 1) {
158 ret
= ldb_add(ldb
, msg_idx
);
161 /* Annoyingly added to our search results */
162 ldb_msg_remove_attr(res_idx
->msgs
[0], "distinguishedName");
164 mod_msg
= ldb_msg_diff(ldb
, res_idx
->msgs
[0], msg_idx
);
165 if (mod_msg
->num_elements
> 0) {
166 ret
= samdb_replace(ldb
, mem_ctx
, mod_msg
);
169 if (ret
== LDB_ERR_OPERATIONS_ERROR
|| ret
== LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
) {
170 /* We might be on a read-only DB */
173 talloc_free(mem_ctx
);
177 talloc_free(mem_ctx
);
178 return LDB_ERR_OPERATIONS_ERROR
;
181 static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
183 return strcasecmp((*c1
)->lDAPDisplayName
, (*c2
)->lDAPDisplayName
);
185 static int dsdb_compare_class_by_governsID_id(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
187 return (*c1
)->governsID_id
- (*c2
)->governsID_id
;
189 static int dsdb_compare_class_by_governsID_oid(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
191 return strcasecmp((*c1
)->governsID_oid
, (*c2
)->governsID_oid
);
193 static int dsdb_compare_class_by_cn(struct dsdb_class
**c1
, struct dsdb_class
**c2
)
195 return strcasecmp((*c1
)->cn
, (*c2
)->cn
);
198 static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
200 return strcasecmp((*a1
)->lDAPDisplayName
, (*a2
)->lDAPDisplayName
);
202 static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
204 return (*a1
)->attributeID_id
- (*a2
)->attributeID_id
;
206 static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
208 return strcasecmp((*a1
)->attributeID_oid
, (*a2
)->attributeID_oid
);
210 static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute
**a1
, struct dsdb_attribute
**a2
)
212 return (*a1
)->linkID
- (*a2
)->linkID
;
216 create the sorted accessor arrays for the schema
218 static int dsdb_setup_sorted_accessors(struct ldb_context
*ldb
,
219 struct dsdb_schema
*schema
)
221 struct dsdb_class
*cur
;
222 struct dsdb_attribute
*a
;
225 talloc_free(schema
->classes_by_lDAPDisplayName
);
226 talloc_free(schema
->classes_by_governsID_id
);
227 talloc_free(schema
->classes_by_governsID_oid
);
228 talloc_free(schema
->classes_by_cn
);
230 /* count the classes */
231 for (i
=0, cur
=schema
->classes
; cur
; i
++, cur
=cur
->next
) /* noop */ ;
232 schema
->num_classes
= i
;
234 /* setup classes_by_* */
235 schema
->classes_by_lDAPDisplayName
= talloc_array(schema
, struct dsdb_class
*, i
);
236 schema
->classes_by_governsID_id
= talloc_array(schema
, struct dsdb_class
*, i
);
237 schema
->classes_by_governsID_oid
= talloc_array(schema
, struct dsdb_class
*, i
);
238 schema
->classes_by_cn
= talloc_array(schema
, struct dsdb_class
*, i
);
239 if (schema
->classes_by_lDAPDisplayName
== NULL
||
240 schema
->classes_by_governsID_id
== NULL
||
241 schema
->classes_by_governsID_oid
== NULL
||
242 schema
->classes_by_cn
== NULL
) {
246 for (i
=0, cur
=schema
->classes
; cur
; i
++, cur
=cur
->next
) {
247 schema
->classes_by_lDAPDisplayName
[i
] = cur
;
248 schema
->classes_by_governsID_id
[i
] = cur
;
249 schema
->classes_by_governsID_oid
[i
] = cur
;
250 schema
->classes_by_cn
[i
] = cur
;
253 /* sort the arrays */
254 qsort(schema
->classes_by_lDAPDisplayName
, schema
->num_classes
,
255 sizeof(struct dsdb_class
*), QSORT_CAST dsdb_compare_class_by_lDAPDisplayName
);
256 qsort(schema
->classes_by_governsID_id
, schema
->num_classes
,
257 sizeof(struct dsdb_class
*), QSORT_CAST dsdb_compare_class_by_governsID_id
);
258 qsort(schema
->classes_by_governsID_oid
, schema
->num_classes
,
259 sizeof(struct dsdb_class
*), QSORT_CAST dsdb_compare_class_by_governsID_oid
);
260 qsort(schema
->classes_by_cn
, schema
->num_classes
,
261 sizeof(struct dsdb_class
*), QSORT_CAST dsdb_compare_class_by_cn
);
263 /* now build the attribute accessor arrays */
264 talloc_free(schema
->attributes_by_lDAPDisplayName
);
265 talloc_free(schema
->attributes_by_attributeID_id
);
266 talloc_free(schema
->attributes_by_attributeID_oid
);
267 talloc_free(schema
->attributes_by_linkID
);
269 /* count the attributes */
270 for (i
=0, a
=schema
->attributes
; a
; i
++, a
=a
->next
) /* noop */ ;
271 schema
->num_attributes
= i
;
273 /* setup attributes_by_* */
274 schema
->attributes_by_lDAPDisplayName
= talloc_array(schema
, struct dsdb_attribute
*, i
);
275 schema
->attributes_by_attributeID_id
= talloc_array(schema
, struct dsdb_attribute
*, i
);
276 schema
->attributes_by_attributeID_oid
= talloc_array(schema
, struct dsdb_attribute
*, i
);
277 schema
->attributes_by_linkID
= talloc_array(schema
, struct dsdb_attribute
*, i
);
278 if (schema
->attributes_by_lDAPDisplayName
== NULL
||
279 schema
->attributes_by_attributeID_id
== NULL
||
280 schema
->attributes_by_attributeID_oid
== NULL
||
281 schema
->attributes_by_linkID
== NULL
) {
285 for (i
=0, a
=schema
->attributes
; a
; i
++, a
=a
->next
) {
286 schema
->attributes_by_lDAPDisplayName
[i
] = a
;
287 schema
->attributes_by_attributeID_id
[i
] = a
;
288 schema
->attributes_by_attributeID_oid
[i
] = a
;
289 schema
->attributes_by_linkID
[i
] = a
;
292 /* sort the arrays */
293 qsort(schema
->attributes_by_lDAPDisplayName
, schema
->num_attributes
,
294 sizeof(struct dsdb_attribute
*), QSORT_CAST dsdb_compare_attribute_by_lDAPDisplayName
);
295 qsort(schema
->attributes_by_attributeID_id
, schema
->num_attributes
,
296 sizeof(struct dsdb_attribute
*), QSORT_CAST dsdb_compare_attribute_by_attributeID_id
);
297 qsort(schema
->attributes_by_attributeID_oid
, schema
->num_attributes
,
298 sizeof(struct dsdb_attribute
*), QSORT_CAST dsdb_compare_attribute_by_attributeID_oid
);
299 qsort(schema
->attributes_by_linkID
, schema
->num_attributes
,
300 sizeof(struct dsdb_attribute
*), QSORT_CAST dsdb_compare_attribute_by_linkID
);
305 schema
->classes_by_lDAPDisplayName
= NULL
;
306 schema
->classes_by_governsID_id
= NULL
;
307 schema
->classes_by_governsID_oid
= NULL
;
308 schema
->classes_by_cn
= NULL
;
309 schema
->attributes_by_lDAPDisplayName
= NULL
;
310 schema
->attributes_by_attributeID_id
= NULL
;
311 schema
->attributes_by_attributeID_oid
= NULL
;
312 schema
->attributes_by_linkID
= NULL
;
314 return LDB_ERR_OPERATIONS_ERROR
;
317 int dsdb_setup_schema_inversion(struct ldb_context
*ldb
, struct dsdb_schema
*schema
)
319 /* Walk the list of schema classes */
321 /* For each subClassOf, add us to subclasses of the parent */
323 /* collect these subclasses into a recursive list of total subclasses, preserving order */
325 /* For each subclass under 'top', write the index from it's
326 * order as an integer in the dsdb_class (for sorting
327 * objectClass lists efficiently) */
329 /* Walk the list of scheam classes */
331 /* Create a 'total possible superiors' on each class */
336 * Attach the schema to an opaque pointer on the ldb, so ldb modules
340 int dsdb_set_schema(struct ldb_context
*ldb
, struct dsdb_schema
*schema
)
344 ret
= dsdb_setup_sorted_accessors(ldb
, schema
);
345 if (ret
!= LDB_SUCCESS
) {
349 schema_fill_constructed(schema
);
351 ret
= ldb_set_opaque(ldb
, "dsdb_schema", schema
);
352 if (ret
!= LDB_SUCCESS
) {
356 /* Set the new attributes based on the new schema */
357 ret
= dsdb_schema_set_attributes(ldb
, schema
, true);
358 if (ret
!= LDB_SUCCESS
) {
362 talloc_steal(ldb
, schema
);
368 * Global variable to hold one copy of the schema, used to avoid memory bloat
370 static struct dsdb_schema
*global_schema
;
373 * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
375 int dsdb_reference_schema(struct ldb_context
*ldb
, struct dsdb_schema
*schema
,
376 bool write_attributes
)
379 ret
= ldb_set_opaque(ldb
, "dsdb_schema", schema
);
380 if (ret
!= LDB_SUCCESS
) {
384 /* Set the new attributes based on the new schema */
385 ret
= dsdb_schema_set_attributes(ldb
, schema
, write_attributes
);
386 if (ret
!= LDB_SUCCESS
) {
390 /* Keep a reference to this schema, just incase the original copy is replaced */
391 if (talloc_reference(ldb
, schema
) == NULL
) {
392 return LDB_ERR_OPERATIONS_ERROR
;
399 * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
401 int dsdb_set_global_schema(struct ldb_context
*ldb
)
403 if (!global_schema
) {
407 return dsdb_reference_schema(ldb
, global_schema
, false /* Don't write attributes, it's expensive */);
411 * Find the schema object for this ldb
414 struct dsdb_schema
*dsdb_get_schema(struct ldb_context
*ldb
)
417 struct dsdb_schema
*schema
;
419 /* see if we have a cached copy */
420 p
= ldb_get_opaque(ldb
, "dsdb_schema");
425 schema
= talloc_get_type(p
, struct dsdb_schema
);
434 * Make the schema found on this ldb the 'global' schema
437 void dsdb_make_schema_global(struct ldb_context
*ldb
)
439 struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
445 talloc_unlink(talloc_autofree_context(), global_schema
);
448 /* we want the schema to be around permanently */
449 talloc_reparent(talloc_parent(schema
), talloc_autofree_context(), schema
);
451 global_schema
= schema
;
453 dsdb_set_global_schema(ldb
);
458 * Rather than read a schema from the LDB itself, read it from an ldif
459 * file. This allows schema to be loaded and used while adding the
460 * schema itself to the directory.
463 WERROR
dsdb_set_schema_from_ldif(struct ldb_context
*ldb
, const char *pf
, const char *df
)
465 struct ldb_ldif
*ldif
;
466 struct ldb_message
*msg
;
470 struct dsdb_schema
*schema
;
471 const struct ldb_val
*prefix_val
;
472 const struct ldb_val
*info_val
;
473 struct ldb_val info_val_default
;
475 mem_ctx
= talloc_new(ldb
);
480 schema
= dsdb_new_schema(mem_ctx
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")));
482 schema
->fsmo
.we_are_master
= true;
483 schema
->fsmo
.master_dn
= ldb_dn_new_fmt(schema
, ldb
, "@PROVISION_SCHEMA_MASTER");
484 if (!schema
->fsmo
.master_dn
) {
489 * load the prefixMap attribute from pf
491 ldif
= ldb_ldif_read_string(ldb
, &pf
);
493 status
= WERR_INVALID_PARAM
;
496 talloc_steal(mem_ctx
, ldif
);
498 msg
= ldb_msg_canonicalize(ldb
, ldif
->msg
);
502 talloc_steal(mem_ctx
, msg
);
505 prefix_val
= ldb_msg_find_ldb_val(msg
, "prefixMap");
507 status
= WERR_INVALID_PARAM
;
511 info_val
= ldb_msg_find_ldb_val(msg
, "schemaInfo");
513 info_val_default
= strhex_to_data_blob(mem_ctx
, "FF0000000000000000000000000000000000000000");
514 if (!info_val_default
.data
) {
517 info_val
= &info_val_default
;
520 status
= dsdb_load_oid_mappings_ldb(schema
, prefix_val
, info_val
);
521 if (!W_ERROR_IS_OK(status
)) {
526 * load the attribute and class definitions outof df
528 while ((ldif
= ldb_ldif_read_string(ldb
, &df
))) {
532 talloc_steal(mem_ctx
, ldif
);
534 msg
= ldb_msg_canonicalize(ldb
, ldif
->msg
);
539 talloc_steal(mem_ctx
, msg
);
542 is_sa
= ldb_msg_check_string_attribute(msg
, "objectClass", "attributeSchema");
543 is_sc
= ldb_msg_check_string_attribute(msg
, "objectClass", "classSchema");
546 struct dsdb_attribute
*sa
;
548 sa
= talloc_zero(schema
, struct dsdb_attribute
);
553 status
= dsdb_attribute_from_ldb(ldb
, schema
, msg
, sa
, sa
);
554 if (!W_ERROR_IS_OK(status
)) {
558 DLIST_ADD(schema
->attributes
, sa
);
560 struct dsdb_class
*sc
;
562 sc
= talloc_zero(schema
, struct dsdb_class
);
567 status
= dsdb_class_from_ldb(schema
, msg
, sc
, sc
);
568 if (!W_ERROR_IS_OK(status
)) {
572 DLIST_ADD(schema
->classes
, sc
);
576 ret
= dsdb_set_schema(ldb
, schema
);
577 if (ret
!= LDB_SUCCESS
) {
578 status
= WERR_FOOBAR
;
588 talloc_free(mem_ctx
);