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