summaryrefslogtreecommitdiff
path: root/source4/dsdb/schema
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2008-08-20 13:22:16 +1000
committerAndrew Bartlett <abartlet@samba.org>2008-08-20 13:22:16 +1000
commit18e86ccf86946a7582a11485f9369bf59988c17b (patch)
treece382aecd1d685e1822a9114d60c366b25f68bda /source4/dsdb/schema
parent5d375297718d06f7c5544372001b8955b23d7ba2 (diff)
downloadsamba-18e86ccf86946a7582a11485f9369bf59988c17b.tar.gz
samba-18e86ccf86946a7582a11485f9369bf59988c17b.tar.bz2
samba-18e86ccf86946a7582a11485f9369bf59988c17b.zip
Split schema_init.c into smaller bits.
This should make schema manipulation a little easier to follow. Andrew Bartlett (This used to be commit 300ed83526e75d834bd23ddd1c1c26ebe2555e0f)
Diffstat (limited to 'source4/dsdb/schema')
-rw-r--r--source4/dsdb/schema/schema_init.c545
-rw-r--r--source4/dsdb/schema/schema_query.c344
-rw-r--r--source4/dsdb/schema/schema_set.c254
3 files changed, 598 insertions, 545 deletions
diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c
index 73be580347..3ed7daee59 100644
--- a/source4/dsdb/schema/schema_init.c
+++ b/source4/dsdb/schema/schema_init.c
@@ -1409,548 +1409,3 @@ WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
return WERR_OK;
}
-const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
- uint32_t id)
-{
- struct dsdb_attribute *cur;
-
- /*
- * 0xFFFFFFFF is used as value when no mapping table is available,
- * so don't try to match with it
- */
- if (id == 0xFFFFFFFF) return NULL;
-
- /* TODO: add binary search */
- for (cur = schema->attributes; cur; cur = cur->next) {
- if (cur->attributeID_id != id) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
- const char *oid)
-{
- struct dsdb_attribute *cur;
-
- if (!oid) return NULL;
-
- /* TODO: add binary search */
- for (cur = schema->attributes; cur; cur = cur->next) {
- if (strcmp(cur->attributeID_oid, oid) != 0) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
- const char *name)
-{
- struct dsdb_attribute *cur;
-
- if (!name) return NULL;
-
- /* TODO: add binary search */
- for (cur = schema->attributes; cur; cur = cur->next) {
- if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
- int linkID)
-{
- struct dsdb_attribute *cur;
-
- /* TODO: add binary search */
- for (cur = schema->attributes; cur; cur = cur->next) {
- if (cur->linkID != linkID) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
- uint32_t id)
-{
- struct dsdb_class *cur;
-
- /*
- * 0xFFFFFFFF is used as value when no mapping table is available,
- * so don't try to match with it
- */
- if (id == 0xFFFFFFFF) return NULL;
-
- /* TODO: add binary search */
- for (cur = schema->classes; cur; cur = cur->next) {
- if (cur->governsID_id != id) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
- const char *oid)
-{
- struct dsdb_class *cur;
-
- if (!oid) return NULL;
-
- /* TODO: add binary search */
- for (cur = schema->classes; cur; cur = cur->next) {
- if (strcmp(cur->governsID_oid, oid) != 0) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
- const char *name)
-{
- struct dsdb_class *cur;
-
- if (!name) return NULL;
-
- /* TODO: add binary search */
- for (cur = schema->classes; cur; cur = cur->next) {
- if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
- const char *cn)
-{
- struct dsdb_class *cur;
-
- if (!cn) return NULL;
-
- /* TODO: add binary search */
- for (cur = schema->classes; cur; cur = cur->next) {
- if (strcasecmp(cur->cn, cn) != 0) continue;
-
- return cur;
- }
-
- return NULL;
-}
-
-const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
- uint32_t id)
-{
- const struct dsdb_attribute *a;
- const struct dsdb_class *c;
-
- /* TODO: add binary search */
- a = dsdb_attribute_by_attributeID_id(schema, id);
- if (a) {
- return a->lDAPDisplayName;
- }
-
- c = dsdb_class_by_governsID_id(schema, id);
- if (c) {
- return c->lDAPDisplayName;
- }
-
- return NULL;
-}
-
-/**
- Return a list of linked attributes, in lDAPDisplayName format.
-
- This may be used to determine if a modification would require
- backlinks to be updated, for example
-*/
-
-WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
-{
- const char **attr_list = NULL;
- struct dsdb_attribute *cur;
- int i = 0;
- for (cur = schema->attributes; cur; cur = cur->next) {
- if (cur->linkID == 0) continue;
-
- attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
- if (!attr_list) {
- return WERR_NOMEM;
- }
- attr_list[i] = cur->lDAPDisplayName;
- i++;
- }
- attr_list[i] = NULL;
- *attr_list_ret = attr_list;
- return WERR_OK;
-}
-
-char **merge_attr_list(TALLOC_CTX *mem_ctx,
- char **attrs, const char **new_attrs)
-{
- char **ret_attrs;
- int i;
- size_t new_len, orig_len = str_list_length((const char **)attrs);
- if (!new_attrs) {
- return attrs;
- }
-
- ret_attrs = talloc_realloc(mem_ctx,
- attrs, char *, orig_len + str_list_length(new_attrs) + 1);
- if (ret_attrs) {
- for (i=0; i < str_list_length(new_attrs); i++) {
- ret_attrs[orig_len + i] = new_attrs[i];
- }
- new_len = orig_len + str_list_length(new_attrs);
-
- ret_attrs[new_len] = NULL;
- }
-
- return ret_attrs;
-}
-
-/*
- Return a merged list of the attributes of exactly one class (not
- considering subclasses, auxillary classes etc)
-*/
-
-char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *class, enum dsdb_attr_list_query query)
-{
- char **attr_list = NULL;
- switch (query) {
- case DSDB_SCHEMA_ALL_MAY:
- attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
- attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
- break;
-
- case DSDB_SCHEMA_ALL_MUST:
- attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
- attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
- break;
-
- case DSDB_SCHEMA_SYS_MAY:
- attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
- break;
-
- case DSDB_SCHEMA_SYS_MUST:
- attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
- break;
-
- case DSDB_SCHEMA_MAY:
- attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
- break;
-
- case DSDB_SCHEMA_MUST:
- attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
- break;
-
- case DSDB_SCHEMA_ALL:
- attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
- attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
- attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
- attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
- break;
- }
- return attr_list;
-}
-
-static char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx,
- const struct dsdb_schema *schema,
- const char **class_list,
- enum dsdb_attr_list_query query)
-{
- int i;
- const struct dsdb_class *class;
-
- char **attr_list = NULL;
- char **this_class_list;
- char **recursive_list;
-
- for (i=0; class_list && class_list[i]; i++) {
- class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]);
-
- this_class_list = dsdb_attribute_list(mem_ctx, class, query);
- attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)this_class_list);
-
- recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
- class->systemAuxiliaryClass,
- query);
-
- attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
-
- recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
- class->auxiliaryClass,
- query);
-
- attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
-
- }
- return attr_list;
-}
-
-char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx,
- const struct dsdb_schema *schema,
- const char **class_list,
- enum dsdb_attr_list_query query)
-{
- char **attr_list = dsdb_full_attribute_list_internal(mem_ctx, schema, class_list, query);
- size_t new_len = str_list_length((const char **)attr_list);
-
- /* Remove duplicates */
- if (new_len > 1) {
- int i;
- qsort(attr_list, new_len,
- sizeof(*attr_list),
- (comparison_fn_t)strcasecmp);
-
- for (i=1 ; i < new_len; i++) {
- char **val1 = &attr_list[i-1];
- char **val2 = &attr_list[i];
- if (ldb_attr_cmp(*val1, *val2) == 0) {
- memmove(val1, val2, (new_len - i) * sizeof( *attr_list));
- new_len--;
- i--;
- }
- }
- }
- return attr_list;
-}
-/**
- * Attach the schema to an opaque pointer on the ldb, so ldb modules
- * can find it
- */
-
-int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
-{
- int ret;
-
- ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(ldb, schema);
-
- return LDB_SUCCESS;
-}
-
-/**
- * Global variable to hold one copy of the schema, used to avoid memory bloat
- */
-static struct dsdb_schema *global_schema;
-
-/**
- * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
- */
-int dsdb_set_global_schema(struct ldb_context *ldb)
-{
- int ret;
- if (!global_schema) {
- return LDB_SUCCESS;
- }
- ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- /* Keep a reference to this schema, just incase the global copy is replaced */
- if (talloc_reference(ldb, global_schema) == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- return LDB_SUCCESS;
-}
-
-/**
- * Find the schema object for this ldb
- */
-
-struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
-{
- const void *p;
- struct dsdb_schema *schema;
-
- /* see if we have a cached copy */
- p = ldb_get_opaque(ldb, "dsdb_schema");
- if (!p) {
- return NULL;
- }
-
- schema = talloc_get_type(p, struct dsdb_schema);
- if (!schema) {
- return NULL;
- }
-
- return schema;
-}
-
-/**
- * Make the schema found on this ldb the 'global' schema
- */
-
-void dsdb_make_schema_global(struct ldb_context *ldb)
-{
- struct dsdb_schema *schema = dsdb_get_schema(ldb);
- if (!schema) {
- return;
- }
-
- if (global_schema) {
- talloc_unlink(talloc_autofree_context(), schema);
- }
-
- talloc_steal(talloc_autofree_context(), schema);
- global_schema = schema;
-
- dsdb_set_global_schema(ldb);
-}
-
-
-/**
- * Rather than read a schema from the LDB itself, read it from an ldif
- * file. This allows schema to be loaded and used while adding the
- * schema itself to the directory.
- */
-
-WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df)
-{
- struct ldb_ldif *ldif;
- struct ldb_message *msg;
- TALLOC_CTX *mem_ctx;
- WERROR status;
- int ret;
- struct dsdb_schema *schema;
- const struct ldb_val *prefix_val;
- const struct ldb_val *info_val;
- struct ldb_val info_val_default;
-
- mem_ctx = talloc_new(ldb);
- if (!mem_ctx) {
- goto nomem;
- }
-
- schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")));
-
- schema->fsmo.we_are_master = true;
- schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
- if (!schema->fsmo.master_dn) {
- goto nomem;
- }
-
- /*
- * load the prefixMap attribute from pf
- */
- ldif = ldb_ldif_read_string(ldb, &pf);
- if (!ldif) {
- status = WERR_INVALID_PARAM;
- goto failed;
- }
- talloc_steal(mem_ctx, ldif);
-
- msg = ldb_msg_canonicalize(ldb, ldif->msg);
- if (!msg) {
- goto nomem;
- }
- talloc_steal(mem_ctx, msg);
- talloc_free(ldif);
-
- prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
- if (!prefix_val) {
- status = WERR_INVALID_PARAM;
- goto failed;
- }
-
- info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
- if (!info_val) {
- info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000");
- if (!info_val_default.data) {
- goto nomem;
- }
- talloc_steal(mem_ctx, info_val_default.data);
- info_val = &info_val_default;
- }
-
- status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
- if (!W_ERROR_IS_OK(status)) {
- goto failed;
- }
-
- /*
- * load the attribute and class definitions outof df
- */
- while ((ldif = ldb_ldif_read_string(ldb, &df))) {
- bool is_sa;
- bool is_sc;
-
- talloc_steal(mem_ctx, ldif);
-
- msg = ldb_msg_canonicalize(ldb, ldif->msg);
- if (!msg) {
- goto nomem;
- }
-
- talloc_steal(mem_ctx, msg);
- talloc_free(ldif);
-
- is_sa = ldb_msg_check_string_attribute(msg, "objectClass", "attributeSchema");
- is_sc = ldb_msg_check_string_attribute(msg, "objectClass", "classSchema");
-
- if (is_sa) {
- struct dsdb_attribute *sa;
-
- sa = talloc_zero(schema, struct dsdb_attribute);
- if (!sa) {
- goto nomem;
- }
-
- status = dsdb_attribute_from_ldb(schema, msg, sa, sa);
- if (!W_ERROR_IS_OK(status)) {
- goto failed;
- }
-
- DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
- } else if (is_sc) {
- struct dsdb_class *sc;
-
- sc = talloc_zero(schema, struct dsdb_class);
- if (!sc) {
- goto nomem;
- }
-
- status = dsdb_class_from_ldb(schema, msg, sc, sc);
- if (!W_ERROR_IS_OK(status)) {
- goto failed;
- }
-
- DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
- }
- }
-
- ret = dsdb_set_schema(ldb, schema);
- if (ret != LDB_SUCCESS) {
- status = WERR_FOOBAR;
- goto failed;
- }
-
- goto done;
-
-nomem:
- status = WERR_NOMEM;
-failed:
-done:
- talloc_free(mem_ctx);
- return status;
-}
diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c
new file mode 100644
index 0000000000..ca26ffd206
--- /dev/null
+++ b/source4/dsdb/schema/schema_query.c
@@ -0,0 +1,344 @@
+/*
+ Unix SMB/CIFS mplementation.
+ DSDB schema header
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+
+const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
+ uint32_t id)
+{
+ struct dsdb_attribute *cur;
+
+ /*
+ * 0xFFFFFFFF is used as value when no mapping table is available,
+ * so don't try to match with it
+ */
+ if (id == 0xFFFFFFFF) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (cur->attributeID_id != id) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
+ const char *oid)
+{
+ struct dsdb_attribute *cur;
+
+ if (!oid) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (strcmp(cur->attributeID_oid, oid) != 0) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
+ const char *name)
+{
+ struct dsdb_attribute *cur;
+
+ if (!name) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
+ int linkID)
+{
+ struct dsdb_attribute *cur;
+
+ /* TODO: add binary search */
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (cur->linkID != linkID) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
+ uint32_t id)
+{
+ struct dsdb_class *cur;
+
+ /*
+ * 0xFFFFFFFF is used as value when no mapping table is available,
+ * so don't try to match with it
+ */
+ if (id == 0xFFFFFFFF) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->classes; cur; cur = cur->next) {
+ if (cur->governsID_id != id) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
+ const char *oid)
+{
+ struct dsdb_class *cur;
+
+ if (!oid) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->classes; cur; cur = cur->next) {
+ if (strcmp(cur->governsID_oid, oid) != 0) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
+ const char *name)
+{
+ struct dsdb_class *cur;
+
+ if (!name) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->classes; cur; cur = cur->next) {
+ if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
+ const char *cn)
+{
+ struct dsdb_class *cur;
+
+ if (!cn) return NULL;
+
+ /* TODO: add binary search */
+ for (cur = schema->classes; cur; cur = cur->next) {
+ if (strcasecmp(cur->cn, cn) != 0) continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
+ uint32_t id)
+{
+ const struct dsdb_attribute *a;
+ const struct dsdb_class *c;
+
+ /* TODO: add binary search */
+ a = dsdb_attribute_by_attributeID_id(schema, id);
+ if (a) {
+ return a->lDAPDisplayName;
+ }
+
+ c = dsdb_class_by_governsID_id(schema, id);
+ if (c) {
+ return c->lDAPDisplayName;
+ }
+
+ return NULL;
+}
+
+/**
+ Return a list of linked attributes, in lDAPDisplayName format.
+
+ This may be used to determine if a modification would require
+ backlinks to be updated, for example
+*/
+
+WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
+{
+ const char **attr_list = NULL;
+ struct dsdb_attribute *cur;
+ int i = 0;
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ if (cur->linkID == 0) continue;
+
+ attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
+ if (!attr_list) {
+ return WERR_NOMEM;
+ }
+ attr_list[i] = cur->lDAPDisplayName;
+ i++;
+ }
+ attr_list[i] = NULL;
+ *attr_list_ret = attr_list;
+ return WERR_OK;
+}
+
+char **merge_attr_list(TALLOC_CTX *mem_ctx,
+ char **attrs, const char **new_attrs)
+{
+ char **ret_attrs;
+ int i;
+ size_t new_len, orig_len = str_list_length((const char **)attrs);
+ if (!new_attrs) {
+ return attrs;
+ }
+
+ ret_attrs = talloc_realloc(mem_ctx,
+ attrs, char *, orig_len + str_list_length(new_attrs) + 1);
+ if (ret_attrs) {
+ for (i=0; i < str_list_length(new_attrs); i++) {
+ ret_attrs[orig_len + i] = new_attrs[i];
+ }
+ new_len = orig_len + str_list_length(new_attrs);
+
+ ret_attrs[new_len] = NULL;
+ }
+
+ return ret_attrs;
+}
+
+/*
+ Return a merged list of the attributes of exactly one class (not
+ considering subclasses, auxillary classes etc)
+*/
+
+char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *class, enum dsdb_attr_list_query query)
+{
+ char **attr_list = NULL;
+ switch (query) {
+ case DSDB_SCHEMA_ALL_MAY:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
+ break;
+
+ case DSDB_SCHEMA_ALL_MUST:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
+ break;
+
+ case DSDB_SCHEMA_SYS_MAY:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
+ break;
+
+ case DSDB_SCHEMA_SYS_MUST:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
+ break;
+
+ case DSDB_SCHEMA_MAY:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
+ break;
+
+ case DSDB_SCHEMA_MUST:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
+ break;
+
+ case DSDB_SCHEMA_ALL:
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
+ attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
+ break;
+ }
+ return attr_list;
+}
+
+static char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx,
+ const struct dsdb_schema *schema,
+ const char **class_list,
+ enum dsdb_attr_list_query query)
+{
+ int i;
+ const struct dsdb_class *class;
+
+ char **attr_list = NULL;
+ char **this_class_list;
+ char **recursive_list;
+
+ for (i=0; class_list && class_list[i]; i++) {
+ class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]);
+
+ this_class_list = dsdb_attribute_list(mem_ctx, class, query);
+ attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)this_class_list);
+
+ recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
+ class->systemAuxiliaryClass,
+ query);
+
+ attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
+
+ recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
+ class->auxiliaryClass,
+ query);
+
+ attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
+
+ }
+ return attr_list;
+}
+
+char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx,
+ const struct dsdb_schema *schema,
+ const char **class_list,
+ enum dsdb_attr_list_query query)
+{
+ char **attr_list = dsdb_full_attribute_list_internal(mem_ctx, schema, class_list, query);
+ size_t new_len = str_list_length((const char **)attr_list);
+
+ /* Remove duplicates */
+ if (new_len > 1) {
+ int i;
+ qsort(attr_list, new_len,
+ sizeof(*attr_list),
+ (comparison_fn_t)strcasecmp);
+
+ for (i=1 ; i < new_len; i++) {
+ char **val1 = &attr_list[i-1];
+ char **val2 = &attr_list[i];
+ if (ldb_attr_cmp(*val1, *val2) == 0) {
+ memmove(val1, val2, (new_len - i) * sizeof( *attr_list));
+ new_len--;
+ i--;
+ }
+ }
+ }
+ return attr_list;
+}
diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c
new file mode 100644
index 0000000000..431ea3da65
--- /dev/null
+++ b/source4/dsdb/schema/schema_set.c
@@ -0,0 +1,254 @@
+/*
+ Unix SMB/CIFS mplementation.
+ DSDB schema header
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "lib/util/dlinklist.h"
+#include "param/param.h"
+
+/**
+ * Attach the schema to an opaque pointer on the ldb, so ldb modules
+ * can find it
+ */
+
+int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
+{
+ int ret;
+
+ ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ talloc_steal(ldb, schema);
+
+ return LDB_SUCCESS;
+}
+
+/**
+ * Global variable to hold one copy of the schema, used to avoid memory bloat
+ */
+static struct dsdb_schema *global_schema;
+
+/**
+ * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
+ */
+int dsdb_set_global_schema(struct ldb_context *ldb)
+{
+ int ret;
+ if (!global_schema) {
+ return LDB_SUCCESS;
+ }
+ ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* Keep a reference to this schema, just incase the global copy is replaced */
+ if (talloc_reference(ldb, global_schema) == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/**
+ * Find the schema object for this ldb
+ */
+
+struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
+{
+ const void *p;
+ struct dsdb_schema *schema;
+
+ /* see if we have a cached copy */
+ p = ldb_get_opaque(ldb, "dsdb_schema");
+ if (!p) {
+ return NULL;
+ }
+
+ schema = talloc_get_type(p, struct dsdb_schema);
+ if (!schema) {
+ return NULL;
+ }
+
+ return schema;
+}
+
+/**
+ * Make the schema found on this ldb the 'global' schema
+ */
+
+void dsdb_make_schema_global(struct ldb_context *ldb)
+{
+ struct dsdb_schema *schema = dsdb_get_schema(ldb);
+ if (!schema) {
+ return;
+ }
+
+ if (global_schema) {
+ talloc_unlink(talloc_autofree_context(), schema);
+ }
+
+ talloc_steal(talloc_autofree_context(), schema);
+ global_schema = schema;
+
+ dsdb_set_global_schema(ldb);
+}
+
+
+/**
+ * Rather than read a schema from the LDB itself, read it from an ldif
+ * file. This allows schema to be loaded and used while adding the
+ * schema itself to the directory.
+ */
+
+WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df)
+{
+ struct ldb_ldif *ldif;
+ struct ldb_message *msg;
+ TALLOC_CTX *mem_ctx;
+ WERROR status;
+ int ret;
+ struct dsdb_schema *schema;
+ const struct ldb_val *prefix_val;
+ const struct ldb_val *info_val;
+ struct ldb_val info_val_default;
+
+ mem_ctx = talloc_new(ldb);
+ if (!mem_ctx) {
+ goto nomem;
+ }
+
+ schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")));
+
+ schema->fsmo.we_are_master = true;
+ schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
+ if (!schema->fsmo.master_dn) {
+ goto nomem;
+ }
+
+ /*
+ * load the prefixMap attribute from pf
+ */
+ ldif = ldb_ldif_read_string(ldb, &pf);
+ if (!ldif) {
+ status = WERR_INVALID_PARAM;
+ goto failed;
+ }
+ talloc_steal(mem_ctx, ldif);
+
+ msg = ldb_msg_canonicalize(ldb, ldif->msg);
+ if (!msg) {
+ goto nomem;
+ }
+ talloc_steal(mem_ctx, msg);
+ talloc_free(ldif);
+
+ prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
+ if (!prefix_val) {
+ status = WERR_INVALID_PARAM;
+ goto failed;
+ }
+
+ info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
+ if (!info_val) {
+ info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000");
+ if (!info_val_default.data) {
+ goto nomem;
+ }
+ talloc_steal(mem_ctx, info_val_default.data);
+ info_val = &info_val_default;
+ }
+
+ status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
+ if (!W_ERROR_IS_OK(status)) {
+ goto failed;
+ }
+
+ /*
+ * load the attribute and class definitions outof df
+ */
+ while ((ldif = ldb_ldif_read_string(ldb, &df))) {
+ bool is_sa;
+ bool is_sc;
+
+ talloc_steal(mem_ctx, ldif);
+
+ msg = ldb_msg_canonicalize(ldb, ldif->msg);
+ if (!msg) {
+ goto nomem;
+ }
+
+ talloc_steal(mem_ctx, msg);
+ talloc_free(ldif);
+
+ is_sa = ldb_msg_check_string_attribute(msg, "objectClass", "attributeSchema");
+ is_sc = ldb_msg_check_string_attribute(msg, "objectClass", "classSchema");
+
+ if (is_sa) {
+ struct dsdb_attribute *sa;
+
+ sa = talloc_zero(schema, struct dsdb_attribute);
+ if (!sa) {
+ goto nomem;
+ }
+
+ status = dsdb_attribute_from_ldb(schema, msg, sa, sa);
+ if (!W_ERROR_IS_OK(status)) {
+ goto failed;
+ }
+
+ DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
+ } else if (is_sc) {
+ struct dsdb_class *sc;
+
+ sc = talloc_zero(schema, struct dsdb_class);
+ if (!sc) {
+ goto nomem;
+ }
+
+ status = dsdb_class_from_ldb(schema, msg, sc, sc);
+ if (!W_ERROR_IS_OK(status)) {
+ goto failed;
+ }
+
+ DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
+ }
+ }
+
+ ret = dsdb_set_schema(ldb, schema);
+ if (ret != LDB_SUCCESS) {
+ status = WERR_FOOBAR;
+ goto failed;
+ }
+
+ goto done;
+
+nomem:
+ status = WERR_NOMEM;
+failed:
+done:
+ talloc_free(mem_ctx);
+ return status;
+}