Make ad2oLschema even simpler, by moving the heavy work into dsdb.
authorAndrew Bartlett <abartlet@samba.org>
Thu, 10 Jul 2008 05:52:44 +0000 (15:52 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 10 Jul 2008 05:52:44 +0000 (15:52 +1000)
This will allow the kludge_acl and schema code to leverage the same
work.  (We might even get schema validation soon! :-)

Andrew Bartlett
(This used to be commit cecd04ce1f8ce2af2fb654b3abc1499092405d60)

source4/dsdb/samdb/ldb_modules/schema_fsmo.c
source4/dsdb/schema/schema.h
source4/dsdb/schema/schema_init.c
source4/utils/ad2oLschema.c

index 6f65c199baf4250a60ad8e339886f40e050a327b..a3972287232600541bb5e28e961124d9f355873f 100644 (file)
@@ -37,17 +37,8 @@ static int schema_fsmo_init(struct ldb_module *module)
        TALLOC_CTX *mem_ctx;
        struct ldb_dn *schema_dn;
        struct dsdb_schema *schema;
-       struct ldb_result *schema_res;
-       struct ldb_result *a_res;
-       struct ldb_result *c_res;
        char *error_string = NULL;
        int ret;
-       static const char *schema_attrs[] = {
-               "prefixMap",
-               "schemaInfo",
-               "fSMORoleOwner",
-               NULL
-       };
 
        if (dsdb_get_schema(module->ldb)) {
                return ldb_next_init(module);
@@ -67,83 +58,25 @@ static int schema_fsmo_init(struct ldb_module *module)
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       /*
-        * setup the prefix mappings and schema info
-        */
-       ret = ldb_search(module->ldb, schema_dn,
-                        LDB_SCOPE_BASE,
-                        NULL, schema_attrs,
-                        &schema_res);
+       ret = dsdb_schema_from_schema_dn(mem_ctx, module->ldb,
+                                        lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
+                                        schema_dn, &schema, &error_string);
+
        if (ret == LDB_ERR_NO_SUCH_OBJECT) {
                ldb_reset_err_string(module->ldb);
                ldb_debug(module->ldb, LDB_DEBUG_WARNING,
                          "schema_fsmo_init: no schema head present: (skip schema loading)\n");
                talloc_free(mem_ctx);
                return ldb_next_init(module);
-       } else if (ret != LDB_SUCCESS) {
-               ldb_asprintf_errstring(module->ldb, 
-                                      "schema_fsmo_init: failed to search the schema head: %s",
-                                      ldb_errstring(module->ldb));
-               talloc_free(mem_ctx);
-               return ret;
-       }
-       talloc_steal(mem_ctx, schema_res);
-       if (schema_res->count == 0) {
-               ldb_debug(module->ldb, LDB_DEBUG_WARNING,
-                         "schema_fsmo_init: no schema head present: (skip schema loading)\n");
-               talloc_free(mem_ctx);
-               return ldb_next_init(module);
-       } else if (schema_res->count > 1) {
-               ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
-                             "schema_fsmo_init: [%u] schema heads found on a base search",
-                             schema_res->count);
-               talloc_free(mem_ctx);
-               return LDB_ERR_CONSTRAINT_VIOLATION;
-       }
-
-       /*
-        * load the attribute definitions
-        */
-       ret = ldb_search(module->ldb, schema_dn,
-                        LDB_SCOPE_ONELEVEL,
-                        "(objectClass=attributeSchema)", NULL,
-                        &a_res);
-       if (ret != LDB_SUCCESS) {
-               ldb_asprintf_errstring(module->ldb, 
-                                      "schema_fsmo_init: failed to search attributeSchema objects: %s",
-                                      ldb_errstring(module->ldb));
-               talloc_free(mem_ctx);
-               return ret;
-       }
-       talloc_steal(mem_ctx, a_res);
-
-       /*
-        * load the objectClass definitions
-        */
-       ret = ldb_search(module->ldb, schema_dn,
-                        LDB_SCOPE_ONELEVEL,
-                        "(objectClass=classSchema)", NULL,
-                        &c_res);
-       if (ret != LDB_SUCCESS) {
-               ldb_asprintf_errstring(module->ldb, 
-                                      "schema_fsmo_init: failed to search classSchema objects: %s",
-                                      ldb_errstring(module->ldb));
-               talloc_free(mem_ctx);
-               return ret;
        }
-       talloc_steal(mem_ctx, c_res);
 
-       ret = dsdb_schema_from_ldb_results(mem_ctx, module->ldb,
-                                          lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
-                                          schema_res, a_res, c_res, &schema, &error_string);
        if (ret != LDB_SUCCESS) {
                ldb_asprintf_errstring(module->ldb, 
                                       "schema_fsmo_init: dsdb_schema load failed: %s",
                                       error_string);
                talloc_free(mem_ctx);
-               return ret;
        }
-       
+
        /* dsdb_set_schema() steal schema into the ldb_context */
        ret = dsdb_set_schema(module->ldb, schema);
        if (ret != LDB_SUCCESS) {
index 6fce354f7cc981d59fe6da47418fa27b15858f61..66cc867a197bc14a80dc5c1a2accfb49aac5f118 100644 (file)
@@ -158,6 +158,15 @@ struct dsdb_schema {
        struct smb_iconv_convenience *iconv_convenience;
 };
 
+enum dsdb_attr_list_query {
+       DSDB_SCHEMA_ALL_MAY,
+       DSDB_SCHEMA_ALL_MUST,
+       DSDB_SCHEMA_SYS_MAY,
+       DSDB_SCHEMA_SYS_MUST,
+       DSDB_SCHEMA_MAY,
+       DSDB_SCHEMA_MUST
+};
+
 #include "dsdb/schema/proto.h"
 
 #endif /* _DSDB_SCHEMA_H */
index 826f91b5f0d770f16e60d2f3ee55e7b9f857be1a..3a6a8f5553594a74e34a16aa4c42d11f383f0f57 100644 (file)
@@ -2,8 +2,8 @@
    Unix SMB/CIFS mplementation.
    DSDB schema header
    
-   Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
-   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+   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
@@ -624,7 +624,7 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
                status = dsdb_attribute_from_ldb(schema, attrs_res->msgs[i], sa, sa);
                if (!W_ERROR_IS_OK(status)) {
                        *error_string = talloc_asprintf(mem_ctx, 
-                                     "schema_fsmo_init: failed to load attriute definition: %s:%s",
+                                     "schema_fsmo_init: failed to load attribute definition: %s:%s",
                                      ldb_dn_get_linearized(attrs_res->msgs[i]->dn),
                                      win_errstr(status));
                        talloc_free(mem_ctx);
@@ -670,6 +670,191 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
        return LDB_SUCCESS;
 }
 
+/* This recursive load of the objectClasses presumes that they
+ * everything is in a strict subClassOf hirarchy.  
+ *
+ * We load this in order so we produce certain outputs (such as the
+ * exported schema for openldap, and sorted objectClass attribute) 'in
+ * order' */
+
+static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn, 
+                             TALLOC_CTX *mem_ctx, 
+                             struct ldb_result *search_from,
+                             struct ldb_result *res_list)
+{
+       int i;
+       int ret = 0;
+       for (i=0; i < search_from->count; i++) {
+               struct ldb_result *res;
+               const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i], 
+                                                              "lDAPDisplayname", NULL);
+
+               ret = ldb_search_exp_fmt(ldb, mem_ctx, &res,
+                                       schemadn, LDB_SCOPE_SUBTREE, NULL,
+                                       "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
+                                       name, name);
+               if (ret != LDB_SUCCESS) {
+                       printf("Search failed: %s\n", ldb_errstring(ldb));
+                       return ret;
+               }
+               
+               res_list->msgs = talloc_realloc(res_list, res_list->msgs, 
+                                               struct ldb_message *, res_list->count + 2);
+               if (!res_list->msgs) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               res_list->msgs[res_list->count] = talloc_move(res_list, 
+                                                             &search_from->msgs[i]);
+               res_list->count++;
+               res_list->msgs[res_list->count] = NULL;
+
+               if (res->count > 0) {
+                       ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list); 
+               }
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn, 
+                                   TALLOC_CTX *mem_ctx, 
+                                   struct ldb_result **objectclasses_res)
+{
+       TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
+       struct ldb_result *top_res, *ret_res;
+       int ret;
+       if (!local_ctx) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       /* Downlaod 'top' */
+       ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
+                        "(&(objectClass=classSchema)(lDAPDisplayName=top))", 
+                        NULL, &top_res);
+       if (ret != LDB_SUCCESS) {
+               printf("Search failed: %s\n", ldb_errstring(ldb));
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       talloc_steal(local_ctx, top_res);
+
+       if (top_res->count != 1) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret_res = talloc_zero(local_ctx, struct ldb_result);
+       if (!ret_res) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res); 
+
+       if (ret != LDB_SUCCESS) {
+               printf("Search failed: %s\n", ldb_errstring(ldb));
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       *objectclasses_res = talloc_move(mem_ctx, &ret_res);
+       return ret;
+}
+
+int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+                              struct smb_iconv_convenience *iconv_convenience, 
+                              struct ldb_dn *schema_dn,
+                              struct dsdb_schema **schema,
+                              char **error_string_out) 
+{
+       TALLOC_CTX *tmp_ctx;
+       char *error_string;
+       int ret;
+
+       struct ldb_result *schema_res;
+       struct ldb_result *a_res;
+       struct ldb_result *c_res;
+       static const char *schema_attrs[] = {
+               "prefixMap",
+               "schemaInfo",
+               "fSMORoleOwner",
+               NULL
+       };
+
+       tmp_ctx = talloc_new(mem_ctx);
+       if (!tmp_ctx) {
+               dsdb_oom(error_string_out, mem_ctx);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /*
+        * setup the prefix mappings and schema info
+        */
+       ret = ldb_search(ldb, schema_dn,
+                        LDB_SCOPE_BASE,
+                        NULL, schema_attrs,
+                        &schema_res);
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return ret;
+       } else if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                      "dsdb_schema: failed to search the schema head: %s",
+                                      ldb_errstring(ldb));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+       talloc_steal(tmp_ctx, schema_res);
+       if (schema_res->count != 1) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                             "dsdb_schema: [%u] schema heads found on a base search",
+                             schema_res->count);
+               talloc_free(tmp_ctx);
+               return LDB_ERR_CONSTRAINT_VIOLATION;
+       }
+
+       /*
+        * load the attribute definitions
+        */
+       ret = ldb_search(ldb, schema_dn,
+                        LDB_SCOPE_ONELEVEL,
+                        "(objectClass=attributeSchema)", NULL,
+                        &a_res);
+       if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                      "dsdb_schema: failed to search attributeSchema objects: %s",
+                                      ldb_errstring(ldb));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+       talloc_steal(tmp_ctx, a_res);
+
+       /*
+        * load the objectClass definitions
+        */
+       ret = fetch_objectclass_schema(ldb, schema_dn, tmp_ctx, &c_res);
+       if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                      "Failed to fetch objectClass schema elements: %s\n", ldb_errstring(ldb));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+
+       ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb,
+                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+                                          schema_res, a_res, c_res, schema, &error_string);
+       if (ret != LDB_SUCCESS) {
+               *error_string_out = talloc_asprintf(mem_ctx, 
+                                                   "dsdb_schema load failed: %s",
+                                                   error_string);
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+       talloc_steal(mem_ctx, *schema);
+       talloc_free(tmp_ctx);
+
+       return LDB_SUCCESS;
+}      
+
 
 static const struct {
        const char *name;
@@ -1167,6 +1352,13 @@ const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
        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;
@@ -1187,6 +1379,114 @@ WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *sche
        return WERR_OK;
 }
 
