r17599: Improvements to the AD-like to OpenLDAP format schema conversion utility.
authorAndrew Bartlett <abartlet@samba.org>
Fri, 18 Aug 2006 03:52:50 +0000 (03:52 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:16:16 +0000 (14:16 -0500)
We now read the objectClasses, and sort them into order, so that
OpenLDAP will load them.  We do this by walking down the 'subClassOf'
chain.  This should also be used in the objectClass module to sort the
objectClass list, and to populate the @SUBCLASS records.

Andrew Bartlett

source/lib/ldb/tools/ad2oLschema.c

index 03adf195db42dbf256ff223100c2d638909ba772..75b03dd3b04e9f09ee0d62d7dee0b21e31bfc314 100644 (file)
@@ -43,6 +43,12 @@ struct schema_conv {
        int failures;
 };
 
+enum convert_target {
+       TARGET_OPENLDAP,
+       TARGET_FEDORA_DS
+};
+       
+
 static void usage(void)
 {
        printf("Usage: ad2oLschema <options>\n");
@@ -58,25 +64,18 @@ static void usage(void)
        exit(1);
 };
 
-static int fetch_schema(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_result **attrs_res, struct ldb_result **objectclasses_res) 
+static int fetch_attrs_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
+                             TALLOC_CTX *mem_ctx, 
+                             struct ldb_result **attrs_res)
 {
        TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
-       struct ldb_dn *basedn, *schemadn;
-       struct ldb_result *res;
        int ret;
-       const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
        const char *attrs[] = {
                "lDAPDisplayName",
-               "mayContain",
-               "mustContain",
-               "systemMayContain",
-               "systemMustContain",
-               "objectClassCategory",
                "isSingleValued",
                "attributeID",
                "attributeSyntax",
                "description",          
-               "subClassOf",
                NULL
        };
 
@@ -84,53 +83,153 @@ static int fetch_schema(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb
                return LDB_ERR_OPERATIONS_ERROR;
        }
        
-       basedn = ldb_dn_explode(mem_ctx, "");
-       if (!basedn) {
+       /* Downlaod schema */
+       ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
+                        "objectClass=attributeSchema", 
+                        attrs, attrs_res);
+       if (ret != LDB_SUCCESS) {
+               printf("Search failed: %s\n", ldb_errstring(ldb));
                return LDB_ERR_OPERATIONS_ERROR;
        }
        
-       /* Search for rootdse */
-       ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &res);
+       return ret;
+}
+
+static const char *oc_attrs[] = {
+       "lDAPDisplayName",
+       "mayContain",
+       "mustContain",
+       "systemMayContain",
+       "systemMustContain",
+       "objectClassCategory",
+       "governsID",
+       "description",          
+       "subClassOf",
+       NULL
+};
+
+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);
+               char *filter = talloc_asprintf(mem_ctx, "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))", 
+                                              name, name);
+
+               ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
+                                filter,
+                                oc_attrs, &res);
+               talloc_free(filter);
+               if (ret != LDB_SUCCESS) {
+                       printf("Search failed: %s\n", ldb_errstring(ldb));
+                       return ret;
+               }
+               
+               talloc_steal(mem_ctx, res);
+
+               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_steal(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))", 
+                        oc_attrs, &top_res);
        if (ret != LDB_SUCCESS) {
                printf("Search failed: %s\n", ldb_errstring(ldb));
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       
-       if (res->count != 1) {
+
+       talloc_steal(local_ctx, top_res);
+
+       if (top_res->count != 1) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       
-       /* Locate schema */
-       schemadn = ldb_msg_find_attr_as_dn(mem_ctx, res->msgs[0], "schemaNamingContext");
-       if (!schemadn) {
+
+       ret_res = talloc_zero(local_ctx, struct ldb_result);
+       if (!ret_res) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       /* Downlaod schema */
-       ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
-                        "objectClass=attributeSchema", 
-                        attrs, attrs_res);
+       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;
        }
 
-       ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
-                        "objectClass=classSchema", 
-                        attrs, objectclasses_res);
-       if (ret != LDB_SUCCESS) {
+       *objectclasses_res = talloc_steal(mem_ctx, ret_res);
+       return ret;
+}
+
+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_explode(mem_ctx, "");
+       struct ldb_result *rootdse_res;
+       int ldb_ret;
+       if (!basedn) {
+               return NULL;
+       }
+       
+       /* Search for rootdse */
+       ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &rootdse_res);
+       if (ldb_ret != LDB_SUCCESS) {
                printf("Search failed: %s\n", ldb_errstring(ldb));
-               return ret;
+               return NULL;
        }
+       
+       talloc_steal(mem_ctx, rootdse_res);
 
-       talloc_steal(mem_ctx, *attrs_res);
-       talloc_steal(mem_ctx, *objectclasses_res);
-       talloc_free(local_ctx);
+       if (rootdse_res->count != 1) {
+               printf("Failed to find rootDSE");
+               return NULL;
+       }
        
-       return LDB_SUCCESS;
+       /* Locate schema */
+       schemadn = ldb_msg_find_attr_as_dn(mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
+       if (!schemadn) {
+               return NULL;
+       }
+
+       talloc_free(rootdse_res);
+       return schemadn;
 }
 
-static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FILE *out) 
+static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_target target, FILE *in, FILE *out) 
 {
        /* Read list of attributes to skip, OIDs to map */
        TALLOC_CTX *mem_ctx = talloc_new(ldb);
@@ -143,7 +242,9 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
        } *oid_map = NULL;
        int num_maps = 0;
        struct ldb_result *attrs_res, *objectclasses_res;
