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/>.
23 #include "dsdb/samdb/samdb.h"
24 #include "system/locale.h"
28 #define SEPARATOR "\n "
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
);
48 DEBUG(0, ("Cannot find class %s in schema\n", print_class
));
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
;
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",
66 .values
= &objectclass_name_as_ldb_val
69 unsigned int attr_idx
;
72 DEBUG(0, ("Failed to create new talloc context\n"));
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
;
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
;
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
;
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
;
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
;
124 schema_entry
= schema_class_description(mem_ctx
, target
,
134 if (schema_entry
== NULL
) {
135 talloc_free(mem_ctx
);
136 DEBUG(0, ("failed to generate schema description for %s\n", name
));
141 case TARGET_OPENLDAP
:
142 out
= talloc_asprintf_append(out
, "objectclass %s\n\n", schema_entry
);
144 case TARGET_FEDORA_DS
:
145 out
= talloc_asprintf_append(out
, "objectClasses: %s\n", schema_entry
);
148 talloc_free(mem_ctx
);
149 DEBUG(0,(__location__
" Wrong type of target %u!\n", (unsigned)target
));
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
);
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
173 #The memberOf plugin provides this attribute
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
);
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
;
205 talloc_free(mem_ctx
);
206 DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str
));
210 /* The mappings are line-separated, and specify details such as OIDs to skip etc */
213 next_line
= strchr(line
, '\n');
221 if (line
[0] == '\0') {
225 if (line
[0] == '#') {
229 if (isdigit(line
[0])) {
230 char *p
= strchr(line
, ':');
232 DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line
));
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
;
243 oid_map
[num_oid_maps
].old_oid
= NULL
;
245 char *p
= strchr(line
, ':');
247 /* remap attribute/objectClass */
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
;
256 attr_map
[num_attr_maps
].old_attr
= NULL
;
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
);
263 attrs_skip
[num_skip
] = NULL
;
268 schema
= dsdb_get_schema(ldb
, mem_ctx
);
270 talloc_free(mem_ctx
);
271 DEBUG(0, ("No schema on ldb to convert!\n"));
276 case TARGET_OPENLDAP
:
277 out
= talloc_strdup(mem_ctx
, "");
279 case TARGET_FEDORA_DS
:
280 out
= talloc_strdup(mem_ctx
, "dn: cn=schema\n");
283 talloc_free(mem_ctx
);
284 DEBUG(0,(__location__
" Wrong type of target %u!\n", (unsigned)target
));
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
;
298 /* We have been asked to skip some attributes/objectClasses */
299 if (attrs_skip
&& str_list_check_ci(attrs_skip
, name
)) {
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
;
311 if (attribute
->syntax
) {
312 /* We might have been asked to remap this oid,
313 * due to a conflict, or lack of
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
;
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
;
336 schema_entry
= schema_attribute_description(mem_ctx
,
350 if (schema_entry
== NULL
) {
351 talloc_free(mem_ctx
);
352 DEBUG(0, ("failed to generate attribute description for %s\n", name
));
357 case TARGET_OPENLDAP
:
358 out
= talloc_asprintf_append(out
, "attributetype %s\n\n", schema_entry
);
360 case TARGET_FEDORA_DS
:
361 out
= talloc_asprintf_append(out
, "attributeTypes: %s\n", schema_entry
);
364 talloc_free(mem_ctx
);
365 DEBUG(0,(__location__
" Wrong type of target %u!\n", (unsigned)target
));
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
);