Rework generation of the objectClass and attributeType lines.
[tprouty/samba.git] / source4 / utils / ad2oLschema.c
index 879b1a7213f775c64a952398b8ca776281d339f7..1e6348bc1a2e24f7f2e454b0cbedaad722f8ccd5 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    ldb database library
 
-   Copyright (C) Andrew Bartlett 2006
+   Copyright (C) Andrew Bartlett 2006-2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -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,134 +85,214 @@ 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 */
+#define IF_NULL_FAIL_RET(x) do {     \
+               if (!x) {               \
+                       return NULL;    \
+               }                       \
+       } while (0) 
 
-       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) 
+static char *schema_attribute_description(TALLOC_CTX *mem_ctx, 
+                                         enum convert_target target,
+                                         const char *seperator,
+                                         const char *oid, 
+                                         const char *name,
+                                         const char *description,
+                                         struct syntax_map *map,
+                                         const char *syntax,
+                                         bool single_value, bool operational)
 {
-       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];
+       char *schema_entry = talloc_asprintf(mem_ctx, 
+                                            "(%s%s%s", seperator, oid, seperator);
+       
+       schema_entry = talloc_asprintf_append(schema_entry, 
+                                             "NAME '%s'%s", name, seperator);
+       IF_NULL_FAIL_RET(schema_entry);
+       
+       if (description) {
+#if 0          
+               /* Need a way to escape ' characters from the description */
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "DESC '%s'%s", description, seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+#endif
+       }
 
-               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 (map) {
+               if (map->equality) {
+                       schema_entry = talloc_asprintf_append(schema_entry, 
+                                                             "EQUALITY %s%s", map->equality, seperator);
+                       IF_NULL_FAIL_RET(schema_entry);
                }
-               if (!merge_attr_list(mem_ctx, sys_may, ldb_msg_find_element(msg, "systemMayContain"))) {
-                       return false;
+               if (map->substring) {
+                       schema_entry = talloc_asprintf_append(schema_entry, 
+                                                             "SUBSTR %s%s", map->substring, seperator);
+                       IF_NULL_FAIL_RET(schema_entry);
                }
                
-               
-               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;
-               }
+               syntax = map->Standard_OID;
        }
-       return true;
+       
+       schema_entry = talloc_asprintf_append(schema_entry, 
+                                             "SYNTAX %s%s", syntax, seperator);
+       IF_NULL_FAIL_RET(schema_entry);
+       
+       if (single_value) {
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "SINGLE-VALUE%s", seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+       }
+       
+       if (operational) {
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "NO-USER-MODIFICATION%s", seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+       }
+       
+       schema_entry = talloc_asprintf_append(schema_entry, 
+                                             ")");
+       return schema_entry;
 }
 
+static char *schema_class_description(TALLOC_CTX *mem_ctx, 
+                                     enum convert_target target,
+                                     const char *seperator,
+                                     const char *oid, 
+                                     const char *name,
+                                     const char *description,
+                                     const char *subClassOf,
+                                     int objectClassCategory,
+                                     char **must,
+                                     char **may)
+{
+       char *schema_entry = talloc_asprintf(mem_ctx, 
+                                            "(%s%s%s", seperator, oid, seperator);
+       
+       IF_NULL_FAIL_RET(schema_entry);
 
-#define IF_NULL_FAIL_RET(x) do {     \
-               if (!x) {               \
-                       ret.failures++; \
-                       return ret;     \
-               }                       \
-       } while (0) 
+       schema_entry = talloc_asprintf_append(schema_entry, 
+                                             "NAME '%s'%s", name, seperator);
+       IF_NULL_FAIL_RET(schema_entry);
+       
+       if (description) {
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "DESC '%s'%s", description, seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+       }
 
