source4/dsdb/schema/schema_convert_to_ol.c: Fix typo in comment.
[Samba.git] / source4 / dsdb / schema / schema_convert_to_ol.c
blob71a417ed8437c7d14e865a7b3a99a2481d251520
1 /*
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/>.
21 #include "includes.h"
22 #include "ldb.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "system/locale.h"
26 #define SEPERATOR "\n "
28 struct attr_map {
29 char *old_attr;
30 char *new_attr;
33 struct oid_map {
34 char *old_oid;
35 char *new_oid;
38 static char *print_schema_recursive(char *append_to_string, struct dsdb_schema *schema, const char *print_class,
39 enum dsdb_schema_convert_target target,
40 const char **attrs_skip, const struct attr_map *attr_map, const struct oid_map *oid_map)
42 char *out = append_to_string;
43 const struct dsdb_class *objectclass;
44 objectclass = dsdb_class_by_lDAPDisplayName(schema, print_class);
45 if (!objectclass) {
46 DEBUG(0, ("Cannot find class %s in schema\n", print_class));
47 return NULL;
50 do {
51 TALLOC_CTX *mem_ctx = talloc_new(append_to_string);
52 const char *name = objectclass->lDAPDisplayName;
53 const char *oid = objectclass->governsID_oid;
54 const char *subClassOf = objectclass->subClassOf;
55 int objectClassCategory = objectclass->objectClassCategory;
56 const char **must;
57 const char **may;
58 char *schema_entry = NULL;
59 struct ldb_val objectclass_name_as_ldb_val = data_blob_string_const(objectclass->lDAPDisplayName);
60 struct ldb_message_element objectclass_name_as_el = {
61 .name = "objectClass",
62 .num_values = 1,
63 .values = &objectclass_name_as_ldb_val
65 unsigned int j;
66 unsigned int attr_idx;
68 if (!mem_ctx) {
69 DEBUG(0, ("Failed to create new talloc context\n"));
70 return NULL;
73 /* We have been asked to skip some attributes/objectClasses */
74 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
75 continue;
78 /* We might have been asked to remap this oid, due to a conflict */
79 for (j=0; oid_map && oid_map[j].old_oid; j++) {
80 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
81 oid = oid_map[j].new_oid;
82 break;
86 /* We might have been asked to remap this name, due to a conflict */
87 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
88 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
89 name = attr_map[j].new_attr;
90 break;
94 /* We might have been asked to remap this subClassOf, due to a conflict */
95 for (j=0; subClassOf && attr_map && attr_map[j].old_attr; j++) {
96 if (strcasecmp(subClassOf, attr_map[j].old_attr) == 0) {
97 subClassOf = attr_map[j].new_attr;
98 break;
102 may = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MAY);
104 for (j=0; may && may[j]; j++) {
105 /* We might have been asked to remap this name, due to a conflict */
106 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
107 if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) {
108 may[j] = attr_map[attr_idx].new_attr;
109 break;
114 must = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MUST);
116 for (j=0; must && must[j]; j++) {
117 /* We might have been asked to remap this name, due to a conflict */
118 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
119 if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) {
120 must[j] = attr_map[attr_idx].new_attr;
121 break;
126 schema_entry = schema_class_description(mem_ctx, target,
127 SEPERATOR,
128 oid,
129 name,
130 NULL,
131 subClassOf,
132 objectClassCategory,
133 must,
134 may,
135 NULL);
136 if (schema_entry == NULL) {
137 talloc_free(mem_ctx);
138 DEBUG(0, ("failed to generate schema description for %s\n", name));
139 return NULL;
142 switch (target) {
143 case TARGET_OPENLDAP:
144 out = talloc_asprintf_append(out, "objectclass %s\n\n", schema_entry);
145 break;
146 case TARGET_FEDORA_DS:
147 out = talloc_asprintf_append(out, "objectClasses: %s\n", schema_entry);
148 break;
149 default:
150 talloc_free(mem_ctx);
151 DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
152 return NULL;
154 talloc_free(mem_ctx);
155 } while (0);
158 for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) {
159 if (ldb_attr_cmp(objectclass->subClassOf, print_class) == 0
160 && ldb_attr_cmp(objectclass->lDAPDisplayName, print_class) != 0) {
161 out = print_schema_recursive(out, schema, objectclass->lDAPDisplayName,
162 target, attrs_skip, attr_map, oid_map);
165 return out;
168 /* Routine to linearise our internal schema into the format that
169 OpenLDAP and Fedora DS use for their backend.
171 The 'mappings' are of a format like:
173 #Standard OpenLDAP attributes
174 labeledURI
175 #The memberOf plugin provides this attribute
176 memberOf
177 #These conflict with OpenLDAP builtins
178 attributeTypes:samba4AttributeTypes
179 2.5.21.5:1.3.6.1.4.1.7165.4.255.7
184 char *dsdb_convert_schema_to_openldap(struct ldb_context *ldb, char *target_str, const char *mappings)
186 /* Read list of attributes to skip, OIDs to map */
187 TALLOC_CTX *mem_ctx = talloc_new(ldb);
188 char *line;
189 char *out;
190 const char **attrs_skip = NULL;
191 unsigned int num_skip = 0;
192 struct oid_map *oid_map = NULL;
193 unsigned int num_oid_maps = 0;
194 struct attr_map *attr_map = NULL;
195 unsigned int num_attr_maps = 0;
196 struct dsdb_attribute *attribute;
197 struct dsdb_schema *schema;
198 enum dsdb_schema_convert_target target;
200 char *next_line = talloc_strdup(mem_ctx, mappings);
202 if (!target_str || strcasecmp(target_str, "openldap") == 0) {
203 target = TARGET_OPENLDAP;
204 } else if (strcasecmp(target_str, "fedora-ds") == 0) {
205 target = TARGET_FEDORA_DS;
206 } else {
207 talloc_free(mem_ctx);
208 DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str));
209 return NULL;
212 /* The mappings are line-separated, and specify details such as OIDs to skip etc */
213 while (1) {
214 line = next_line;
215 next_line = strchr(line, '\n');
216 if (!next_line) {
217 break;
219 next_line[0] = '\0';
220 next_line++;
222 /* Blank Line */
223 if (line[0] == '\0') {
224 continue;
226 /* Comment */
227 if (line[0] == '#') {
228 continue;
231 if (isdigit(line[0])) {
232 char *p = strchr(line, ':');
233 if (!p) {
234 DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line));
235 return NULL;
237 p[0] = '\0';
238 p++;
239 oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
240 trim_string(line, " ", " ");
241 oid_map[num_oid_maps].old_oid = talloc_strdup(oid_map, line);
242 trim_string(p, " ", " ");
243 oid_map[num_oid_maps].new_oid = p;
244 num_oid_maps++;
245 oid_map[num_oid_maps].old_oid = NULL;
246 } else {
247 char *p = strchr(line, ':');
248 if (p) {
249 /* remap attribute/objectClass */
250 p[0] = '\0';
251 p++;
252 attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
253 trim_string(line, " ", " ");
254 attr_map[num_attr_maps].old_attr = talloc_strdup(attr_map, line);
255 trim_string(p, " ", " ");
256 attr_map[num_attr_maps].new_attr = p;
257 num_attr_maps++;
258 attr_map[num_attr_maps].old_attr = NULL;
259 } else {
260 /* skip attribute/objectClass */
261 attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
262 trim_string(line, " ", " ");
263 attrs_skip[num_skip] = talloc_strdup(attrs_skip, line);
264 num_skip++;
265 attrs_skip[num_skip] = NULL;
270 schema = dsdb_get_schema(ldb, mem_ctx);
271 if (!schema) {
272 talloc_free(mem_ctx);
273 DEBUG(0, ("No schema on ldb to convert!\n"));
274 return NULL;
277 switch (target) {
278 case TARGET_OPENLDAP:
279 out = talloc_strdup(mem_ctx, "");
280 break;
281 case TARGET_FEDORA_DS:
282 out = talloc_strdup(mem_ctx, "dn: cn=schema\n");
283 break;
284 default:
285 talloc_free(mem_ctx);
286 DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
287 return NULL;
290 for (attribute=schema->attributes; attribute; attribute = attribute->next) {
291 const char *name = attribute->lDAPDisplayName;
292 const char *oid = attribute->attributeID_oid;
293 const char *syntax = attribute->attributeSyntax_oid;
294 const char *equality = NULL, *substring = NULL;
295 bool single_value = attribute->isSingleValued;
297 char *schema_entry = NULL;
298 unsigned int j;
300 /* We have been asked to skip some attributes/objectClasses */
301 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
302 continue;
305 /* We might have been asked to remap this oid, due to a conflict */
306 for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
307 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
308 oid = oid_map[j].new_oid;
309 break;
313 if (attribute->syntax) {
314 /* We might have been asked to remap this oid,
315 * due to a conflict, or lack of
316 * implementation */
317 syntax = attribute->syntax->ldap_oid;
318 /* We might have been asked to remap this oid, due to a conflict */
319 for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) {
320 if (strcasecmp(syntax, oid_map[j].old_oid) == 0) {
321 syntax = oid_map[j].new_oid;
322 break;
326 equality = attribute->syntax->equality;
327 substring = attribute->syntax->substring;
330 /* We might have been asked to remap this name, due to a conflict */
331 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
332 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
333 name = attr_map[j].new_attr;
334 break;
338 schema_entry = schema_attribute_description(mem_ctx,
339 target,
340 SEPERATOR,
341 oid,
342 name,
343 equality,
344 substring,
345 syntax,
346 single_value,
347 false,
348 NULL, NULL,
349 NULL, NULL,
350 false, false);
352 if (schema_entry == NULL) {
353 talloc_free(mem_ctx);
354 DEBUG(0, ("failed to generate attribute description for %s\n", name));
355 return NULL;
358 switch (target) {
359 case TARGET_OPENLDAP:
360 out = talloc_asprintf_append(out, "attributetype %s\n\n", schema_entry);
361 break;
362 case TARGET_FEDORA_DS:
363 out = talloc_asprintf_append(out, "attributeTypes: %s\n", schema_entry);
364 break;
365 default:
366 talloc_free(mem_ctx);
367 DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
368 return NULL;
372 out = print_schema_recursive(out, schema, "top", target, attrs_skip, attr_map, oid_map);
374 talloc_steal(ldb, out);
375 talloc_free(mem_ctx);
377 return out;