diff options
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/config.mk | 3 | ||||
-rw-r--r-- | source4/dsdb/schema/schema_convert_to_ol.c | 316 | ||||
-rw-r--r-- | source4/dsdb/schema/schema_set.c | 2 |
3 files changed, 319 insertions, 2 deletions
diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index 2ca4e4ca6d..6db2890738 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -37,7 +37,8 @@ SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \ schema_set.o \ schema_query.o \ schema_syntax.o \ - schema_description.o) + schema_description.o \ + schema_convert_to_ol.o) $(eval $(call proto_header_template,$(dsdbsrcdir)/schema/proto.h,$(SAMDB_SCHEMA_OBJ_FILES:.o=.c))) # PUBLIC_HEADERS += dsdb/schema/schema.h diff --git a/source4/dsdb/schema/schema_convert_to_ol.c b/source4/dsdb/schema/schema_convert_to_ol.c new file mode 100644 index 0000000000..375e4e3810 --- /dev/null +++ b/source4/dsdb/schema/schema_convert_to_ol.c @@ -0,0 +1,316 @@ +/* + schema conversion routines + + Copyright (C) Andrew Bartlett 2006-2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "includes.h" +#include "ldb.h" +#include "dsdb/samdb/samdb.h" +#include "system/locale.h" + +/* Routine to linearise our internal schema into the format that + OpenLDAP and Fedora DS use for their backend. + + The 'mappings' are of a format like: + +#Standard OpenLDAP attributes +labeledURI +#The memberOf plugin provides this attribute +memberOf +#These conflict with OpenLDAP builtins +attributeTypes:samba4AttributeTypes +2.5.21.5:1.3.6.1.4.1.7165.4.255.7 + +*/ + + +char *dsdb_convert_schema_to_openldap(struct ldb_context *ldb, char *target_str, const char *mappings) +{ + /* Read list of attributes to skip, OIDs to map */ + TALLOC_CTX *mem_ctx = talloc_new(ldb); + char *line; + char *out; + const char **attrs_skip = NULL; + int num_skip = 0; + struct oid_map { + char *old_oid; + char *new_oid; + } *oid_map = NULL; + int num_oid_maps = 0; + struct attr_map { + char *old_attr; + char *new_attr; + } *attr_map = NULL; + int num_attr_maps = 0; + struct dsdb_class *objectclass; + struct dsdb_attribute *attribute; + struct dsdb_schema *schema; + const char *seperator; + enum dsdb_schema_convert_target target; + + char *next_line = talloc_strdup(mem_ctx, mappings); + + if (!target_str || strcasecmp(target_str, "openldap") == 0) { + target = TARGET_OPENLDAP; + } else if (strcasecmp(target_str, "fedora-ds") == 0) { + target = TARGET_FEDORA_DS; + } else { + DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str)); + return NULL; + } + + /* The mappings are line-seperated, and specify details such as OIDs to skip etc */ + while (1) { + line = next_line; + next_line = strchr(line, '\n'); + if (!next_line) { + break; + } + next_line[0] = '\0'; + next_line++; + + /* Blank Line */ + if (line[0] == '\0') { + continue; + } + /* Comment */ + if (line[0] == '#') { + continue; + } + + if (isdigit(line[0])) { + char *p = strchr(line, ':'); + if (!p) { + DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line)); + return NULL; + } + p[0] = '\0'; + p++; + oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2); + trim_string(line, " ", " "); + oid_map[num_oid_maps].old_oid = talloc_strdup(oid_map, line); + trim_string(p, " ", " "); + oid_map[num_oid_maps].new_oid = p; + num_oid_maps++; + oid_map[num_oid_maps].old_oid = NULL; + } else { + 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_strdup(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_strdup(attrs_skip, line); + num_skip++; + attrs_skip[num_skip] = NULL; + } + } + } + + schema = dsdb_get_schema(ldb); + if (!schema) { + DEBUG(0, ("No schema on ldb to convert!\n")); + return NULL; + } + switch (target) { + case TARGET_OPENLDAP: + seperator = "\n "; + out = talloc_strdup(mem_ctx, ""); + break; + case TARGET_FEDORA_DS: + seperator = "\n "; + out = talloc_strdup(mem_ctx, "dn: cn=schema\n"); + break; + } + + for (attribute=schema->attributes; attribute; attribute = attribute->next) { + const char *name = attribute->lDAPDisplayName; + const char *oid = attribute->attributeID_oid; + const char *syntax = attribute->attributeSyntax_oid; + const char *equality = NULL, *substring = NULL; + bool single_value = attribute->isSingleValued; + + char *schema_entry = NULL; + int j; + + /* We have been asked to skip some attributes/objectClasses */ + if (attrs_skip && str_list_check_ci(attrs_skip, name)) { + continue; + } + + /* We might have been asked to remap this oid, due to a conflict */ + 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; + } + } + + if (attribute->syntax) { + /* We might have been asked to remap this oid, + * due to a conflict, or lack of + * implementation */ + syntax = attribute->syntax->ldap_oid; + /* We might have been asked to remap this oid, due to a conflict */ + for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) { + if (strcasecmp(syntax, oid_map[j].old_oid) == 0) { + syntax = oid_map[j].new_oid; + break; + } + } + + equality = attribute->syntax->equality; + substring = attribute->syntax->substring; + } + + /* 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 = schema_attribute_description(mem_ctx, + target, + seperator, + oid, + name, + equality, + substring, + syntax, + single_value, + false, + NULL, NULL, + NULL, NULL, + false, false); + + if (schema_entry == NULL) { + DEBUG(0, ("failed to generate attribute description for %s\n", name)); + return NULL; + } + + switch (target) { + case TARGET_OPENLDAP: + out = talloc_asprintf_append(out, "attributetype %s\n\n", schema_entry); + break; + case TARGET_FEDORA_DS: + out = talloc_asprintf_append(out, "attributeTypes: %s\n", schema_entry); + break; + } + } + + /* 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 *oid = objectclass->governsID_oid; + const char *subClassOf = objectclass->subClassOf; + int objectClassCategory = objectclass->objectClassCategory; + const char **must; + const char **may; + char *schema_entry = NULL; + const char *objectclass_name_as_list[] = { + objectclass->lDAPDisplayName, + NULL + }; + int j; + int attr_idx; + + /* We have been asked to skip some attributes/objectClasses */ + if (attrs_skip && str_list_check_ci(attrs_skip, name)) { + 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) { + oid = oid_map[j].new_oid; + 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; + } + } + + 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, + NULL, + subClassOf, + objectClassCategory, + must, + may, + NULL); + if (schema_entry == NULL) { + DEBUG(0, ("failed to generate schema description for %s\n", name)); + return NULL; + } + + switch (target) { + case TARGET_OPENLDAP: + out = talloc_asprintf_append(out, "objectclass %s\n\n", schema_entry); + break; + case TARGET_FEDORA_DS: + out = talloc_asprintf_append(out, "objectClasses: %s\n", schema_entry); + break; + } + } + + return out; +} + diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c index 6abd8a8f88..d52976958d 100644 --- a/source4/dsdb/schema/schema_set.c +++ b/source4/dsdb/schema/schema_set.c @@ -277,7 +277,7 @@ void dsdb_make_schema_global(struct ldb_context *ldb) * schema itself to the directory. */ -WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df) +WERROR dsdb_attach_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df) { struct ldb_ldif *ldif; struct ldb_message *msg; |