+       struct ldb_dn *schemadn;
        struct schema_conv ret;
+
        int ldb_ret, i;
 
        ret.count = 0;
@@ -172,8 +273,16 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
                }
        }
 
-       ldb_ret = fetch_schema(ldb, mem_ctx, &attrs_res, &objectclasses_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;
        }
@@ -182,7 +291,6 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
                const char *name = ldb_msg_find_attr_as_string(attrs_res->msgs[i], "lDAPDisplayName", NULL);
                const char *description = ldb_msg_find_attr_as_string(attrs_res->msgs[i], "description", NULL);
                const char *oid = ldb_msg_find_attr_as_string(attrs_res->msgs[i], "attributeID", NULL);
-               const char *subClassOf = ldb_msg_find_attr_as_string(attrs_res->msgs[i], "subClassOf", NULL);
                const char *syntax = ldb_msg_find_attr_as_string(attrs_res->msgs[i], "attributeSyntax", NULL);
                BOOL single_value = ldb_msg_find_attr_as_bool(attrs_res->msgs[i], "isSingleValued", False);
                const struct syntax_map *map = find_syntax_map_by_ad_oid(syntax);
@@ -196,16 +304,25 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
                }
 
                /* We might have been asked to remap this oid, due to a conflict */
-               for (j=0; oid_map[j].old_oid; j++) {
+               for (j=0; oid && oid_map[j].old_oid; j++) {
                        if (strcmp(oid, oid_map[j].old_oid) == 0) {
                                oid =  oid_map[j].new_oid;
                                break;
                        }
                }
                
-               schema_entry = talloc_asprintf(mem_ctx, 
-                                              "attributetype (\n"
-                                              "  %s\n", oid);
+               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 (!schema_entry) {
                        ret.failures++;
                        break;
@@ -229,15 +346,6 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
                        }
                }
 
-               if (subClassOf) {
-                       schema_entry = talloc_asprintf_append(schema_entry, 
-                                                             "  SUP %s\n", subClassOf);
-                       if (!schema_entry) {
-                               ret.failures++;
-                               return ret;
-                       }
-               }
-                              
                if (map) {
                        if (map->equality) {
                                schema_entry = talloc_asprintf_append(schema_entry, 
@@ -273,13 +381,91 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
                }
                
                schema_entry = talloc_asprintf_append(schema_entry, 
-                                                     ")\n\n");
+                                                     "  )\n\n");
 
                fprintf(out, "%s", schema_entry);
        }
 
-       /* Read each element */
-       /* Replace OID if required */
+       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;
+       }
+       
+       for (i=0; i < objectclasses_res->count; i++) {
+               const char *name = ldb_msg_find_attr_as_string(objectclasses_res->msgs[i], "lDAPDisplayName", NULL);
+               const char *description = ldb_msg_find_attr_as_string(objectclasses_res->msgs[i], "description", NULL);
+               const char *oid = ldb_msg_find_attr_as_string(objectclasses_res->msgs[i], "governsID", NULL);
+               const char *subClassOf = ldb_msg_find_attr_as_string(objectclasses_res->msgs[i], "subClassOf", NULL);
+               char *schema_entry = NULL;
+               int j;
+
+               /* We have been asked to skip some attributes/objectClasses */
+               if (in_list(attrs_skip, name, False)) {
+                       ret.skipped++;
+                       continue;
+               }
+
+               /* We might have been asked to remap this oid, due to a conflict */
+               for (j=0; oid_map[j].old_oid; j++) {
+                       if (strcmp(oid, oid_map[j].old_oid) == 0) {
+                               oid =  oid_map[j].new_oid;
+                               break;
+                       }
+               }
+               
+               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 (!schema_entry) {
+                       ret.failures++;
+                       break;
+               }
+
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "  NAME '%s'\n", name);
+               if (!schema_entry) {
+                       ret.failures++;
+                       return ret;
+               }
+
+               if (!schema_entry) return ret;
+
+               if (description) {
+                       schema_entry = talloc_asprintf_append(schema_entry, 
+                                                             "  DESC %s\n", description);
+                       if (!schema_entry) {
+                               ret.failures++;
+                               return ret;
+                       }
+               }
+
+               if (subClassOf) {
+                       schema_entry = talloc_asprintf_append(schema_entry, 
+                                                             "  SUP %s\n", subClassOf);
+                       if (!schema_entry) {
+                               ret.failures++;
+                               return ret;
+                       }
+               }
+
+               schema_entry = talloc_asprintf_append(schema_entry, 
+                                                     "  )\n\n");
+
+               fprintf(out, "%s", schema_entry);
+       }
+
+       return ret;
 }
 
  int main(int argc, const char **argv)
@@ -290,6 +476,8 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
        FILE *out = stdout;
        struct ldb_context *ldb;
        struct schema_conv ret;
+       const char *target_str;
+       enum convert_target target;
 
        ldb_global_init();
 
@@ -313,7 +501,18 @@ static struct schema_conv process_convert(struct ldb_context *ldb, FILE *in, FIL
                }
        }
 
-       ret = process_convert(ldb, in, out);
+       target_str = lp_parm_string(-1, "convert", "target");
+
+       if (!target_str || strcasecmp(target_str, "openldap") == 0) {
+               target = TARGET_OPENLDAP;
+       } else if (strcasecmp(target_str, "fedora-ds") == 0) {
+               target = TARGET_FEDORA_DS;
+       } else {
+               printf("Unsupported target: %s\n", target_str);
+               exit(1);
+       }
+
+       ret = process_convert(ldb, target, in, out);
 
        fclose(in);
        fclose(out);