+static 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;
+}
+
+char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, 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 **recursive_list;
+
+       for (i=0; class_list && class_list[i]; i++) {
+               class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]);
+               
+               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;
+               }
+
+               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, 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 
index 879b1a7213f775c64a952398b8ca776281d339f7..51b03b8e8f9a3ddd296fc2c05bd3ca36d5a0ebff 100644 (file)
@@ -67,114 +67,13 @@ static void usage(void)
        exit(1);
 }
 
-static int fetch_attrs_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
-                             TALLOC_CTX *mem_ctx, 
-                             struct ldb_result **attrs_res)
-{
-       int ret;
-
-       /* Downlaod schema */
-       ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
-                        "objectClass=attributeSchema", 
-                        NULL, attrs_res);
-       if (ret != LDB_SUCCESS) {
-               printf("Search failed: %s\n", ldb_errstring(ldb));
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       
-       return ret;
-}
-
-static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn, 
-                             TALLOC_CTX *mem_ctx, 
-                             struct ldb_result *search_from,
-                             struct ldb_result *res_list)
-{
-       int i;
-       int ret = 0;
-       for (i=0; i < search_from->count; i++) {
-               struct ldb_result *res;
-               const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i], 
-                                                              "lDAPDisplayname", NULL);
-
-               ret = ldb_search_exp_fmt(ldb, mem_ctx, &res,
-                                       schemadn, LDB_SCOPE_SUBTREE, NULL,
-                                       "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
-                                       name, name);
-               if (ret != LDB_SUCCESS) {
-                       printf("Search failed: %s\n", ldb_errstring(ldb));
-                       return ret;
-               }
-               
-               res_list->msgs = talloc_realloc(res_list, res_list->msgs, 
-                                               struct ldb_message *, res_list->count + 2);
-               if (!res_list->msgs) {
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-               res_list->msgs[res_list->count] = talloc_move(res_list, 
-                                                             &search_from->msgs[i]);
-               res_list->count++;
-               res_list->msgs[res_list->count] = NULL;
-
-               if (res->count > 0) {
-                       ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list); 
-               }
-               if (ret != LDB_SUCCESS) {
-                       return ret;
-               }
-       }
-       return ret;
-}
-
-static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn, 
-                                   TALLOC_CTX *mem_ctx, 
-                                   struct ldb_result **objectclasses_res)
-{
-       TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
-       struct ldb_result *top_res, *ret_res;
-       int ret;
-       if (!local_ctx) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       
-       /* Downlaod 'top' */
-       ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
-                        "(&(objectClass=classSchema)(lDAPDisplayName=top))", 
-                        NULL, &top_res);
-       if (ret != LDB_SUCCESS) {
-               printf("Search failed: %s\n", ldb_errstring(ldb));
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       talloc_steal(local_ctx, top_res);
-
-       if (top_res->count != 1) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ret_res = talloc_zero(local_ctx, struct ldb_result);
-       if (!ret_res) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res); 
-
-       if (ret != LDB_SUCCESS) {
-               printf("Search failed: %s\n", ldb_errstring(ldb));
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       *objectclasses_res = talloc_move(mem_ctx, &ret_res);
-       return ret;
-}
-
-static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
-                                    struct ldb_result **schema_res) 
+static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 
 {
        const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
        struct ldb_dn *schemadn;
        struct ldb_dn *basedn = ldb_dn_new(mem_ctx, ldb, NULL);
        struct ldb_result *rootdse_res;
+       struct ldb_result *schema_res;
        int ldb_ret;
        
        if (!basedn) {
@@ -186,126 +85,42 @@ static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ct
        if (ldb_ret != LDB_SUCCESS) {
                ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, 
                                 "(&(objectClass=dMD)(cn=Schema))", 
-                                NULL, schema_res);
+                                NULL, &schema_res);
                if (ldb_ret) {
                        printf("cn=Schema Search failed: %s\n", ldb_errstring(ldb));
                        return NULL;
                }
 
-               talloc_steal(mem_ctx, *schema_res);
+               talloc_steal(mem_ctx, schema_res);
 
-               if ((*schema_res)->count != 1) {
+               if (schema_res->count != 1) {
+                       talloc_free(schema_res);
                        printf("Failed to find rootDSE");
                        return NULL;
                }
                
-               schemadn = talloc_steal(mem_ctx, (*schema_res)->msgs[0]->dn);
+               schemadn = talloc_steal(mem_ctx, schema_res->msgs[0]->dn);
+               talloc_free(schema_res);
                return schemadn;
-               
        }
        
-       talloc_steal(mem_ctx, rootdse_res);
-
        if (rootdse_res->count != 1) {
                printf("Failed to find rootDSE");
+               talloc_free(rootdse_res);
                return NULL;
        }
        
        /* Locate schema */
        schemadn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
-       if (!schemadn) {
-               return NULL;
-       }
+       talloc_free(rootdse_res);
 
-       ldb_ret = ldb_search(ldb, schemadn, LDB_SCOPE_BASE, 
-                            "(&(objectClass=dMD)(cn=Schema))", 
-                            NULL, schema_res);
-       if (ldb_ret) {
-               printf("cn=Schema Search failed: %s\n", ldb_errstring(ldb));
+       if (!schemadn) {
                return NULL;
        }
-       
-       talloc_steal(mem_ctx, *schema_res);
 
-       if ((*schema_res)->count != 1) {
-               printf("Failed to find rootDSE");
-               return NULL;
-       }
-       talloc_free(rootdse_res);
        return schemadn;
 }
 
-static bool merge_attr_list(TALLOC_CTX *mem_ctx, 
-                           struct ldb_message_element *attrs, struct ldb_message_element *new_attrs) 
-{
-       struct ldb_val *values;
-       if (!new_attrs) {
-               return true;
-       }
-
-       values = talloc_realloc(mem_ctx, 
-                               attrs->values, struct ldb_val, attrs->num_values + new_attrs->num_values);
-       
-       attrs->values = values;
-
-       memcpy(&attrs->values[attrs->num_values], new_attrs->values, sizeof(*new_attrs->values) * new_attrs->num_values);
-       attrs->num_values = attrs->num_values + new_attrs->num_values;
-
-       /* Add sort and unique implementation here */
-
-       return true;
-}
-
-static bool find_aux_classes(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldb_dn *schema_dn,
-                            struct ldb_message_element *aux_class, struct ldb_message_element *must, 
-                            struct ldb_message_element *sys_must, struct ldb_message_element *may, 
-                            struct ldb_message_element *sys_may) 
-{
-       int i, ret;
-       struct ldb_message *msg;
-       struct ldb_result *res;
-
-       for (i=0; aux_class && i < aux_class->num_values; i++) {
-               ret = ldb_search_exp_fmt(ldb, mem_ctx, &res,
-                                        schema_dn, LDB_SCOPE_SUBTREE, NULL,
-                                        "(&(objectClass=classSchema)(lDAPDisplayName=%s))",
-                                        aux_class->values[i].data);
-               if (ret != LDB_SUCCESS) {
-                       return false;
-               }
-
-               msg = res->msgs[0];
-
-               if (!merge_attr_list(mem_ctx, must, ldb_msg_find_element(msg, "mustContain"))) {
-                       return false;
-               }
-               if (!merge_attr_list(mem_ctx, sys_must,  ldb_msg_find_element(msg, "systemMustContain"))) {
-                       return false;
-               }
-               if (!merge_attr_list(mem_ctx, may, ldb_msg_find_element(msg, "mayContain"))) {
-                       return false;
-               }
-               if (!merge_attr_list(mem_ctx, sys_may, ldb_msg_find_element(msg, "systemMayContain"))) {
-                       return false;
-               }
-               
-               
-               if (res->count == 0) {
-                       return false;
-               }
-
-               if (!find_aux_classes(mem_ctx, ldb, schema_dn,
-                                     ldb_msg_find_element(msg, "auxiliaryClass"), must, sys_must, may, sys_may)) {
-                       return false;
-               }
-               if (!find_aux_classes(mem_ctx, ldb, schema_dn,
-                                     ldb_msg_find_element(msg, "systemAuxiliaryClass"), must, sys_must, may, sys_may)) {
-                       return false;
-               }
-       }
-       return true;
-}
-
 
 #define IF_NULL_FAIL_RET(x) do {     \
                if (!x) {               \
@@ -332,13 +147,14 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                char *new_attr;
        } *attr_map = NULL;
        int num_attr_maps = 0;  
-       struct ldb_result *schema_res, *attrs_res, *objectclasses_res;
+       struct dsdb_class *objectclass;
+       struct dsdb_attribute *attribute;
        struct ldb_dn *schemadn;
        struct schema_conv ret;
        struct dsdb_schema *schema;
        char *error_string;
 
-       int ldb_ret, i;
+       int ldb_ret;
 
        ret.count = 0;
        ret.skipped = 0;
@@ -389,31 +205,16 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                }
        }
 
