Split schema_init.c into smaller bits.
authorAndrew Bartlett <abartlet@samba.org>
Wed, 20 Aug 2008 03:22:16 +0000 (13:22 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 20 Aug 2008 03:22:16 +0000 (13:22 +1000)
This should make schema manipulation a little easier to follow.

Andrew Bartlett

source/dsdb/config.mk
source/dsdb/schema/schema_init.c
source/dsdb/schema/schema_query.c [new file with mode: 0644]
source/dsdb/schema/schema_set.c [new file with mode: 0644]

index ae35078537242f87af56769367884fb5741ad42c..63e8a77ce4c96ec79b53c0ac32719098ae599986 100644 (file)
@@ -34,6 +34,8 @@ PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS
 
 SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \
                schema_init.o \
+               schema_set.o \
+               schema_query.o \
                schema_syntax.o \
                schema_description.o)
 
index 73be58034791961db0f1f82118a49390b7d5607d..3ed7daee5953aa8a778436a01baf08ea286708dc 100644 (file)
@@ -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/source/dsdb/schema/schema_query.c b/source/dsdb/schema/schema_query.c
new file mode 100644 (file)
index 0000000..ca26ffd
--- /dev/null
@@ -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/source/dsdb/schema/schema_set.c b/source/dsdb/schema/schema_set.c
new file mode 100644 (file)
index 0000000..431ea3d
--- /dev/null
@@ -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;
+}