r26611: Tridge didn't write this...
[samba.git] / source4 / lib / ldb / tools / ad2oLschema.c
index 9bebcde7e0116574a87d6e3e57cfb5e5b1648dfd..dec8a5f9726056cf90c5c40d4fbd5d59ae3e9c6e 100644 (file)
@@ -10,7 +10,7 @@
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 2 of the License, or (at your option) any later version.
+   version 3 of the License, or (at your option) any later version.
 
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,8 +18,7 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
  *
  *  Description: utility to convert an AD schema into the format required by OpenLDAP
  *
- *  Author: Andrew Tridgell
+ *  Author: Andrew Bartlett
  */
 
 #include "includes.h"
-#include "ldb/include/includes.h"
-#include "ldb/tools/cmdline.h"
-#include "ldb/tools/convert.h"
+#include "ldb_includes.h"
+#include "system/locale.h"
+#include "tools/cmdline.h"
+#include "tools/convert.h"
+#include "param/param.h"
+#include "lib/cmdline/popt_common.h"
 
 struct schema_conv {
        int count;
@@ -62,7 +64,7 @@ static void usage(void)
        printf("\n");
        printf("Converts records from an AD-like LDIF schema into an openLdap formatted schema\n\n");
        exit(1);
-};
+}
 
 static int fetch_attrs_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
                              TALLOC_CTX *mem_ctx, 
@@ -119,26 +121,23 @@ static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn,
                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);
+               ret = ldb_search_exp_fmt(ldb, mem_ctx, &res,
+                                       schemadn, LDB_SCOPE_SUBTREE, oc_attrs,
+                                       "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
+                                       name, name);
                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->msgs[res_list->count] = talloc_move(res_list, 
+                                                             &search_from->msgs[i]);
                res_list->count++;
                res_list->msgs[res_list->count] = NULL;
 
@@ -190,16 +189,18 @@ static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *sche
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       *objectclasses_res = talloc_steal(mem_ctx, ret_res);
+       *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) 
 {
        const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
+       const char *no_attrs[] = { NULL };
        struct ldb_dn *schemadn;
-       struct ldb_dn *basedn = ldb_dn_explode(mem_ctx, "");
+       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) {
                return NULL;
@@ -208,8 +209,25 @@ static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ct
        /* 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 NULL;
+               ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, 
+                                "(&(objectClass=dMD)(cn=Schema))", 
+                                no_attrs, &schema_res);
+               if (ldb_ret) {
+                       printf("cn=Schema Search failed: %s\n", ldb_errstring(ldb));
+                       return NULL;
+               }
+
+               talloc_steal(mem_ctx, schema_res);
+
+               if (schema_res->count != 1) {
+                       printf("Failed to find rootDSE");
+                       return NULL;
+               }
+               
+               schemadn = talloc_steal(mem_ctx, schema_res->msgs[0]->dn);
+               talloc_free(schema_res);
+               return schemadn;
+               
        }
        
        talloc_steal(mem_ctx, rootdse_res);
@@ -220,7 +238,7 @@ static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ct
        }
        
        /* Locate schema */
-       schemadn = ldb_msg_find_attr_as_dn(mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
+       schemadn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
        if (!schemadn) {
                return NULL;
        }
@@ -248,7 +266,12 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                char *old_oid;
                char *new_oid;
        } *oid_map = NULL;
-       int num_maps = 0;
+       int num_oid_maps = 0;
+       struct attr_map {
+               char *old_attr;
+               char *new_attr;
+       } *attr_map = NULL;
+       int num_attr_maps = 0;  
        struct ldb_result *attrs_res, *objectclasses_res;
        struct ldb_dn *schemadn;
        struct schema_conv ret;
@@ -271,25 +294,36 @@ 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 = 1;
-                               return ret;
-                       }
                        p[0] = '\0';
                        p++;
-                       oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_maps + 2);
+                       oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
                        trim_string(line, " ", " ");
-                       oid_map[num_maps].old_oid = talloc_steal(oid_map, line);
+                       oid_map[num_oid_maps].old_oid = talloc_move(oid_map, &line);
                        trim_string(p, " ", " ");