-       schemadn = find_schema_dn(ldb, mem_ctx, &schema_res);
+       schemadn = find_schema_dn(ldb, mem_ctx);
        if (!schemadn) {
                printf("Failed to find schema DN: %s\n", ldb_errstring(ldb));
                ret.failures = 1;
                return ret;
        }
        
-       ldb_ret = fetch_attrs_schema(ldb, schemadn, mem_ctx, &attrs_res);
-       if (ldb_ret != LDB_SUCCESS) {
-               printf("Failed to fetch attribute schema: %s\n", ldb_errstring(ldb));
-               ret.failures = 1;
-               return ret;
-       }
-
-
-       ldb_ret = fetch_objectclass_schema(ldb, schemadn, mem_ctx, &objectclasses_res);
-       if (ldb_ret != LDB_SUCCESS) {
-               printf("Failed to fetch objectClass schema elements: %s\n", ldb_errstring(ldb));
-               ret.failures = 1;
-               return ret;
-       }
-       
-       ldb_ret = dsdb_schema_from_ldb_results(mem_ctx, ldb,
-                                              lp_iconv_convenience(cmdline_lp_ctx),
-                                              schema_res, attrs_res, objectclasses_res, &schema, &error_string);
+       ldb_ret = dsdb_schema_from_schema_dn(mem_ctx, ldb,
+                                            lp_iconv_convenience(cmdline_lp_ctx),
+                                            schemadn, &schema, &error_string);
        if (ldb_ret != LDB_SUCCESS) {
                printf("Failed to load schema: %s\n", error_string);
                ret.failures = 1;
@@ -428,24 +229,17 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                break;
        }
 
