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"
28 #include "librpc/ndr/libndr.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
32 override the name to attribute handler function
34 const struct ldb_schema_attribute *dsdb_attribute_handler_override(struct ldb_context *ldb,
38 struct dsdb_schema *schema = talloc_get_type_abort(private_data, struct dsdb_schema);
39 const struct dsdb_attribute *a = dsdb_attribute_by_lDAPDisplayName(schema, name);
41 /* this will fall back to ldb internal handling */
44 return a->ldb_schema_attribute;
47 static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
49 int ret = LDB_SUCCESS;
50 struct ldb_result *res;
51 struct ldb_result *res_idx;
52 struct dsdb_attribute *attr;
53 struct ldb_message *mod_msg;
55 struct ldb_message *msg;
56 struct ldb_message *msg_idx;
58 /* setup our own attribute name to schema handler */
59 ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);
61 if (!write_attributes) {
65 mem_ctx = talloc_new(ldb);
67 return LDB_ERR_OPERATIONS_ERROR;
70 msg = ldb_msg_new(mem_ctx);
75 msg_idx = ldb_msg_new(mem_ctx);
80 msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
85 msg_idx->dn = ldb_dn_new(msg, ldb, "@INDEXLIST");
91 ret = ldb_msg_add_string(msg_idx, "@IDXONE", "1");
92 if (ret != LDB_SUCCESS) {
96 for (attr = schema->attributes; attr; attr = attr->next) {
97 const char *syntax = attr->syntax->ldb_syntax;
100 syntax = attr->syntax->ldap_oid;
103 /* Write out a rough approximation of the schema as an @ATTRIBUTES value, for bootstrapping */
104 if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) {
105 ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER");
106 } else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) {
107 ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE");
109 if (ret != LDB_SUCCESS) {
113 if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) {
114 ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName);
115 if (ret != LDB_SUCCESS) {
121 if (ret != LDB_SUCCESS) {
122 talloc_free(mem_ctx);
126 /* Try to avoid churning the attributes too much - we only want to do this if they have changed */
127 ret = ldb_search(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg->dn));
128 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
129 ret = ldb_add(ldb, msg);
130 } else if (ret != LDB_SUCCESS) {
131 } else if (res->count != 1) {
132 ret = ldb_add(ldb, msg);
135 /* Annoyingly added to our search results */
136 ldb_msg_remove_attr(res->msgs[0], "distinguishedName");
138 mod_msg = ldb_msg_diff(ldb, res->msgs[0], msg);
139 if (mod_msg->num_elements > 0) {
140 ret = samdb_replace(ldb, mem_ctx, mod_msg);
144 if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
145 /* We might be on a read-only DB or LDAP */
148 if (ret != LDB_SUCCESS) {
149 talloc_free(mem_ctx);
153 /* Now write out the indexs, as found in the schema (if they have changed) */
155 ret = ldb_search(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg_idx->dn));
156 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
157 ret = ldb_add(ldb, msg_idx);
158 } else if (ret != LDB_SUCCESS) {
159 } else if (res_idx->count != 1) {
160 ret = ldb_add(ldb, msg_idx);
163 /* Annoyingly added to our search results */
164 ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName");
166 mod_msg = ldb_msg_diff(ldb, res_idx->msgs[0], msg_idx);
167 if (mod_msg->num_elements > 0) {
168 ret = samdb_replace(ldb, mem_ctx, mod_msg);
171 if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
172 /* We might be on a read-only DB */
175 talloc_free(mem_ctx);
179 talloc_free(mem_ctx);
180 return LDB_ERR_OPERATIONS_ERROR;
183 static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
185 return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
187 static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
189 return (*c1)->governsID_id - (*c2)->governsID_id;
191 static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
193 return strcasecmp((*c1)->governsID_oid, (*c2)->governsID_oid);
195 static int dsdb_compare_class_by_cn(struct dsdb_class **c1, struct dsdb_class **c2)
197 return strcasecmp((*c1)->cn, (*c2)->cn);
200 static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
202 return strcasecmp((*a1)->lDAPDisplayName, (*a2)->lDAPDisplayName);
204 static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
206 return (*a1)->attributeID_id - (*a2)->attributeID_id;
208 static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
210 return strcasecmp((*a1)->attributeID_oid, (*a2)->attributeID_oid);
212 static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
214 return (*a1)->linkID - (*a2)->linkID;
218 create the sorted accessor arrays for the schema
220 static int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
221 struct dsdb_schema *schema)
223 struct dsdb_class *cur;
224 struct dsdb_attribute *a;
227 talloc_free(schema->classes_by_lDAPDisplayName);
228 talloc_free(schema->classes_by_governsID_id);
229 talloc_free(schema->classes_by_governsID_oid);
230 talloc_free(schema->classes_by_cn);
232 /* count the classes */
233 for (i=0, cur=schema->classes; cur; i++, cur=cur->next) /* noop */ ;
234 schema->num_classes = i;
236 /* setup classes_by_* */
237 schema->classes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_class *, i);
238 schema->classes_by_governsID_id = talloc_array(schema, struct dsdb_class *, i);
239 schema->classes_by_governsID_oid = talloc_array(schema, struct dsdb_class *, i);
240 schema->classes_by_cn = talloc_array(schema, struct dsdb_class *, i);
241 if (schema->classes_by_lDAPDisplayName == NULL ||
242 schema->classes_by_governsID_id == NULL ||
243 schema->classes_by_governsID_oid == NULL ||
244 schema->classes_by_cn == NULL) {
248 for (i=0, cur=schema->classes; cur; i++, cur=cur->next) {
249 schema->classes_by_lDAPDisplayName[i] = cur;
250 schema->classes_by_governsID_id[i] = cur;
251 schema->classes_by_governsID_oid[i] = cur;
252 schema->classes_by_cn[i] = cur;
255 /* sort the arrays */
256 qsort(schema->classes_by_lDAPDisplayName, schema->num_classes,
257 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_lDAPDisplayName);
258 qsort(schema->classes_by_governsID_id, schema->num_classes,
259 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_governsID_id);
260 qsort(schema->classes_by_governsID_oid, schema->num_classes,
261 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_governsID_oid);
262 qsort(schema->classes_by_cn, schema->num_classes,
263 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_cn);
265 /* now build the attribute accessor arrays */
266 talloc_free(schema->attributes_by_lDAPDisplayName);
267 talloc_free(schema->attributes_by_attributeID_id);
268 talloc_free(schema->attributes_by_attributeID_oid);
269 talloc_free(schema->attributes_by_linkID);
271 /* count the attributes */
272 for (i=0, a=schema->attributes; a; i++, a=a->next) /* noop */ ;
273 schema->num_attributes = i;
275 /* setup attributes_by_* */
276 schema->attributes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_attribute *, i);
277 schema->attributes_by_attributeID_id = talloc_array(schema, struct dsdb_attribute *, i);
278 schema->attributes_by_attributeID_oid = talloc_array(schema, struct dsdb_attribute *, i);
279 schema->attributes_by_linkID = talloc_array(schema, struct dsdb_attribute *, i);
280 if (schema->attributes_by_lDAPDisplayName == NULL ||
281 schema->attributes_by_attributeID_id == NULL ||
282 schema->attributes_by_attributeID_oid == NULL ||
283 schema->attributes_by_linkID == NULL) {
287 for (i=0, a=schema->attributes; a; i++, a=a->next) {
288 schema->attributes_by_lDAPDisplayName[i] = a;
289 schema->attributes_by_attributeID_id[i] = a;
290 schema->attributes_by_attributeID_oid[i] = a;
291 schema->attributes_by_linkID[i] = a;
294 /* sort the arrays */
295 qsort(schema->attributes_by_lDAPDisplayName, schema->num_attributes,
296 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_lDAPDisplayName);
297 qsort(schema->attributes_by_attributeID_id, schema->num_attributes,
298 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_attributeID_id);
299 qsort(schema->attributes_by_attributeID_oid, schema->num_attributes,
300 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_attributeID_oid);
301 qsort(schema->attributes_by_linkID, schema->num_attributes,
302 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_linkID);
307 schema->classes_by_lDAPDisplayName = NULL;
308 schema->classes_by_governsID_id = NULL;
309 schema->classes_by_governsID_oid = NULL;
310 schema->classes_by_cn = NULL;
311 schema->attributes_by_lDAPDisplayName = NULL;
312 schema->attributes_by_attributeID_id = NULL;
313 schema->attributes_by_attributeID_oid = NULL;
314 schema->attributes_by_linkID = NULL;
316 return LDB_ERR_OPERATIONS_ERROR;
319 int dsdb_setup_schema_inversion(struct ldb_context *ldb, struct dsdb_schema *schema)
321 /* Walk the list of schema classes */
323 /* For each subClassOf, add us to subclasses of the parent */
325 /* collect these subclasses into a recursive list of total subclasses, preserving order */
327 /* For each subclass under 'top', write the index from it's
328 * order as an integer in the dsdb_class (for sorting
329 * objectClass lists efficiently) */
331 /* Walk the list of scheam classes */
333 /* Create a 'total possible superiors' on each class */
338 * Attach the schema to an opaque pointer on the ldb, so ldb modules
342 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
346 ret = dsdb_setup_sorted_accessors(ldb, schema);
347 if (ret != LDB_SUCCESS) {
351 ret = schema_fill_constructed(schema);
352 if (ret != LDB_SUCCESS) {
356 ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
357 if (ret != LDB_SUCCESS) {
361 /* Set the new attributes based on the new schema */
362 ret = dsdb_schema_set_attributes(ldb, schema, true);
363 if (ret != LDB_SUCCESS) {
367 talloc_steal(ldb, schema);
373 * Global variable to hold one copy of the schema, used to avoid memory bloat
375 static struct dsdb_schema *global_schema;
378 * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
380 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
381 bool write_attributes)
384 ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
385 if (ret != LDB_SUCCESS) {
389 /* Set the new attributes based on the new schema */
390 ret = dsdb_schema_set_attributes(ldb, schema, write_attributes);
391 if (ret != LDB_SUCCESS) {
395 /* Keep a reference to this schema, just incase the original copy is replaced */
396 if (talloc_reference(ldb, schema) == NULL) {
397 return LDB_ERR_OPERATIONS_ERROR;
404 * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
406 int dsdb_set_global_schema(struct ldb_context *ldb)
408 if (!global_schema) {
412 return dsdb_reference_schema(ldb, global_schema, false /* Don't write attributes, it's expensive */);
416 * Find the schema object for this ldb
419 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
422 struct dsdb_schema *schema;
424 /* see if we have a cached copy */
425 p = ldb_get_opaque(ldb, "dsdb_schema");
430 schema = talloc_get_type(p, struct dsdb_schema);
439 * Make the schema found on this ldb the 'global' schema
442 void dsdb_make_schema_global(struct ldb_context *ldb)
444 struct dsdb_schema *schema = dsdb_get_schema(ldb);
450 talloc_unlink(talloc_autofree_context(), global_schema);
453 /* we want the schema to be around permanently */
454 talloc_reparent(talloc_parent(schema), talloc_autofree_context(), schema);
456 global_schema = schema;
458 dsdb_set_global_schema(ldb);
461 /* When loading the schema from LDIF files, we don't get the extended DNs.
463 We need to set these up, so that from the moment we start the provision, the defaultObjectCategory links are set up correctly.
465 int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *schema)
467 struct dsdb_class *cur;
468 const struct dsdb_class *target_class;
469 for (cur = schema->classes; cur; cur = cur->next) {
470 enum ndr_err_code ndr_err;
471 const struct ldb_val *rdn;
473 struct ldb_dn *dn = ldb_dn_new(NULL, ldb, cur->defaultObjectCategory);
475 return LDB_ERR_INVALID_DN_SYNTAX;
477 rdn = ldb_dn_get_component_val(dn, 0);
480 return LDB_ERR_INVALID_DN_SYNTAX;
482 target_class = dsdb_class_by_cn_ldb_val(schema, rdn);
485 return LDB_ERR_CONSTRAINT_VIOLATION;
488 ndr_err = ndr_push_struct_blob(&guid, dn, NULL, &target_class->objectGUID,
489 (ndr_push_flags_fn_t)ndr_push_GUID);
490 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
492 return LDB_ERR_OPERATIONS_ERROR;
494 ldb_dn_set_extended_component(dn, "GUID", &guid);
496 cur->defaultObjectCategory = ldb_dn_get_extended_linearized(cur, dn, 1);
503 * Add an element to the schema (attribute or class) from an LDB message
505 WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema,
506 struct ldb_message *msg)
508 static struct ldb_parse_tree *attr_tree, *class_tree;
510 attr_tree = ldb_parse_tree(talloc_autofree_context(), "(objectClass=attributeSchema)");
517 class_tree = ldb_parse_tree(talloc_autofree_context(), "(objectClass=classSchema)");
523 if (ldb_match_msg(ldb, msg, attr_tree, NULL, LDB_SCOPE_BASE)) {
524 return dsdb_attribute_from_ldb(ldb, schema, msg);
525 } else if (ldb_match_msg(ldb, msg, class_tree, NULL, LDB_SCOPE_BASE)) {
526 return dsdb_class_from_ldb(schema, msg);
529 /* Don't fail on things not classes or attributes */
534 * Rather than read a schema from the LDB itself, read it from an ldif
535 * file. This allows schema to be loaded and used while adding the
536 * schema itself to the directory.
539 WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df)
541 struct ldb_ldif *ldif;
542 struct ldb_message *msg;
546 struct dsdb_schema *schema;
547 const struct ldb_val *prefix_val;
548 const struct ldb_val *info_val;
549 struct ldb_val info_val_default;
552 mem_ctx = talloc_new(ldb);
557 schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")));
559 schema->fsmo.we_are_master = true;
560 schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
561 if (!schema->fsmo.master_dn) {
566 * load the prefixMap attribute from pf
568 ldif = ldb_ldif_read_string(ldb, &pf);
570 status = WERR_INVALID_PARAM;
573 talloc_steal(mem_ctx, ldif);
575 msg = ldb_msg_canonicalize(ldb, ldif->msg);
579 talloc_steal(mem_ctx, msg);
582 prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
584 status = WERR_INVALID_PARAM;
588 info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
590 info_val_default = strhex_to_data_blob(mem_ctx, "FF0000000000000000000000000000000000000000");
591 if (!info_val_default.data) {
594 info_val = &info_val_default;
597 status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
598 if (!W_ERROR_IS_OK(status)) {
603 * load the attribute and class definitions outof df
605 while ((ldif = ldb_ldif_read_string(ldb, &df))) {
606 talloc_steal(mem_ctx, ldif);
608 msg = ldb_msg_canonicalize(ldb, ldif->msg);
613 status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, msg);
615 if (!W_ERROR_IS_OK(status)) {
620 ret = dsdb_set_schema(ldb, schema);
621 if (ret != LDB_SUCCESS) {
622 status = WERR_FOOBAR;
626 ret = dsdb_schema_fill_extended_dn(ldb, schema);
627 if (ret != LDB_SUCCESS) {
628 status = WERR_FOOBAR;
638 talloc_free(mem_ctx);