+       if (subClassOf) {
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "SUP %s%s", subClassOf, seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+       }
+       
+       switch (objectClassCategory) {
+       case 1:
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "STRUCTURAL%s", seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+               break;
+       case 2:
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "ABSTRACT%s", seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+               break;
+       case 3:
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "AUXILIARY%s", seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+               break;
+       }
+       
+#define APPEND_ATTRS(attributes)                               \
+       do {                                                            \
+               int k;                                                  \
+               for (k=0; attributes && attributes[k]; k++) {           \
+                       const char *attr_name = attributes[k];          \
+                                                                       \
+                       schema_entry = talloc_asprintf_append(schema_entry, \
+                                                             "%s ",    \
+                                                             attr_name); \
+                       IF_NULL_FAIL_RET(schema_entry);                 \
+                       if (attributes[k+1]) {                          \
+                               IF_NULL_FAIL_RET(schema_entry);         \
+                               if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \
+                                       schema_entry = talloc_asprintf_append(schema_entry, \
+                                                                             "$%s ", seperator); \
+                                       IF_NULL_FAIL_RET(schema_entry); \
+                               } else {                                \
+                                       schema_entry = talloc_asprintf_append(schema_entry, \
+                                                                             "$ "); \
+                               }                                       \
+                       }                                               \
+               }                                                       \
+       } while (0)
+       
+       if (must) {
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "MUST ( ");
+               IF_NULL_FAIL_RET(schema_entry);
+               
+               APPEND_ATTRS(must);
+               
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     ")%s", seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+       }
+       
+       if (may) {
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "MAY ( ");
+               IF_NULL_FAIL_RET(schema_entry);
+               
+               APPEND_ATTRS(may);
+               
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     ")%s", seperator);
+               IF_NULL_FAIL_RET(schema_entry);
+       }
+       
+       schema_entry = talloc_asprintf_append(schema_entry, 
+                                             ")");
+       return schema_entry;
+}
 
 static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_target target, FILE *in, FILE *out) 
 {
@@ -332,13 +311,15 @@ 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;
+       const char *seperator;
        char *error_string;
 
-       int ldb_ret, i;
+       int ldb_ret;
 
        ret.count = 0;
        ret.skipped = 0;
@@ -355,7 +336,10 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                }
                if (isdigit(line[0])) {
                        char *p = strchr(line, ':');
-                       IF_NULL_FAIL_RET(p);
+                       if (!p) {
+                               ret.failures++;
+                               return ret;
+                       }
                        p[0] = '\0';
                        p++;
                        oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
@@ -389,31 +373,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;
@@ -422,30 +391,26 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
 
        switch (target) {
        case TARGET_OPENLDAP:
+               seperator = "\n  ";
                break;
        case TARGET_FEDORA_DS:
+               seperator = "\n  ";
                fprintf(out, "dn: cn=schema\n");
                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);
+               const struct syntax_map *const_map = find_syntax_map_by_ad_oid(syntax);
+               struct syntax_map map, *map_p = NULL;
                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++;
@@ -460,19 +425,21 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        }
                }
                
-               switch (target) {
-               case TARGET_OPENLDAP:
-                       schema_entry = talloc_asprintf(mem_ctx, 
-                                                      "attributetype (\n"
-                                                      "  %s\n", oid);
-                       break;
-               case TARGET_FEDORA_DS:
-                       schema_entry = talloc_asprintf(mem_ctx, 
-                                                      "attributeTypes: (\n"
-                                                      "  %s\n", oid);
-                       break;
+               if (const_map) {
+                       map = *const_map;
+                       
+                       /* We might have been asked to remap this oid,
+                        * due to a conflict, or lack of
+                        * implementation */
+                       for (j=0; map.Standard_OID && oid_map && oid_map[j].old_oid; j++) {
+                               if (strcasecmp(map.Standard_OID, oid_map[j].old_oid) == 0) {
+                                       map.Standard_OID =  oid_map[j].new_oid;
+                                       break;
+                               }
+                       }
+
+                       map_p = &map;
                }
-               IF_NULL_FAIL_RET(schema_entry);
 
                /* We might have been asked to remap this name, due to a conflict */
                for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
@@ -482,117 +449,47 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        }
                }
                
-               schema_entry = talloc_asprintf_append(schema_entry, 
-                                                     "  NAME '%s'\n", name);
-               IF_NULL_FAIL_RET(schema_entry);
-
-               if (description) {
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  DESC %s\n", description);
-                       IF_NULL_FAIL_RET(schema_entry);
-               }
+               schema_entry = schema_attribute_description(mem_ctx, target, seperator, oid, name, description, map_p, syntax, single_value, false);
 
-               if (map) {
-                       const char *syntax_oid;
-                       if (map->equality) {
-                               schema_entry = talloc_asprintf_append(schema_entry, 
-                                                                     "  EQUALITY %s\n", map->equality);
-                               IF_NULL_FAIL_RET(schema_entry);
-                       }
-                       if (map->substring) {
-                               schema_entry = talloc_asprintf_append(schema_entry, 
-                                                                     "  SUBSTR %s\n", map->substring);
-                               IF_NULL_FAIL_RET(schema_entry);
-                       }
-                       syntax_oid = map->Standard_OID;
-                       /* We might have been asked to remap this oid,
-                        * due to a conflict, or lack of
-                        * implementation */
-                       for (j=0; syntax_oid && oid_map && oid_map[j].old_oid; j++) {
-                               if (strcasecmp(syntax_oid, oid_map[j].old_oid) == 0) {
-                                       syntax_oid =  oid_map[j].new_oid;
-                                       break;
-                               }
-                       }
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  SYNTAX %s\n", syntax_oid);
-                       IF_NULL_FAIL_RET(schema_entry);
-               }
-
-               if (single_value) {
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  SINGLE-VALUE\n");
-                       IF_NULL_FAIL_RET(schema_entry);
+               if (schema_entry == NULL) {
+                       ret.failures++;
+                       return ret;
                }
-               
-               schema_entry = talloc_asprintf_append(schema_entry, 
-                                                     "  )");
 
                switch (target) {
                case TARGET_OPENLDAP:
-                       fprintf(out, "%s\n\n", schema_entry);
+                       fprintf(out, "attributetype %s\n\n", schema_entry);
                        break;
                case TARGET_FEDORA_DS:
-                       fprintf(out, "%s\n", schema_entry);
+                       fprintf(out, "attributeTypes: %s\n", schema_entry);
                        break;
                }
                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;
-               }
-
+               int attr_idx;
+               
                /* 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);
-               }
-
-               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;
-               }
-
                /* We might have been asked to remap this oid, due to a conflict */
                for (j=0; oid_map && oid_map[j].old_oid; j++) {
                        if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
@@ -601,24 +498,6 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        }
                }
                
