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 uint32_cmp(uint32_t c1, uint32_t c2)
185 if (c1 == c2) return 0;
186 return c1 > c2 ? 1 : -1;
189 static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
191 return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
193 static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
195 return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id);
197 static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
199 return strcasecmp((*c1)->governsID_oid, (*c2)->governsID_oid);
201 static int dsdb_compare_class_by_cn(struct dsdb_class **c1, struct dsdb_class **c2)
203 return strcasecmp((*c1)->cn, (*c2)->cn);
206 static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
208 return strcasecmp((*a1)->lDAPDisplayName, (*a2)->lDAPDisplayName);
210 static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
212 return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id);
214 static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
216 return strcasecmp((*a1)->attributeID_oid, (*a2)->attributeID_oid);
218 static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
220 return uint32_cmp((*a1)->linkID, (*a2)->linkID);
224 create the sorted accessor arrays for the schema
226 static int dsdb_setup_sorted_accessors(struct ldb_context *ldb,
227 struct dsdb_schema *schema)
229 struct dsdb_class *cur;
230 struct dsdb_attribute *a;
233 talloc_free(schema->classes_by_lDAPDisplayName);
234 talloc_free(schema->classes_by_governsID_id);
235 talloc_free(schema->classes_by_governsID_oid);
236 talloc_free(schema->classes_by_cn);
238 /* count the classes */
239 for (i=0, cur=schema->classes; cur; i++, cur=cur->next) /* noop */ ;
240 schema->num_classes = i;
242 /* setup classes_by_* */
243 schema->classes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_class *, i);
244 schema->classes_by_governsID_id = talloc_array(schema, struct dsdb_class *, i);
245 schema->classes_by_governsID_oid = talloc_array(schema, struct dsdb_class *, i);
246 schema->classes_by_cn = talloc_array(schema, struct dsdb_class *, i);
247 if (schema->classes_by_lDAPDisplayName == NULL ||
248 schema->classes_by_governsID_id == NULL ||
249 schema->classes_by_governsID_oid == NULL ||
250 schema->classes_by_cn == NULL) {
254 for (i=0, cur=schema->classes; cur; i++, cur=cur->next) {
255 schema->classes_by_lDAPDisplayName[i] = cur;
256 schema->classes_by_governsID_id[i] = cur;
257 schema->classes_by_governsID_oid[i] = cur;
258 schema->classes_by_cn[i] = cur;
261 /* sort the arrays */
262 qsort(schema->classes_by_lDAPDisplayName, schema->num_classes,
263 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_lDAPDisplayName);
264 qsort(schema->classes_by_governsID_id, schema->num_classes,
265 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_governsID_id);
266 qsort(schema->classes_by_governsID_oid, schema->num_classes,
267 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_governsID_oid);
268 qsort(schema->classes_by_cn, schema->num_classes,
269 sizeof(struct dsdb_class *), QSORT_CAST dsdb_compare_class_by_cn);
271 /* now build the attribute accessor arrays */
272 talloc_free(schema->attributes_by_lDAPDisplayName);
273 talloc_free(schema->attributes_by_attributeID_id);
274 talloc_free(schema->attributes_by_attributeID_oid);
275 talloc_free(schema->attributes_by_linkID);
277 /* count the attributes */
278 for (i=0, a=schema->attributes; a; i++, a=a->next) /* noop */ ;
279 schema->num_attributes = i;
281 /* setup attributes_by_* */
282 schema->attributes_by_lDAPDisplayName = talloc_array(schema, struct dsdb_attribute *, i);
283 schema->attributes_by_attributeID_id = talloc_array(schema, struct dsdb_attribute *, i);
284 schema->attributes_by_attributeID_oid = talloc_array(schema, struct dsdb_attribute *, i);
285 schema->attributes_by_linkID = talloc_array(schema, struct dsdb_attribute *, i);
286 if (schema->attributes_by_lDAPDisplayName == NULL ||
287 schema->attributes_by_attributeID_id == NULL ||
288 schema->attributes_by_attributeID_oid == NULL ||
289 schema->attributes_by_linkID == NULL) {
293 for (i=0, a=schema->attributes; a; i++, a=a->next) {
294 schema->attributes_by_lDAPDisplayName[i] = a;
295 schema->attributes_by_attributeID_id[i] = a;
296 schema->attributes_by_attributeID_oid[i] = a;
297 schema->attributes_by_linkID[i] = a;
300 /* sort the arrays */
301 qsort(schema->attributes_by_lDAPDisplayName, schema->num_attributes,
302 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_lDAPDisplayName);
303 qsort(schema->attributes_by_attributeID_id, schema->num_attributes,
304 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_attributeID_id);
305 qsort(schema->attributes_by_attributeID_oid, schema->num_attributes,
306 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_attributeID_oid);
307 qsort(schema->attributes_by_linkID, schema->num_attributes,
308 sizeof(struct dsdb_attribute *), QSORT_CAST dsdb_compare_attribute_by_linkID);
313 schema->classes_by_lDAPDisplayName = NULL;
314 schema->classes_by_governsID_id = NULL;
315 schema->classes_by_governsID_oid = NULL;
316 schema->classes_by_cn = NULL;
317 schema->attributes_by_lDAPDisplayName = NULL;
318 schema->attributes_by_attributeID_id = NULL;
319 schema->attributes_by_attributeID_oid = NULL;
320 schema->attributes_by_linkID = NULL;
322 return LDB_ERR_OPERATIONS_ERROR;
325 int dsdb_setup_schema_inversion(struct ldb_context *ldb, struct dsdb_schema *schema)
327 /* Walk the list of schema classes */
329 /* For each subClassOf, add us to subclasses of the parent */
331 /* collect these subclasses into a recursive list of total subclasses, preserving order */
333 /* For each subclass under 'top', write the index from it's
334 * order as an integer in the dsdb_class (for sorting
335 * objectClass lists efficiently) */
337 /* Walk the list of scheam classes */
339 /* Create a 'total possible superiors' on each class */
344 * Attach the schema to an opaque pointer on the ldb, so ldb modules
348 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
352 ret = dsdb_setup_sorted_accessors(ldb, schema);
353 if (ret != LDB_SUCCESS) {
357 ret = schema_fill_constructed(schema);
358 if (ret != LDB_SUCCESS) {
362 ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
363 if (ret != LDB_SUCCESS) {
367 /* Set the new attributes based on the new schema */
368 ret = dsdb_schema_set_attributes(ldb, schema, true);
369 if (ret != LDB_SUCCESS) {
373 talloc_steal(ldb, schema);
379 * Global variable to hold one copy of the schema, used to avoid memory bloat
381 static struct dsdb_schema *global_schema;
384 * Make this ldb use a specified schema, already fully calculated and belonging to another ldb
386 int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
387 bool write_attributes)
390 ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
391 if (ret != LDB_SUCCESS) {
395 /* Set the new attributes based on the new schema */
396 ret = dsdb_schema_set_attributes(ldb, schema, write_attributes);
397 if (ret != LDB_SUCCESS) {
401 /* Keep a reference to this schema, just incase the original copy is replaced */
402 if (talloc_reference(ldb, schema) == NULL) {
403 return LDB_ERR_OPERATIONS_ERROR;
410 * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
412 int dsdb_set_global_schema(struct ldb_context *ldb)
414 if (!global_schema) {
418 return dsdb_reference_schema(ldb, global_schema, false /* Don't write attributes, it's expensive */);
422 * Find the schema object for this ldb
425 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
428 struct dsdb_schema *schema;
430 /* see if we have a cached copy */
431 p = ldb_get_opaque(ldb, "dsdb_schema");
436 schema = talloc_get_type(p, struct dsdb_schema);
445 * Make the schema found on this ldb the 'global' schema
448 void dsdb_make_schema_global(struct ldb_context *ldb)
450 struct dsdb_schema *schema = dsdb_get_schema(ldb);
456 talloc_unlink(talloc_autofree_context(), global_schema);
459 /* we want the schema to be around permanently */
460 talloc_reparent(talloc_parent(schema), talloc_autofree_context(), schema);
462 global_schema = schema;
464 dsdb_set_global_schema(ldb);
467 /* When loading the schema from LDIF files, we don't get the extended DNs.
469 We need to set these up, so that from the moment we start the provision, the defaultObjectCategory links are set up correctly.
471 int dsdb_schema_fill_extended_dn(struct ldb_context *ldb, struct dsdb_schema *schema)
473 struct dsdb_class *cur;
474 const struct dsdb_class *target_class;
475 for (cur = schema->classes; cur; cur = cur->next) {
476 const struct ldb_val *rdn;
479 struct ldb_dn *dn = ldb_dn_new(NULL, ldb, cur->defaultObjectCategory);
482 return LDB_ERR_INVALID_DN_SYNTAX;
484 rdn = ldb_dn_get_component_val(dn, 0);
487 return LDB_ERR_INVALID_DN_SYNTAX;
489 target_class = dsdb_class_by_cn_ldb_val(schema, rdn);
492 return LDB_ERR_CONSTRAINT_VIOLATION;
495 status = GUID_to_ndr_blob(&target_class->objectGUID, dn, &guid);
496 if (!NT_STATUS_IS_OK(status)) {
498 return LDB_ERR_OPERATIONS_ERROR;
500 ldb_dn_set_extended_component(dn, "GUID", &guid);
502 cur->defaultObjectCategory = ldb_dn_get_extended_linearized(cur, dn, 1);
509 * Add an element to the schema (attribute or class) from an LDB message
511 WERROR dsdb_schema_set_el_from_ldb_msg(struct ldb_context *ldb, struct dsdb_schema *schema,
512 struct ldb_message *msg)
514 static struct ldb_parse_tree *attr_tree, *class_tree;
516 attr_tree = ldb_parse_tree(talloc_autofree_context(), "(objectClass=attributeSchema)");
523 class_tree = ldb_parse_tree(talloc_autofree_context(), "(objectClass=classSchema)");
529 if (ldb_match_msg(ldb, msg, attr_tree, NULL, LDB_SCOPE_BASE)) {
530 return dsdb_attribute_from_ldb(ldb, schema, msg);
531 } else if (ldb_match_msg(ldb, msg, class_tree, NULL, LDB_SCOPE_BASE)) {
532 return dsdb_class_from_ldb(schema, msg);
535 /* Don't fail on things not classes or attributes */
540 * Rather than read a schema from the LDB itself, read it from an ldif
541 * file. This allows schema to be loaded and used while adding the
542 * schema itself to the directory.
545 WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df)
547 struct ldb_ldif *ldif;
548 struct ldb_message *msg;
552 struct dsdb_schema *schema;
553 const struct ldb_val *prefix_val;
554 const struct ldb_val *info_val;
555 struct ldb_val info_val_default;
558 mem_ctx = talloc_new(ldb);
563 schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")));
565 schema->fsmo.we_are_master = true;
566 schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
567 if (!schema->fsmo.master_dn) {
572 * load the prefixMap attribute from pf
574 ldif = ldb_ldif_read_string(ldb, &pf);
576 status = WERR_INVALID_PARAM;
579 talloc_steal(mem_ctx, ldif);
581 msg = ldb_msg_canonicalize(ldb, ldif->msg);
585 talloc_steal(mem_ctx, msg);
588 prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
590 status = WERR_INVALID_PARAM;
594 info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
596 info_val_default = strhex_to_data_blob(mem_ctx, "FF0000000000000000000000000000000000000000");
597 if (!info_val_default.data) {
600 info_val = &info_val_default;
603 status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
604 if (!W_ERROR_IS_OK(status)) {
609 * load the attribute and class definitions outof df
611 while ((ldif = ldb_ldif_read_string(ldb, &df))) {
612 talloc_steal(mem_ctx, ldif);
614 msg = ldb_msg_canonicalize(ldb, ldif->msg);
619 status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, msg);
621 if (!W_ERROR_IS_OK(status)) {
626 ret = dsdb_set_schema(ldb, schema);
627 if (ret != LDB_SUCCESS) {
628 status = WERR_FOOBAR;
632 ret = dsdb_schema_fill_extended_dn(ldb, schema);
633 if (ret != LDB_SUCCESS) {
634 status = WERR_FOOBAR;
644 talloc_free(mem_ctx);