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