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