-               switch (target) {
-               case TARGET_OPENLDAP:
-                       schema_entry = talloc_asprintf(mem_ctx, 
-                                                      "objectclass (\n"
-                                                      "  %s\n", oid);
-                       break;
-               case TARGET_FEDORA_DS:
-                       schema_entry = talloc_asprintf(mem_ctx, 
-                                                      "objectClasses: (\n"
-                                                      "  %s\n", oid);
-                       break;
-               }
-               IF_NULL_FAIL_RET(schema_entry);
-               if (!schema_entry) {
-                       ret.failures++;
-                       break;
-               }
-
                /* We might have been asked to remap this name, due to a conflict */
                for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
                        if (strcasecmp(name, attr_map[j].old_attr) == 0) {
@@ -627,116 +506,50 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        }
                }
                
-               schema_entry = talloc_asprintf_append(schema_entry, 
-                                                     "  NAME '%s'\n", name);
-               IF_NULL_FAIL_RET(schema_entry);
-
-               if (!schema_entry) return ret;
-
-               if (description) {
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  DESC %s\n", description);
-                       IF_NULL_FAIL_RET(schema_entry);
-               }
-
-               if (subClassOf) {
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  SUP %s\n", subClassOf);
-                       IF_NULL_FAIL_RET(schema_entry);
-               }
-               
-               switch (objectClassCategory) {
-               case 1:
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  STRUCTURAL\n");
-                       IF_NULL_FAIL_RET(schema_entry);
-                       break;
-               case 2:
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  ABSTRACT\n");
-                       IF_NULL_FAIL_RET(schema_entry);
-                       break;
-               case 3:
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  AUXILIARY\n");
-                       IF_NULL_FAIL_RET(schema_entry);
-                       break;
-               }
-
-#define APPEND_ATTRS(attributes) \
-               do {                                            \
-                       int k;                                          \
-                       for (k=0; attributes && k < attributes->num_values; k++) { \
-                               int attr_idx; \
-                               const char *attr_name = (const char *)attributes->values[k].data;  \
-                               /* 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) { \
-                                               attr_name =  attr_map[attr_idx].new_attr; \
-                                               break;                  \
-                                       }                               \
-                               }                                       \
-                                                                       \
-                               schema_entry = talloc_asprintf_append(schema_entry, \
-                                                                     " %s", \
-                                                                     attr_name); \
-                               IF_NULL_FAIL_RET(schema_entry);         \
-                               if (k != (attributes->num_values - 1)) { \
-                                       schema_entry = talloc_asprintf_append(schema_entry, \
-                                                                             " $"); \
-                                       IF_NULL_FAIL_RET(schema_entry); \
-                                       if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \
-                                               schema_entry = talloc_asprintf_append(schema_entry, \
-                                                                                     "\n  "); \
-                                               IF_NULL_FAIL_RET(schema_entry); \
-                                       }                               \
-                               }                                       \
-                       }                                               \
-               } while (0)
-
-               if ((must && must->values) || (sys_must && sys_must->values)) {
-                       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)) {
-                       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);
+               may = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MAY);
+
+               for (j=0; may && may[j]; j++) {
+                       /* We might have been asked to remap this name, due to a conflict */ 
+                       for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) { 
+                               if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) { 
+                                       may[j] =  attr_map[attr_idx].new_attr; 
+                                       break;                          
+                               }                                       
+                       }                                               
+               }
+
+               must = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MUST);
+
+               for (j=0; must && must[j]; j++) {
+                       /* We might have been asked to remap this name, due to a conflict */ 
+                       for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) { 
+                               if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) { 
+                                       must[j] =  attr_map[attr_idx].new_attr; 
+                                       break;                          
+                               }                                       
+                       }                                               
+               }
+
+               schema_entry = schema_class_description(mem_ctx, target, 
+                                                       seperator,
+                                                       oid, 
+                                                       name,
+                                                       description,
+                                                       subClassOf,
+                                                       objectClassCategory,
+                                                       must,
+                                                       may);
+               if (schema_entry == NULL) {
+                       ret.failures++;
+                       return ret;
                }
 
-               schema_entry = talloc_asprintf_append(schema_entry, 
-                                                     "  )");
-
                switch (target) {
                case TARGET_OPENLDAP:
-                       fprintf(out, "%s\n\n", schema_entry);
+                       fprintf(out, "objectclass %s\n\n", schema_entry);
                        break;
                case TARGET_FEDORA_DS:
-                       fprintf(out, "%s\n", schema_entry);
+                       fprintf(out, "objectClasses: %s\n", schema_entry);
                        break;
                }
                ret.count++;