mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
b07d97d7f5
Signed-off-by: Karolin Seeger <kseeger@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
380 lines
11 KiB
C
380 lines
11 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) {
|
|
talloc_free(mem_ctx);
|
|
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;
|
|
default:
|
|
talloc_free(mem_ctx);
|
|
DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
|
|
return NULL;
|
|
}
|
|
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 {
|
|
talloc_free(mem_ctx);
|
|
DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str));
|
|
return NULL;
|
|
}
|
|
|
|
/* The mappings are line-separated, 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) {
|
|
talloc_free(mem_ctx);
|
|
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;
|
|
default:
|
|
talloc_free(mem_ctx);
|
|
DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
|
|
return NULL;
|
|
}
|
|
|
|
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) {
|
|
talloc_free(mem_ctx);
|
|
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;
|
|
default:
|
|
talloc_free(mem_ctx);
|
|
DEBUG(0,(__location__ " Wrong type of target %u!", (unsigned)target));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
out = print_schema_recursive(out, schema, "top", target, attrs_skip, attr_map, oid_map);
|
|
|
|
talloc_steal(ldb, out);
|
|
talloc_free(mem_ctx);
|
|
|
|
return out;
|
|
}
|
|
|