-       for (i=0; i < attrs_res->count; i++) {
-               struct ldb_message *msg = attrs_res->msgs[i];
+       for (attribute=schema->attributes; attribute; attribute = attribute->next) {
+               const char *name = attribute->lDAPDisplayName;
+               const char *description = attribute->adminDescription;
+               const char *oid = attribute->attributeID_oid;
+               const char *syntax = attribute->attributeSyntax_oid;
+               bool single_value = attribute->isSingleValued;
 
-               const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL);
-               const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL);
-               const char *oid = ldb_msg_find_attr_as_string(msg, "attributeID", NULL);
-               const char *syntax = ldb_msg_find_attr_as_string(msg, "attributeSyntax", NULL);
-               bool single_value = ldb_msg_find_attr_as_bool(msg, "isSingleValued", false);
                const struct syntax_map *map = find_syntax_map_by_ad_oid(syntax);
                char *schema_entry = NULL;
                int j;
 
-               if (!name) {
-                       printf("Failed to find lDAPDisplayName for schema DN: %s\n", ldb_dn_get_linearized(msg->dn));
-                       ret.failures++;
-                       continue;
-               }
-
                /* We have been asked to skip some attributes/objectClasses */
                if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
                        ret.skipped++;
@@ -487,9 +281,11 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                IF_NULL_FAIL_RET(schema_entry);
 
                if (description) {
+#if 0 /* If you want to re-enable this, you must first figure out a sane escaping of ' in the description */
                        schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  DESC %s\n", description);
+                                                             "  DESC '%s'\n", description);
                        IF_NULL_FAIL_RET(schema_entry);