-                       oid_map[num_maps].new_oid = p;
-                       num_maps++;
-                       oid_map[num_maps].old_oid = NULL;
+                       oid_map[num_oid_maps].new_oid = p;
+                       num_oid_maps++;
+                       oid_map[num_oid_maps].old_oid = NULL;
                } else {
-                       attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
-                       trim_string(line, " ", " ");
-                       attrs_skip[num_skip] = talloc_steal(attrs_skip, line);
-                       num_skip++;
-                       attrs_skip[num_skip] = NULL;
+                       char *p = strchr(line, ':');
+                       if (p) {
+                               /* remap attribute/objectClass */
+                               p[0] = '\0';
+                               p++;
+                               attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
+                               trim_string(line, " ", " ");
+                               attr_map[num_attr_maps].old_attr = talloc_move(attr_map, &line);
+                               trim_string(p, " ", " ");
+                               attr_map[num_attr_maps].new_attr = p;
+                               num_attr_maps++;
+                               attr_map[num_attr_maps].old_attr = NULL;
+                       } else {
+                               /* skip attribute/objectClass */
+                               attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
+                               trim_string(line, " ", " ");
+                               attrs_skip[num_skip] = talloc_move(attrs_skip, &line);
+                               num_skip++;
+                               attrs_skip[num_skip] = NULL;
+                       }
                }
        }
 
@@ -322,20 +356,26 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                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);
+               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 (str_list_check_ci(attrs_skip, name)) {
+               if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
                        ret.skipped++;
                        continue;
                }
 
                /* We might have been asked to remap this oid, due to a conflict */
-               for (j=0; oid && oid_map[j].old_oid; j++) {
-                       if (strcmp(oid, oid_map[j].old_oid) == 0) {
+               for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
+                       if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
                                oid =  oid_map[j].new_oid;
                                break;
                        }
@@ -355,6 +395,14 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                }
                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++) {
+                       if (strcasecmp(name, attr_map[j].old_attr) == 0) {
+                               name =  attr_map[j].new_attr;
+                               break;
+                       }
+               }
+               
                schema_entry = talloc_asprintf_append(schema_entry, 
                                                      "  NAME '%s'\n", name);
                IF_NULL_FAIL_RET(schema_entry);
@@ -382,7 +430,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                         * due to a conflict, or lack of
                         * implementation */
                        for (j=0; syntax_oid && oid_map[j].old_oid; j++) {
-                               if (strcmp(syntax_oid, oid_map[j].old_oid) == 0) {
+                               if (strcasecmp(syntax_oid, oid_map[j].old_oid) == 0) {
                                        syntax_oid =  oid_map[j].new_oid;
                                        break;
                                }
@@ -409,6 +457,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        fprintf(out, "%s\n", schema_entry);
                        break;
                }
+               ret.count++;
        }
 
        ldb_ret = fetch_objectclass_schema(ldb, schemadn, mem_ctx, &objectclasses_res);
@@ -432,15 +481,21 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                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 (str_list_check_ci(attrs_skip, name)) {
+               if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
                        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) {
+                       if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
                                oid =  oid_map[j].new_oid;
                                break;
                        }
@@ -464,6 +519,14 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        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) {
+                               name =  attr_map[j].new_attr;
+                               break;
+                       }
+               }
+               
                schema_entry = talloc_asprintf_append(schema_entry, 
                                                      "  NAME '%s'\n", name);
                IF_NULL_FAIL_RET(schema_entry);
@@ -504,9 +567,19 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                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", \
-                                                                     (const char *)attributes->values[k].data); \
+                                                                     attr_name); \
                                IF_NULL_FAIL_RET(schema_entry);         \
                                if (k != (attributes->num_values - 1)) { \
                                        schema_entry = talloc_asprintf_append(schema_entry, \
@@ -566,6 +639,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                        fprintf(out, "%s\n", schema_entry);
                        break;
                }
+               ret.count++;
        }
 
        return ret;
@@ -604,7 +678,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
                }
        }
 
-       target_str = lp_parm_string(-1, "convert", "target");
+       target_str = lp_parm_string(cmdline_lp_ctx, NULL, "convert", "target");
 
        if (!target_str || strcasecmp(target_str, "openldap") == 0) {
                target = TARGET_OPENLDAP;
@@ -620,7 +694,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_
        fclose(in);
        fclose(out);
 
-       printf("Converted %d records with %d failures\n", ret.count, ret.failures);
+       printf("Converted %d records (skipped %d) with %d failures\n", ret.count, ret.skipped, ret.failures);
 
        return 0;
 }