s3: tests: Add new test_stream_dir_rename.sh test.
[Samba.git] / source4 / dsdb / schema / schema_convert_to_ol.c
blobebb886da677f0487fb39df73b9a606b4994be895
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 #undef strcasecmp
28 #define SEPERATOR "\n "
30 struct attr_map {
31 char *old_attr;
32 char *new_attr;
35 struct oid_map {
36 char *old_oid;
37 char *new_oid;
40 static char *print_schema_recursive(char *append_to_string, struct dsdb_schema *schema, const char *print_class,
41 enum dsdb_schema_convert_target target,
42 const char **attrs_skip, const struct attr_map *attr_map, const struct oid_map *oid_map)
44 char *out = append_to_string;
45 const struct dsdb_class *objectclass;
46 objectclass = dsdb_class_by_lDAPDisplayName(schema, print_class);
47 if (!objectclass) {
48 DEBUG(0, ("Cannot find class %s in schema\n", print_class));
49 return NULL;
52 do {
53 TALLOC_CTX *mem_ctx = talloc_new(append_to_string);
54 const char *name = objectclass->lDAPDisplayName;
55 const char *oid = objectclass->governsID_oid;
56 const char *subClassOf = objectclass->subClassOf;
57 int objectClassCategory = objectclass->objectClassCategory;
58 const char **must;
59 const char **may;
60 char *schema_entry = NULL;
61 struct ldb_val objectclass_name_as_ldb_val = data_blob_string_const(objectclass->lDAPDisplayName);
62 struct ldb_message_element objectclass_name_as_el = {
63 .name = "objectClass",
64 .num_values = 1,
65 .values = &objectclass_name_as_ldb_val
67 unsigned int j;
68 unsigned int attr_idx;
70 if (!mem_ctx) {
71 DEBUG(0, ("Failed to create new talloc context\n"));
72 return NULL;
75 /* We have been asked to skip some attributes/objectClasses */
76 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
77 continue;
80 /* We might have been asked to remap this oid, due to a conflict */
81 for (j=0; oid_map && oid_map[j].old_oid; j++) {
82 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
83 oid = oid_map[j].new_oid;
84 break;
88 /* We might have been asked to remap this name, due to a conflict */
89 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
90 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
91 name = attr_map[j].new_attr;
92 break;
96 /* We might have been asked to remap this subClassOf, due to a conflict */
97 for (j=0; subClassOf && attr_map && attr_map[j].old_attr; j++) {
98 if (strcasecmp(subClassOf, attr_map[j].old_attr) == 0) {
99 subClassOf = attr_map[j].new_attr;
100 break;
104 may = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MAY);
106 for (j=0; may && may[j]; j++) {
107 /* We might have been asked to remap this name, due to a conflict */
108 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
109 if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) {
110 may[j] = attr_map[attr_idx].new_attr;
111 break;
116 must = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MUST);
118 for (j=0; must && must[j]; j++) {
119 /* We might have been asked to remap this name, due to a conflict */
120 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
121 if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) {
122 must[j] = attr_map[attr_idx].new_attr;
123 break;
128 schema_entry = schema_class_description(mem_ctx, target,
129 SEPERATOR,
130 oid,
131 name,
132 NULL,
133 subClassOf,
134 objectClassCategory,
135 must,
136 may,
137 NULL);
138 if (schema_entry == NULL) {
139 talloc_free(mem_ctx);
140 DEBUG(0, ("failed to generate schema description for %s\n", name));
141 return NULL;
144 switch (target) {
145 case TARGET_OPENLDAP:
146 out = talloc_asprintf_append(out, "objectclass %s\n\n", schema_entry);
147 break;
148 case TARGET_FEDORA_DS:
149 out = talloc_asprintf_append(out, "objectClasses: %s\n", schema_entry);
150 break;
151 default:
152 talloc_free(mem_ctx);
153 DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
154 return NULL;
156 talloc_free(mem_ctx);
157 } while (0);
160 for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) {
161 if (ldb_attr_cmp(objectclass->subClassOf, print_class) == 0
162 && ldb_attr_cmp(objectclass->lDAPDisplayName, print_class) != 0) {
163 out = print_schema_recursive(out, schema, objectclass->lDAPDisplayName,
164 target, attrs_skip, attr_map, oid_map);
167 return out;
170 /* Routine to linearise our internal schema into the format that
171 OpenLDAP and Fedora DS use for their backend.
173 The 'mappings' are of a format like:
175 #Standard OpenLDAP attributes
176 labeledURI
177 #The memberOf plugin provides this attribute
178 memberOf
179 #These conflict with OpenLDAP builtins
180 attributeTypes:samba4AttributeTypes
181 2.5.21.5:1.3.6.1.4.1.7165.4.255.7
186 char *dsdb_convert_schema_to_openldap(struct ldb_context *ldb, char *target_str, const char *mappings)
188 /* Read list of attributes to skip, OIDs to map */
189 TALLOC_CTX *mem_ctx = talloc_new(ldb);
190 char *line;
191 char *out;
192 const char **attrs_skip = NULL;
193 unsigned int num_skip = 0;
194 struct oid_map *oid_map = NULL;
195 unsigned int num_oid_maps = 0;
196 struct attr_map *attr_map = NULL;
197 unsigned int num_attr_maps = 0;
198 struct dsdb_attribute *attribute;
199 struct dsdb_schema *schema;
200 enum dsdb_schema_convert_target target;
202 char *next_line = talloc_strdup(mem_ctx, mappings);
204 if (!target_str || strcasecmp(target_str, "openldap") == 0) {
205 target = TARGET_OPENLDAP;
206 } else if (strcasecmp(target_str, "fedora-ds") == 0) {
207 target = TARGET_FEDORA_DS;
208 } else {
209 talloc_free(mem_ctx);
210 DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str));
211 return NULL;
214 /* The mappings are line-separated, and specify details such as OIDs to skip etc */
215 while (1) {
216 line = next_line;
217 next_line = strchr(line, '\n');
218 if (!next_line) {
219 break;
221 next_line[0] = '\0';
222 next_line++;
224 /* Blank Line */
225 if (line[0] == '\0') {
226 continue;
228 /* Comment */
229 if (line[0] == '#') {
230 continue;
233 if (isdigit(line[0])) {
234 char *p = strchr(line, ':');
235 if (!p) {
236 DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line));
237 return NULL;
239 p[0] = '\0';
240 p++;
241 oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
242 trim_string(line, " ", " ");
243 oid_map[num_oid_maps].old_oid = talloc_strdup(oid_map, line);
244 trim_string(p, " ", " ");
245 oid_map[num_oid_maps].new_oid = p;
246 num_oid_maps++;
247 oid_map[num_oid_maps].old_oid = NULL;
248 } else {
249 char *p = strchr(line, ':');
250 if (p) {
251 /* remap attribute/objectClass */
252 p[0] = '\0';
253 p++;
254 attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
255 trim_string(line, " ", " ");
256 attr_map[num_attr_maps].old_attr = talloc_strdup(attr_map, line);
257 trim_string(p, " ", " ");
258 attr_map[num_attr_maps].new_attr = p;
259 num_attr_maps++;
260 attr_map[num_attr_maps].old_attr = NULL;
261 } else {
262 /* skip attribute/objectClass */
263 attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
264 trim_string(line, " ", " ");
265 attrs_skip[num_skip] = talloc_strdup(attrs_skip, line);
266 num_skip++;
267 attrs_skip[num_skip] = NULL;
272 schema = dsdb_get_schema(ldb, mem_ctx);
273 if (!schema) {
274 talloc_free(mem_ctx);
275 DEBUG(0, ("No schema on ldb to convert!\n"));
276 return NULL;
279 switch (target) {
280 case TARGET_OPENLDAP:
281 out = talloc_strdup(mem_ctx, "");
282 break;
283 case TARGET_FEDORA_DS:
284 out = talloc_strdup(mem_ctx, "dn: cn=schema\n");
285 break;
286 default:
287 talloc_free(mem_ctx);
288 DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
289 return NULL;
292 for (attribute=schema->attributes; attribute; attribute = attribute->next) {
293 const char *name = attribute->lDAPDisplayName;
294 const char *oid = attribute->attributeID_oid;
295 const char *syntax = attribute->attributeSyntax_oid;
296 const char *equality = NULL, *substring = NULL;
297 bool single_value = attribute->isSingleValued;
299 char *schema_entry = NULL;
300 unsigned int j;
302 /* We have been asked to skip some attributes/objectClasses */
303 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
304 continue;
307 /* We might have been asked to remap this oid, due to a conflict */
308 for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
309 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
310 oid = oid_map[j].new_oid;
311 break;
315 if (attribute->syntax) {
316 /* We might have been asked to remap this oid,
317 * due to a conflict, or lack of
318 * implementation */
319 syntax = attribute->syntax->ldap_oid;
320 /* We might have been asked to remap this oid, due to a conflict */
321 for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) {
322 if (strcasecmp(syntax, oid_map[j].old_oid) == 0) {
323 syntax = oid_map[j].new_oid;
324 break;
328 equality = attribute->syntax->equality;
329 substring = attribute->syntax->substring;
332 /* We might have been asked to remap this name, due to a conflict */
333 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
334 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
335 name = attr_map[j].new_attr;
336 break;
340 schema_entry = schema_attribute_description(mem_ctx,
341 target,
342 SEPERATOR,
343 oid,
344 name,
345 equality,
346 substring,
347 syntax,
348 single_value,
349 false,
350 NULL, NULL,
351 NULL, NULL,
352 false, false);
354 if (schema_entry == NULL) {
355 talloc_free(mem_ctx);
356 DEBUG(0, ("failed to generate attribute description for %s\n", name));
357 return NULL;
360 switch (target) {
361 case TARGET_OPENLDAP:
362 out = talloc_asprintf_append(out, "attributetype %s\n\n", schema_entry);
363 break;
364 case TARGET_FEDORA_DS:
365 out = talloc_asprintf_append(out, "attributeTypes: %s\n", schema_entry);
366 break;
367 default:
368 talloc_free(mem_ctx);
369 DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
370 return NULL;
374 out = print_schema_recursive(out, schema, "top", target, attrs_skip, attr_map, oid_map);
376 talloc_steal(ldb, out);
377 talloc_free(mem_ctx);
379 return out;