summaryrefslogtreecommitdiff
path: root/source4/dsdb
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb')
-rw-r--r--source4/dsdb/config.mk3
-rw-r--r--source4/dsdb/schema/schema_convert_to_ol.c350
-rw-r--r--source4/dsdb/schema/schema_init.c106
-rw-r--r--source4/dsdb/schema/schema_set.c2
4 files changed, 367 insertions, 94 deletions
diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk
index 2ca4e4ca6d..6db2890738 100644
--- a/source4/dsdb/config.mk
+++ b/source4/dsdb/config.mk
@@ -37,7 +37,8 @@ SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \
schema_set.o \
schema_query.o \
schema_syntax.o \
- schema_description.o)
+ schema_description.o \
+ schema_convert_to_ol.o)
$(eval $(call proto_header_template,$(dsdbsrcdir)/schema/proto.h,$(SAMDB_SCHEMA_OBJ_FILES:.o=.c)))
# PUBLIC_HEADERS += dsdb/schema/schema.h
diff --git a/source4/dsdb/schema/schema_convert_to_ol.c b/source4/dsdb/schema/schema_convert_to_ol.c
new file mode 100644
index 0000000000..ebcb7ade59
--- /dev/null
+++ b/source4/dsdb/schema/schema_convert_to_ol.c
@@ -0,0 +1,350 @@
+/*
+ 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;
+ const char *objectclass_name_as_list[] = {
+ objectclass->lDAPDisplayName,
+ NULL
+ };
+ int j;
+ 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;
+ }
+ }
+
+ may = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, 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_list, 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;
+ int num_skip = 0;
+ struct oid_map *oid_map = NULL;
+ int num_oid_maps = 0;
+ struct attr_map *attr_map = NULL;
+ 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);
+ 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;
+ 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;
+}
+
diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c
index a67aecd1e8..b6a7cf7cc8 100644
--- a/source4/dsdb/schema/schema_init.c
+++ b/source4/dsdb/schema/schema_init.c
@@ -808,6 +808,12 @@ WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
#define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__)
+/*
+ Create a DSDB schema from the ldb results provided. This is called
+ directly when the schema is provisioned from an on-disk LDIF file, or
+ from dsdb_schema_from_schema_dn below
+*/
+
int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
struct smb_iconv_convenience *iconv_convenience,
struct ldb_result *schema_res,
@@ -908,96 +914,9 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
return LDB_SUCCESS;
}
-/* This recursive load of the objectClasses presumes that they
- * everything is in a strict subClassOf hirarchy.
- *
- * We load this in order so we produce certain outputs (such as the
- * exported schema for openldap, and sorted objectClass attribute) 'in
- * order' */
-
-static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn,
- TALLOC_CTX *mem_ctx,
- struct ldb_result *search_from,
- struct ldb_result *res_list)
-{
- int i;
- int ret = 0;
- for (i=0; i < search_from->count; i++) {
- struct ldb_result *res;
- const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i],
- "lDAPDisplayname", NULL);
-
- ret = ldb_search(ldb, mem_ctx, &res,
- schemadn, LDB_SCOPE_SUBTREE, NULL,
- "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
- name, name);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- res_list->msgs = talloc_realloc(res_list, res_list->msgs,
- struct ldb_message *, res_list->count + 2);
- if (!res_list->msgs) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- res_list->msgs[res_list->count] = talloc_move(res_list,
- &search_from->msgs[i]);
- res_list->count++;
- res_list->msgs[res_list->count] = NULL;
-
- if (res->count > 0) {
- ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list);
- }
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
- return ret;
-}
-
-static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
- TALLOC_CTX *mem_ctx,
- struct ldb_result **objectclasses_res,
- char **error_string)
-{
- TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
- struct ldb_result *top_res, *ret_res;
- int ret;
- if (!local_ctx) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* Download 'top' */
- ret = ldb_search(ldb, local_ctx, &top_res,
- schemadn, LDB_SCOPE_SUBTREE, NULL,
- "(&(objectClass=classSchema)(lDAPDisplayName=top))");
- if (ret != LDB_SUCCESS) {
- *error_string = talloc_asprintf(mem_ctx,
- "dsdb_schema: failed to search for top classSchema object: %s",
- ldb_errstring(ldb));
- return ret;
- }
-
- if (top_res->count != 1) {
- *error_string = talloc_asprintf(mem_ctx,
- "dsdb_schema: failed to find top classSchema object");
- return LDB_ERR_NO_SUCH_OBJECT;
- }
-
- ret_res = talloc_zero(local_ctx, struct ldb_result);
- if (!ret_res) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- *objectclasses_res = talloc_move(mem_ctx, &ret_res);
- return ret;
-}
+/*
+ Given an LDB, and the DN, return a populated schema
+*/
int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
struct smb_iconv_convenience *iconv_convenience,
@@ -1065,10 +984,13 @@ int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
/*
* load the objectClass definitions
*/
- ret = fetch_objectclass_schema(ldb, schema_dn, tmp_ctx, &c_res, &error_string);
+ ret = ldb_search(ldb, tmp_ctx, &c_res,
+ schema_dn, LDB_SCOPE_ONELEVEL, NULL,
+ "(objectClass=classSchema)");
if (ret != LDB_SUCCESS) {
*error_string_out = talloc_asprintf(mem_ctx,
- "Failed to fetch objectClass schema elements: %s", error_string);
+ "dsdb_schema: failed to search attributeSchema objects: %s",
+ ldb_errstring(ldb));
talloc_free(tmp_ctx);
return ret;
}
diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c
index 6abd8a8f88..d52976958d 100644
--- a/source4/dsdb/schema/schema_set.c
+++ b/source4/dsdb/schema/schema_set.c
@@ -277,7 +277,7 @@ void dsdb_make_schema_global(struct ldb_context *ldb)
* schema itself to the directory.
*/
-WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df)
+WERROR dsdb_attach_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df)
{
struct ldb_ldif *ldif;
struct ldb_message *msg;