2 schema conversion routines
4 Copyright (C) Andrew Bartlett 2006-2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "dsdb/samdb/samdb.h"
24 #include "system/locale.h"
26 /* Routine to linearise our internal schema into the format that
27 OpenLDAP and Fedora DS use for their backend.
29 The 'mappings' are of a format like:
31 #Standard OpenLDAP attributes
33 #The memberOf plugin provides this attribute
35 #These conflict with OpenLDAP builtins
36 attributeTypes:samba4AttributeTypes
37 2.5.21.5:1.3.6.1.4.1.7165.4.255.7
42 char *dsdb_convert_schema_to_openldap(struct ldb_context *ldb, char *target_str, const char *mappings)
44 /* Read list of attributes to skip, OIDs to map */
45 TALLOC_CTX *mem_ctx = talloc_new(ldb);
48 const char **attrs_skip = NULL;
59 int num_attr_maps = 0;
60 struct dsdb_class *objectclass;
61 struct dsdb_attribute *attribute;
62 struct dsdb_schema *schema;
63 const char *seperator;
64 enum dsdb_schema_convert_target target;
66 char *next_line = talloc_strdup(mem_ctx, mappings);
68 if (!target_str || strcasecmp(target_str, "openldap") == 0) {
69 target = TARGET_OPENLDAP;
70 } else if (strcasecmp(target_str, "fedora-ds") == 0) {
71 target = TARGET_FEDORA_DS;
73 DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str));
77 /* The mappings are line-seperated, and specify details such as OIDs to skip etc */
80 next_line = strchr(line, '\n');
88 if (line[0] == '\0') {
96 if (isdigit(line[0])) {
97 char *p = strchr(line, ':');
99 DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line));
104 oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
105 trim_string(line, " ", " ");
106 oid_map[num_oid_maps].old_oid = talloc_strdup(oid_map, line);
107 trim_string(p, " ", " ");
108 oid_map[num_oid_maps].new_oid = p;
110 oid_map[num_oid_maps].old_oid = NULL;
112 char *p = strchr(line, ':');
114 /* remap attribute/objectClass */
117 attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
118 trim_string(line, " ", " ");
119 attr_map[num_attr_maps].old_attr = talloc_strdup(attr_map, line);
120 trim_string(p, " ", " ");
121 attr_map[num_attr_maps].new_attr = p;
123 attr_map[num_attr_maps].old_attr = NULL;
125 /* skip attribute/objectClass */
126 attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
127 trim_string(line, " ", " ");
128 attrs_skip[num_skip] = talloc_strdup(attrs_skip, line);
130 attrs_skip[num_skip] = NULL;
135 schema = dsdb_get_schema(ldb);
137 DEBUG(0, ("No schema on ldb to convert!\n"));
141 case TARGET_OPENLDAP:
143 out = talloc_strdup(mem_ctx, "");
145 case TARGET_FEDORA_DS:
147 out = talloc_strdup(mem_ctx, "dn: cn=schema\n");
151 for (attribute=schema->attributes; attribute; attribute = attribute->next) {
152 const char *name = attribute->lDAPDisplayName;
153 const char *oid = attribute->attributeID_oid;
154 const char *syntax = attribute->attributeSyntax_oid;
155 const char *equality = NULL, *substring = NULL;
156 bool single_value = attribute->isSingleValued;
158 char *schema_entry = NULL;
161 /* We have been asked to skip some attributes/objectClasses */
162 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
166 /* We might have been asked to remap this oid, due to a conflict */
167 for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
168 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
169 oid = oid_map[j].new_oid;
174 if (attribute->syntax) {
175 /* We might have been asked to remap this oid,
176 * due to a conflict, or lack of
178 syntax = attribute->syntax->ldap_oid;
179 /* We might have been asked to remap this oid, due to a conflict */
180 for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) {
181 if (strcasecmp(syntax, oid_map[j].old_oid) == 0) {
182 syntax = oid_map[j].new_oid;
187 equality = attribute->syntax->equality;
188 substring = attribute->syntax->substring;
191 /* We might have been asked to remap this name, due to a conflict */
192 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
193 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
194 name = attr_map[j].new_attr;
199 schema_entry = schema_attribute_description(mem_ctx,
213 if (schema_entry == NULL) {
214 DEBUG(0, ("failed to generate attribute description for %s\n", name));
219 case TARGET_OPENLDAP:
220 out = talloc_asprintf_append(out, "attributetype %s\n\n", schema_entry);
222 case TARGET_FEDORA_DS:
223 out = talloc_asprintf_append(out, "attributeTypes: %s\n", schema_entry);
228 /* This is already sorted to have 'top' and similar classes first */
229 for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) {
230 const char *name = objectclass->lDAPDisplayName;
231 const char *oid = objectclass->governsID_oid;
232 const char *subClassOf = objectclass->subClassOf;
233 int objectClassCategory = objectclass->objectClassCategory;
236 char *schema_entry = NULL;
237 const char *objectclass_name_as_list[] = {
238 objectclass->lDAPDisplayName,
244 /* We have been asked to skip some attributes/objectClasses */
245 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
249 /* We might have been asked to remap this oid, due to a conflict */
250 for (j=0; oid_map && oid_map[j].old_oid; j++) {
251 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
252 oid = oid_map[j].new_oid;
257 /* We might have been asked to remap this name, due to a conflict */
258 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
259 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
260 name = attr_map[j].new_attr;
265 may = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MAY);
267 for (j=0; may && may[j]; j++) {
268 /* We might have been asked to remap this name, due to a conflict */
269 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
270 if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) {
271 may[j] = attr_map[attr_idx].new_attr;
277 must = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MUST);
279 for (j=0; must && must[j]; j++) {
280 /* We might have been asked to remap this name, due to a conflict */
281 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
282 if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) {
283 must[j] = attr_map[attr_idx].new_attr;
289 schema_entry = schema_class_description(mem_ctx, target,
299 if (schema_entry == NULL) {
300 DEBUG(0, ("failed to generate schema description for %s\n", name));
305 case TARGET_OPENLDAP:
306 out = talloc_asprintf_append(out, "objectclass %s\n\n", schema_entry);
308 case TARGET_FEDORA_DS:
309 out = talloc_asprintf_append(out, "objectClasses: %s\n", schema_entry);