1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-08 21:18:16 +03:00
samba-mirror/source4/dsdb/schema/schema_convert_to_ol.c
Andrew Bartlett 2de07761e0 s4:dsdb Change dsdb_get_schema() callers to use new talloc argument
This choses an appropriate talloc context to attach the schema too,
long enough lived to ensure it does not go away before the operation
compleates.

Andrew Bartlett
2010-03-16 19:26:03 +11:00

361 lines
10 KiB
C

/*
schema conversion routines
Copyright (C) Andrew Bartlett 2006-2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "ldb.h"
#include "dsdb/samdb/samdb.h"
#include "system/locale.h"
#define SEPERATOR "\n "
struct attr_map {
char *old_attr;
char *new_attr;
};
struct oid_map {
char *old_oid;
char *new_oid;
};
static char *print_schema_recursive(char *append_to_string, struct dsdb_schema *schema, const char *print_class,
enum dsdb_schema_convert_target target,
const char **attrs_skip, const struct attr_map *attr_map, const struct oid_map *oid_map)
{
char *out = append_to_string;
const struct dsdb_class *objectclass;
objectclass = dsdb_class_by_lDAPDisplayName(schema, print_class);
if (!objectclass) {
DEBUG(0, ("Cannot find class %s in schema\n", print_class));
return NULL;
}
do {
TALLOC_CTX *mem_ctx = talloc_new(append_to_string);
const char *name = objectclass->lDAPDisplayName;
const char *oid = objectclass->governsID_oid;
const char *subClassOf = objectclass->subClassOf;
int objectClassCategory = objectclass->objectClassCategory;
const char **must;
const char **may;
char *schema_entry = NULL;
struct ldb_val objectclass_name_as_ldb_val = data_blob_string_const(objectclass->lDAPDisplayName);
struct ldb_message_element objectclass_name_as_el = {
.name = "objectClass",
.num_values = 1,
.values = &objectclass_name_as_ldb_val
};
unsigned int j;
unsigned int attr_idx;
if (!mem_ctx) {
DEBUG(0, ("Failed to create new talloc context\n"));
return NULL;
}
/* We have been asked to skip some attributes/objectClasses */
if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
continue;
}
/* We might have been asked to remap this oid, due to a conflict */
for (j=0; oid_map && oid_map[j].old_oid; j++) {
if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
oid = oid_map[j].new_oid;
break;
}
}
/* We might have been asked to remap this name, due to a conflict */
for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
if (strcasecmp(name, attr_map[j].old_attr) == 0) {
name = attr_map[j].new_attr;
break;
}
}
/* We might have been asked to remap this subClassOf, due to a conflict */
for (j=0; subClassOf && attr_map && attr_map[j].old_attr; j++) {
if (strcasecmp(subClassOf, attr_map[j].old_attr) == 0) {
subClassOf = attr_map[j].new_attr;
break;
}
}
may = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MAY);
for (j=0; may && may[j]; j++) {
/* We might have been asked to remap this name, due to a conflict */
for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) {
may[j] = attr_map[attr_idx].new_attr;
break;
}
}
}
must = dsdb_full_attribute_list(mem_ctx, schema, &objectclass_name_as_el, DSDB_SCHEMA_ALL_MUST);
for (j=0; must && must[j]; j++) {
/* We might have been asked to remap this name, due to a conflict */
for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) {
if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) {
must[j] = attr_map[attr_idx].new_attr;
break;
}
}
}
schema_entry = schema_class_description(mem_ctx, target,
SEPERATOR,
oid,
name,
NULL,
subClassOf,
objectClassCategory,
must,
may,
NULL);
if (schema_entry == NULL) {
DEBUG(0, ("failed to generate schema description for %s\n", name));
return NULL;
}
switch (target) {
case TARGET_OPENLDAP:
out = talloc_asprintf_append(out, "objectclass %s\n\n", schema_entry);
break;
case TARGET_FEDORA_DS:
out = talloc_asprintf_append(out, "objectClasses: %s\n", schema_entry);
break;
}
talloc_free(mem_ctx);
} while (0);
for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) {
if (ldb_attr_cmp(objectclass->subClassOf, print_class) == 0
&& ldb_attr_cmp(objectclass->lDAPDisplayName, print_class) != 0) {
out = print_schema_recursive(out, schema, objectclass->lDAPDisplayName,
target, attrs_skip, attr_map, oid_map);
}
}
return out;
}
/* Routine to linearise our internal schema into the format that
OpenLDAP and Fedora DS use for their backend.
The 'mappings' are of a format like:
#Standard OpenLDAP attributes
labeledURI
#The memberOf plugin provides this attribute
memberOf
#These conflict with OpenLDAP builtins
attributeTypes:samba4AttributeTypes
2.5.21.5:1.3.6.1.4.1.7165.4.255.7
*/
char *dsdb_convert_schema_to_openldap(struct ldb_context *ldb, char *target_str, const char *mappings)
{
/* Read list of attributes to skip, OIDs to map */
TALLOC_CTX *mem_ctx = talloc_new(ldb);
char *line;
char *out;
const char **attrs_skip = NULL;
unsigned int num_skip = 0;
struct oid_map *oid_map = NULL;
unsigned int num_oid_maps = 0;
struct attr_map *attr_map = NULL;
unsigned int num_attr_maps = 0;
struct dsdb_attribute *attribute;
struct dsdb_schema *schema;
enum dsdb_schema_convert_target target;
char *next_line = talloc_strdup(mem_ctx, mappings);
if (!target_str || strcasecmp(target_str, "openldap") == 0) {
target = TARGET_OPENLDAP;
} else if (strcasecmp(target_str, "fedora-ds") == 0) {
target = TARGET_FEDORA_DS;
} else {
DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str));
return NULL;
}
/* The mappings are line-seperated, and specify details such as OIDs to skip etc */
while (1) {
line = next_line;
next_line = strchr(line, '\n');
if (!next_line) {
break;
}
next_line[0] = '\0';
next_line++;
/* Blank Line */
if (line[0] == '\0') {
continue;
}
/* Comment */
if (line[0] == '#') {
continue;
}
if (isdigit(line[0])) {
char *p = strchr(line, ':');
if (!p) {
DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line));
return NULL;
}
p[0] = '\0';
p++;
oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
trim_string(line, " ", " ");
oid_map[num_oid_maps].old_oid = talloc_strdup(oid_map, line);
trim_string(p, " ", " ");
oid_map[num_oid_maps].new_oid = p;
num_oid_maps++;
oid_map[num_oid_maps].old_oid = NULL;
} else {
char *p = strchr(line, ':');
if (p) {
/* remap attribute/objectClass */
p[0] = '\0';
p++;
attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
trim_string(line, " ", " ");
attr_map[num_attr_maps].old_attr = talloc_strdup(attr_map, line);
trim_string(p, " ", " ");
attr_map[num_attr_maps].new_attr = p;
num_attr_maps++;
attr_map[num_attr_maps].old_attr = NULL;
} else {
/* skip attribute/objectClass */
attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
trim_string(line, " ", " ");
attrs_skip[num_skip] = talloc_strdup(attrs_skip, line);
num_skip++;
attrs_skip[num_skip] = NULL;
}
}
}
schema = dsdb_get_schema(ldb, mem_ctx);
if (!schema) {
DEBUG(0, ("No schema on ldb to convert!\n"));
return NULL;
}
switch (target) {
case TARGET_OPENLDAP:
out = talloc_strdup(mem_ctx, "");
break;
case TARGET_FEDORA_DS:
out = talloc_strdup(mem_ctx, "dn: cn=schema\n");
break;
}
for (attribute=schema->attributes; attribute; attribute = attribute->next) {
const char *name = attribute->lDAPDisplayName;
const char *oid = attribute->attributeID_oid;
const char *syntax = attribute->attributeSyntax_oid;
const char *equality = NULL, *substring = NULL;
bool single_value = attribute->isSingleValued;
char *schema_entry = NULL;
unsigned int j;
/* We have been asked to skip some attributes/objectClasses */
if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
continue;
}
/* We might have been asked to remap this oid, due to a conflict */
for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
oid = oid_map[j].new_oid;
break;
}
}
if (attribute->syntax) {
/* We might have been asked to remap this oid,
* due to a conflict, or lack of
* implementation */
syntax = attribute->syntax->ldap_oid;
/* We might have been asked to remap this oid, due to a conflict */
for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) {
if (strcasecmp(syntax, oid_map[j].old_oid) == 0) {
syntax = oid_map[j].new_oid;
break;
}
}
equality = attribute->syntax->equality;
substring = attribute->syntax->substring;
}
/* We might have been asked to remap this name, due to a conflict */
for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
if (strcasecmp(name, attr_map[j].old_attr) == 0) {
name = attr_map[j].new_attr;
break;
}
}
schema_entry = schema_attribute_description(mem_ctx,
target,
SEPERATOR,
oid,
name,
equality,
substring,
syntax,
single_value,
false,
NULL, NULL,
NULL, NULL,
false, false);
if (schema_entry == NULL) {
DEBUG(0, ("failed to generate attribute description for %s\n", name));
return NULL;
}
switch (target) {
case TARGET_OPENLDAP:
out = talloc_asprintf_append(out, "attributetype %s\n\n", schema_entry);
break;
case TARGET_FEDORA_DS:
out = talloc_asprintf_append(out, "attributeTypes: %s\n", schema_entry);
break;
}
}
out = print_schema_recursive(out, schema, "top", target, attrs_skip, attr_map, oid_map);
return out;
}