s3:utils: let smbstatus report anonymous signing/encryption explicitly
[Samba.git] / source4 / dsdb / schema / schema_convert_to_ol.c
blob013787e9f4c678d35fae0b612adc3cf58424359b
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 SEPARATOR "\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 /* We have been asked to skip some attributes/objectClasses */
53 if (attrs_skip == NULL || !str_list_check_ci(attrs_skip, objectclass->lDAPDisplayName)) {
54 TALLOC_CTX *mem_ctx = talloc_new(append_to_string);
55 const char *name = objectclass->lDAPDisplayName;
56 const char *oid = objectclass->governsID_oid;
57 const char *subClassOf = objectclass->subClassOf;
58 int objectClassCategory = objectclass->objectClassCategory;
59 const char **must;
60 const char **may;
61 char *schema_entry = NULL;
62 struct ldb_val objectclass_name_as_ldb_val = data_blob_string_const(objectclass->lDAPDisplayName);
63 struct ldb_message_element objectclass_name_as_el = {
64 .name = "objectClass",
65 .num_values = 1,
66 .values = &objectclass_name_as_ldb_val
68 unsigned int j;
69 unsigned int attr_idx;
71 if (!mem_ctx) {
72 DEBUG(0, ("Failed to create new talloc context\n"));
73 return NULL;
76 /* We might have been asked to remap this oid, due to a conflict */
77 for (j=0; oid_map && oid_map[j].old_oid; j++) {
78 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
79 oid = oid_map[j].new_oid;
80 break;
84 /* We might have been asked to remap this name, due to a conflict */
85 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
86 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
87 name = attr_map[j].new_attr;
88 break;
92 /* We might have been asked to remap this subClassOf, due to a conflict */
93 for (j=0; subClassOf && attr_map && attr_map[j].old_attr; j++) {
94 if (strcasecmp(subClassOf, attr_map[j].old_attr) == 0) {
95 subClassOf = attr_map[j].new_attr;
96 break;
100 may = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MAY);
102 for (j=0; may && may[j]; j++) {
103 /* We might have been asked to remap this name, due to a conflict */
104 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
105 if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) {
106 may[j] = attr_map[attr_idx].new_attr;
107 break;
112 must = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MUST);
114 for (j=0; must && must[j]; j++) {
115 /* We might have been asked to remap this name, due to a conflict */
116 for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
117 if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) {
118 must[j] = attr_map[attr_idx].new_attr;
119 break;
124 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 if (schema_entry == NULL) {
135 talloc_free(mem_ctx);
136 DEBUG(0, ("failed to generate schema description for %s\n", name));
137 return NULL;
140 switch (target) {
141 case TARGET_OPENLDAP:
142 out = talloc_asprintf_append(out, "objectclass %s\n\n", schema_entry);
143 break;
144 case TARGET_FEDORA_DS:
145 out = talloc_asprintf_append(out, "objectClasses: %s\n", schema_entry);
146 break;
147 default:
148 talloc_free(mem_ctx);
149 DEBUG(0,(__location__ " Wrong type of target %u!\n", (unsigned)target));
150 return NULL;
152 talloc_free(mem_ctx);
156 for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) {
157 if (ldb_attr_cmp(objectclass->subClassOf, print_class) == 0
158 && ldb_attr_cmp(objectclass->lDAPDisplayName, print_class) != 0) {
159 out = print_schema_recursive(out, schema, objectclass->lDAPDisplayName,
160 target, attrs_skip, attr_map, oid_map);
163 return out;
166 /* Routine to linearise our internal schema into the format that
167 OpenLDAP and Fedora DS use for their backend.
169 The 'mappings' are of a format like:
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
182 char *dsdb_convert_schema_to_openldap(struct ldb_context *ldb, char *target_str, const char *mappings)
184 /* Read list of attributes to skip, OIDs to map */
185 TALLOC_CTX *mem_ctx = talloc_new(ldb);
186 char *line;
187 char *out;
188 const char **attrs_skip = NULL;
189 unsigned int num_skip = 0;
190 struct oid_map *oid_map = NULL;
191 unsigned int num_oid_maps = 0;
192 struct attr_map *attr_map = NULL;
193 unsigned int num_attr_maps = 0;
194 struct dsdb_attribute *attribute;
195 struct dsdb_schema *schema;
196 enum dsdb_schema_convert_target target;
198 char *next_line = talloc_strdup(mem_ctx, mappings);
200 if (!target_str || strcasecmp(target_str, "openldap") == 0) {
201 target = TARGET_OPENLDAP;
202 } else if (strcasecmp(target_str, "fedora-ds") == 0) {
203 target = TARGET_FEDORA_DS;
204 } else {
205 talloc_free(mem_ctx);
206 DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str));
207 return NULL;
210 /* The mappings are line-separated, and specify details such as OIDs to skip etc */
211 while (1) {
212 line = next_line;
213 next_line = strchr(line, '\n');
214 if (!next_line) {
215 break;
217 next_line[0] = '\0';
218 next_line++;
220 /* Blank Line */
221 if (line[0] == '\0') {
222 continue;
224 /* Comment */
225 if (line[0] == '#') {
226 continue;
229 if (isdigit(line[0])) {
230 char *p = strchr(line, ':');
231 if (!p) {
232 DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line));
233 return NULL;
235 p[0] = '\0';
236 p++;
237 oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
238 trim_string(line, " ", " ");
239 oid_map[num_oid_maps].old_oid = talloc_strdup(oid_map, line);
240 trim_string(p, " ", " ");
241 oid_map[num_oid_maps].new_oid = p;
242 num_oid_maps++;
243 oid_map[num_oid_maps].old_oid = NULL;
244 } else {
245 char *p = strchr(line, ':');
246 if (p) {
247 /* remap attribute/objectClass */
248 p[0] = '\0';
249 p++;
250 attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
251 trim_string(line, " ", " ");
252 attr_map[num_attr_maps].old_attr = talloc_strdup(attr_map, line);
253 trim_string(p, " ", " ");
254 attr_map[num_attr_maps].new_attr = p;
255 num_attr_maps++;
256 attr_map[num_attr_maps].old_attr = NULL;
257 } else {
258 /* skip attribute/objectClass */
259 attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
260 trim_string(line, " ", " ");
261 attrs_skip[num_skip] = talloc_strdup(attrs_skip, line);
262 num_skip++;
263 attrs_skip[num_skip] = NULL;
268 schema = dsdb_get_schema(ldb, mem_ctx);
269 if (!schema) {
270 talloc_free(mem_ctx);
271 DEBUG(0, ("No schema on ldb to convert!\n"));
272 return NULL;
275 switch (target) {
276 case TARGET_OPENLDAP:
277 out = talloc_strdup(mem_ctx, "");
278 break;
279 case TARGET_FEDORA_DS:
280 out = talloc_strdup(mem_ctx, "dn: cn=schema\n");
281 break;
282 default:
283 talloc_free(mem_ctx);
284 DEBUG(0,(__location__ " Wrong type of target %u!\n", (unsigned)target));
285 return NULL;
288 for (attribute=schema->attributes; attribute; attribute = attribute->next) {
289 const char *name = attribute->lDAPDisplayName;
290 const char *oid = attribute->attributeID_oid;
291 const char *syntax = attribute->attributeSyntax_oid;
292 const char *equality = NULL, *substring = NULL;
293 bool single_value = attribute->isSingleValued;
295 char *schema_entry = NULL;
296 unsigned int j;
298 /* We have been asked to skip some attributes/objectClasses */
299 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
300 continue;
303 /* We might have been asked to remap this oid, due to a conflict */
304 for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
305 if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
306 oid = oid_map[j].new_oid;
307 break;
311 if (attribute->syntax) {
312 /* We might have been asked to remap this oid,
313 * due to a conflict, or lack of
314 * implementation */
315 syntax = attribute->syntax->ldap_oid;
316 /* We might have been asked to remap this oid, due to a conflict */
317 for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) {
318 if (strcasecmp(syntax, oid_map[j].old_oid) == 0) {
319 syntax = oid_map[j].new_oid;
320 break;
324 equality = attribute->syntax->equality;
325 substring = attribute->syntax->substring;
328 /* We might have been asked to remap this name, due to a conflict */
329 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
330 if (strcasecmp(name, attr_map[j].old_attr) == 0) {
331 name = attr_map[j].new_attr;
332 break;
336 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);
350 if (schema_entry == NULL) {
351 talloc_free(mem_ctx);
352 DEBUG(0, ("failed to generate attribute description for %s\n", name));
353 return NULL;
356 switch (target) {
357 case TARGET_OPENLDAP:
358 out = talloc_asprintf_append(out, "attributetype %s\n\n", schema_entry);
359 break;
360 case TARGET_FEDORA_DS:
361 out = talloc_asprintf_append(out, "attributeTypes: %s\n", schema_entry);
362 break;
363 default:
364 talloc_free(mem_ctx);
365 DEBUG(0,(__location__ " Wrong type of target %u!\n", (unsigned)target));
366 return NULL;
370 out = print_schema_recursive(out, schema, "top", target, attrs_skip, attr_map, oid_map);
372 talloc_steal(ldb, out);
373 talloc_free(mem_ctx);
375 return out;