+#endif
                }
 
                if (map) {
@@ -539,59 +335,31 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                ret.count++;
        }
 
-       for (i=0; i < objectclasses_res->count; i++) {
-               struct ldb_message *msg = objectclasses_res->msgs[i];
-               const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL);
-               const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL);
-               const char *oid = ldb_msg_find_attr_as_string(msg, "governsID", NULL);
-               const char *subClassOf = ldb_msg_find_attr_as_string(msg, "subClassOf", NULL);
-               int objectClassCategory = ldb_msg_find_attr_as_int(msg, "objectClassCategory", 0);
-               struct ldb_message_element *must = ldb_msg_find_element(msg, "mustContain");
-               struct ldb_message_element *sys_must = ldb_msg_find_element(msg, "systemMustContain");
-               struct ldb_message_element *may = ldb_msg_find_element(msg, "mayContain");
-               struct ldb_message_element *sys_may = ldb_msg_find_element(msg, "systemMayContain");
-               struct ldb_message_element *aux_class = ldb_msg_find_element(msg, "auxiliaryClass");
-               struct ldb_message_element *sys_aux_class = ldb_msg_find_element(msg, "systemAuxiliaryClass");
+       /* This is already sorted to have 'top' and similar classes first */
+       for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) {
+               const char *name = objectclass->lDAPDisplayName;
+               const char *description = objectclass->adminDescription;
+               const char *oid = objectclass->governsID_oid;
+               const char *subClassOf = objectclass->subClassOf;
+               int objectClassCategory = objectclass->objectClassCategory;
+               char **must;
+               char **may;
                char *schema_entry = NULL;
+               const char *objectclass_name_as_list[] = {
+                       objectclass->lDAPDisplayName,
+                       NULL
+               };
                int j;
-
-               if (!name) {
-                       printf("Failed to find lDAPDisplayName for schema DN: %s\n", ldb_dn_get_linearized(msg->dn));
-                       ret.failures++;
-                       continue;
-               }
-
+               
                /* We have been asked to skip some attributes/objectClasses */
                if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
                        ret.skipped++;
                        continue;
                }
 
