int failures;
};
+enum convert_target {
+ TARGET_OPENLDAP,
+ TARGET_FEDORA_DS
+};
+
+
static void usage(void)
{
printf("Usage: ad2oLschema <options>\n");
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
};
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)
+#define IF_NULL_FAIL_RET(x) do { \
+ if (!x) { \
+ ret.failures++; \
+ return ret; \
+ } \
+ } while (0)
+
+
+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);
} *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;
ret.failures = 0;
while ((line = afdgets(fileno(in), mem_ctx, 0))) {
- if (!*line) {
- break;
+ /* Blank Line */
+ if (line[0] == '\0') {
+ continue;
}
- if (isdigit(*line)) {
+ /* Comment */
+ if (line[0] == '#') {
+ continue;
+ }
+ 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);
+ trim_string(line, " ", " ");
oid_map[num_maps].old_oid = talloc_steal(oid_map, line);
+ trim_string(p, " ", " ");
oid_map[num_maps].new_oid = p;
num_maps++;
oid_map[num_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;
}
}
- 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;
}
+ switch (target) {
+ case TARGET_OPENLDAP:
+ break;
+ case TARGET_FEDORA_DS:
+ fprintf(out, "dn: cn=schema\n");
+ break;
+ }
+
for (i=0; i < attrs_res->count; i++) {
- 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);
+ struct ldb_message *msg = attrs_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, "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;
/* We have been asked to skip some attributes/objectClasses */
- if (in_list(attrs_skip, name, False)) {
+ if (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++) {
+ 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);
- if (!schema_entry) {
- ret.failures++;
+ 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_NULL_FAIL_RET(schema_entry);
schema_entry = talloc_asprintf_append(schema_entry,
" NAME '%s'\n", name);
- if (!schema_entry) {
- ret.failures++;
- return ret;
- }
-
- if (!schema_entry) return ret;
+ IF_NULL_FAIL_RET(schema_entry);
if (description) {
schema_entry = talloc_asprintf_append(schema_entry,
" DESC %s\n", description);
- if (!schema_entry) {
- ret.failures++;
- return ret;
- }
+ IF_NULL_FAIL_RET(schema_entry);
}
- if (subClassOf) {
- schema_entry = talloc_asprintf_append(schema_entry,
- " SUP %s\n", subClassOf);
- if (!schema_entry) {
- ret.failures++;
- return ret;
- }
- }
-
if (map) {
+ const char *syntax_oid;
if (map->equality) {
schema_entry = talloc_asprintf_append(schema_entry,
" EQUALITY %s\n", map->equality);
- if (!schema_entry) {
- ret.failures++;
- return ret;
- }
+ IF_NULL_FAIL_RET(schema_entry);
}
if (map->substring) {
schema_entry = talloc_asprintf_append(schema_entry,
- " SUBSTRING %s\n", map->substring);
- if (!schema_entry) {
- ret.failures++;
- return ret;
+ " 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[j].old_oid; j++) {
+ if (strcmp(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", map->Standard_OID);
- if (!schema_entry) {
- ret.failures++;
- return ret;
- }
+ " 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 (!schema_entry) {
- ret.failures++;
- return ret;
+ IF_NULL_FAIL_RET(schema_entry);
+ }
+
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " )");
+
+ switch (target) {
+ case TARGET_OPENLDAP:
+ fprintf(out, "%s\n\n", schema_entry);
+ break;
+ case TARGET_FEDORA_DS:
+ fprintf(out, "%s\n", schema_entry);
+ break;
+ }
+ ret.count++;
+ }
+
+ 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++) {
+ 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");
+ char *schema_entry = NULL;
+ int j;
+
+ /* We have been asked to skip some attributes/objectClasses */
+ if (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) {
+ 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_NULL_FAIL_RET(schema_entry);
+ if (!schema_entry) {
+ ret.failures++;
+ break;
+ }
+
+ 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++) { \
+ schema_entry = talloc_asprintf_append(schema_entry, \
+ " %s", \
+ (const char *)attributes->values[k].data); \
+ 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 || sys_must) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " MUST (");
+ IF_NULL_FAIL_RET(schema_entry);
+
+ APPEND_ATTRS(must);
+ if (must && sys_must) {
+ 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 || sys_may) {
+ schema_entry = talloc_asprintf_append(schema_entry,
+ " MAY (");
+ IF_NULL_FAIL_RET(schema_entry);
+
+ APPEND_ATTRS(may);
+ if (may && sys_may) {
+ 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);
+ }
+
schema_entry = talloc_asprintf_append(schema_entry,
- ")\n\n");
+ " )");
- fprintf(out, "%s", schema_entry);
+ switch (target) {
+ case TARGET_OPENLDAP:
+ fprintf(out, "%s\n\n", schema_entry);
+ break;
+ case TARGET_FEDORA_DS:
+ fprintf(out, "%s\n", schema_entry);
+ break;
+ }
+ ret.count++;
}
- /* Read each element */
- /* Replace OID if required */
+ return ret;
}
int main(int argc, const char **argv)
FILE *out = stdout;
struct ldb_context *ldb;
struct schema_conv ret;
+ const char *target_str;
+ enum convert_target target;
ldb_global_init();
}
}
- 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);
- 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;
}