-               if (must == NULL) {
-                       must = talloc_zero(mem_ctx, struct ldb_message_element);
-               }
-
-               if (may == NULL) {
-                       may = talloc_zero(mem_ctx, struct ldb_message_element);
-               }
-
-               if (sys_must == NULL) {
-                       sys_must = talloc_zero(mem_ctx, struct ldb_message_element);
-               }
-
-               if (sys_may == NULL) {
-                       sys_may = talloc_zero(mem_ctx, struct ldb_message_element);
-               }
+               may = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MAY);
 
-               if (!find_aux_classes(mem_ctx, ldb, schemadn, aux_class, must, sys_must, may, sys_may)) {
-                       ret.failures++;
-                       continue;
-               }
-
-               if (!find_aux_classes(mem_ctx, ldb, schemadn, sys_aux_class, must, sys_must, may, sys_may)) {
-                       ret.failures++;
-                       continue;
-               }
+               must = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MUST);
 
                /* We might have been asked to remap this oid, due to a conflict */
                for (j=0; oid_map && oid_map[j].old_oid; j++) {
@@ -635,7 +403,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
 
                if (description) {
                        schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  DESC %s\n", description);
+                                                             "  DESC '%s'\n", description);
                        IF_NULL_FAIL_RET(schema_entry);
                }
 
@@ -666,9 +434,9 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
 #define APPEND_ATTRS(attributes) \
                do {                                            \
                        int k;                                          \
-                       for (k=0; attributes && k < attributes->num_values; k++) { \
+                       for (k=0; attributes && attributes[k]; k++) { \
                                int attr_idx; \
-                               const char *attr_name = (const char *)attributes->values[k].data;  \
+                               const char *attr_name = attributes[k];  \
                                /* We might have been asked to remap this name, due to a conflict */ \
                                for (attr_idx=0; attr_name && attr_map && attr_map[attr_idx].old_attr; attr_idx++) { \
                                        if (strcasecmp(attr_name, attr_map[attr_idx].old_attr) == 0) { \
@@ -681,7 +449,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                                                                      " %s", \
                                                                      attr_name); \
                                IF_NULL_FAIL_RET(schema_entry);         \
-                               if (k != (attributes->num_values - 1)) { \
+                               if (attributes[k+1]) { \
                                        schema_entry = talloc_asprintf_append(schema_entry, \
                                                                              " $"); \
                                        IF_NULL_FAIL_RET(schema_entry); \
@@ -694,35 +462,25 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        }                                               \
                } while (0)
 
-               if ((must && must->values) || (sys_must && sys_must->values)) {
+               if (must) {
                        schema_entry = talloc_asprintf_append(schema_entry, 
                                                              "  MUST (");
                        IF_NULL_FAIL_RET(schema_entry);
 
                        APPEND_ATTRS(must);
-                       if (must && must->values && sys_must && sys_must->values) {
-                               schema_entry = talloc_asprintf_append(schema_entry, \
-                                                                     " $"); \
-                       }
-                       APPEND_ATTRS(sys_must);
-                       
+
                        schema_entry = talloc_asprintf_append(schema_entry, 
                                                              " )\n");
                        IF_NULL_FAIL_RET(schema_entry);
                }
 
-               if ((may && may->values) || (sys_may && sys_may->values)) {
+               if (may) {
                        schema_entry = talloc_asprintf_append(schema_entry, 
                                                              "  MAY (");
                        IF_NULL_FAIL_RET(schema_entry);
 
                        APPEND_ATTRS(may);
-                       if (may && may->values && sys_may && sys_may->values) {
-                               schema_entry = talloc_asprintf_append(schema_entry, \
-                                                                     " $"); \
-                       }
-                       APPEND_ATTRS(sys_may);
-                       
+
                        schema_entry = talloc_asprintf_append(schema_entry, 
                                                              " )\n");
                        IF_NULL_FAIL_RET(schema_entry);