diff options
Diffstat (limited to 'source4/dsdb/schema')
-rw-r--r-- | source4/dsdb/schema/schema_init.c | 545 | ||||
-rw-r--r-- | source4/dsdb/schema/schema_query.c | 344 | ||||
-rw-r--r-- | source4/dsdb/schema/schema_set.c | 254 |
3 files changed, 598 insertions, 545 deletions
diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 73be580347..3ed7daee59 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -1409,548 +1409,3 @@ WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema, return WERR_OK; } -const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema, - uint32_t id) -{ - struct dsdb_attribute *cur; - - /* - * 0xFFFFFFFF is used as value when no mapping table is available, - * so don't try to match with it - */ - if (id == 0xFFFFFFFF) return NULL; - - /* TODO: add binary search */ - for (cur = schema->attributes; cur; cur = cur->next) { - if (cur->attributeID_id != id) continue; - - return cur; - } - - return NULL; -} - -const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema, - const char *oid) -{ - struct dsdb_attribute *cur; - - if (!oid) return NULL; - - /* TODO: add binary search */ - for (cur = schema->attributes; cur; cur = cur->next) { - if (strcmp(cur->attributeID_oid, oid) != 0) continue; - - return cur; - } - - return NULL; -} - -const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema, - const char *name) -{ - struct dsdb_attribute *cur; - - if (!name) return NULL; - - /* TODO: add binary search */ - for (cur = schema->attributes; cur; cur = cur->next) { - if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue; - - return cur; - } - - return NULL; -} - -const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema, - int linkID) -{ - struct dsdb_attribute *cur; - - /* TODO: add binary search */ - for (cur = schema->attributes; cur; cur = cur->next) { - if (cur->linkID != linkID) continue; - - return cur; - } - - return NULL; -} - -const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema, - uint32_t id) -{ - struct dsdb_class *cur; - - /* - * 0xFFFFFFFF is used as value when no mapping table is available, - * so don't try to match with it - */ - if (id == 0xFFFFFFFF) return NULL; - - /* TODO: add binary search */ - for (cur = schema->classes; cur; cur = cur->next) { - if (cur->governsID_id != id) continue; - - return cur; - } - - return NULL; -} - -const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema, - const char *oid) -{ - struct dsdb_class *cur; - - if (!oid) return NULL; - - /* TODO: add binary search */ - for (cur = schema->classes; cur; cur = cur->next) { - if (strcmp(cur->governsID_oid, oid) != 0) continue; - - return cur; - } - - return NULL; -} - -const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema, - const char *name) -{ - struct dsdb_class *cur; - - if (!name) return NULL; - - /* TODO: add binary search */ - for (cur = schema->classes; cur; cur = cur->next) { - if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue; - - return cur; - } - - return NULL; -} - -const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema, - const char *cn) -{ - struct dsdb_class *cur; - - if (!cn) return NULL; - - /* TODO: add binary search */ - for (cur = schema->classes; cur; cur = cur->next) { - if (strcasecmp(cur->cn, cn) != 0) continue; - - return cur; - } - - return NULL; -} - -const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema, - uint32_t id) -{ - const struct dsdb_attribute *a; - const struct dsdb_class *c; - - /* TODO: add binary search */ - a = dsdb_attribute_by_attributeID_id(schema, id); - if (a) { - return a->lDAPDisplayName; - } - - c = dsdb_class_by_governsID_id(schema, id); - if (c) { - return c->lDAPDisplayName; - } - - return NULL; -} - -/** - Return a list of linked attributes, in lDAPDisplayName format. - - This may be used to determine if a modification would require - backlinks to be updated, for example -*/ - -WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret) -{ - const char **attr_list = NULL; - struct dsdb_attribute *cur; - int i = 0; - for (cur = schema->attributes; cur; cur = cur->next) { - if (cur->linkID == 0) continue; - - attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2); - if (!attr_list) { - return WERR_NOMEM; - } - attr_list[i] = cur->lDAPDisplayName; - i++; - } - attr_list[i] = NULL; - *attr_list_ret = attr_list; - return WERR_OK; -} - -char **merge_attr_list(TALLOC_CTX *mem_ctx, - char **attrs, const char **new_attrs) -{ - char **ret_attrs; - int i; - size_t new_len, orig_len = str_list_length((const char **)attrs); - if (!new_attrs) { - return attrs; - } - - ret_attrs = talloc_realloc(mem_ctx, - attrs, char *, orig_len + str_list_length(new_attrs) + 1); - if (ret_attrs) { - for (i=0; i < str_list_length(new_attrs); i++) { - ret_attrs[orig_len + i] = new_attrs[i]; - } - new_len = orig_len + str_list_length(new_attrs); - - ret_attrs[new_len] = NULL; - } - - return ret_attrs; -} - -/* - Return a merged list of the attributes of exactly one class (not - considering subclasses, auxillary classes etc) -*/ - -char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *class, enum dsdb_attr_list_query query) -{ - char **attr_list = NULL; - switch (query) { - case DSDB_SCHEMA_ALL_MAY: - attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain); - attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain); - break; - - case DSDB_SCHEMA_ALL_MUST: - attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain); - attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain); - break; - - case DSDB_SCHEMA_SYS_MAY: - attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain); - break; - - case DSDB_SCHEMA_SYS_MUST: - attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain); - break; - - case DSDB_SCHEMA_MAY: - attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain); - break; - - case DSDB_SCHEMA_MUST: - attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain); - break; - - case DSDB_SCHEMA_ALL: - attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain); - attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain); - attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain); - attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain); - break; - } - return attr_list; -} - -static char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, - const struct dsdb_schema *schema, - const char **class_list, - enum dsdb_attr_list_query query) -{ - int i; - const struct dsdb_class *class; - - char **attr_list = NULL; - char **this_class_list; - char **recursive_list; - - for (i=0; class_list && class_list[i]; i++) { - class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]); - - this_class_list = dsdb_attribute_list(mem_ctx, class, query); - attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)this_class_list); - - recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, - class->systemAuxiliaryClass, - query); - - attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list); - - recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, - class->auxiliaryClass, - query); - - attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list); - - } - return attr_list; -} - -char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx, - const struct dsdb_schema *schema, - const char **class_list, - enum dsdb_attr_list_query query) -{ - char **attr_list = dsdb_full_attribute_list_internal(mem_ctx, schema, class_list, query); - size_t new_len = str_list_length((const char **)attr_list); - - /* Remove duplicates */ - if (new_len > 1) { - int i; - qsort(attr_list, new_len, - sizeof(*attr_list), - (comparison_fn_t)strcasecmp); - - for (i=1 ; i < new_len; i++) { - char **val1 = &attr_list[i-1]; - char **val2 = &attr_list[i]; - if (ldb_attr_cmp(*val1, *val2) == 0) { - memmove(val1, val2, (new_len - i) * sizeof( *attr_list)); - new_len--; - i--; - } - } - } - return attr_list; -} -/** - * Attach the schema to an opaque pointer on the ldb, so ldb modules - * can find it - */ - -int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema) -{ - int ret; - - ret = ldb_set_opaque(ldb, "dsdb_schema", schema); - if (ret != LDB_SUCCESS) { - return ret; - } - - talloc_steal(ldb, schema); - - return LDB_SUCCESS; -} - -/** - * Global variable to hold one copy of the schema, used to avoid memory bloat - */ -static struct dsdb_schema *global_schema; - -/** - * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process - */ -int dsdb_set_global_schema(struct ldb_context *ldb) -{ - int ret; - if (!global_schema) { - return LDB_SUCCESS; - } - ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema); - if (ret != LDB_SUCCESS) { - return ret; - } - - /* Keep a reference to this schema, just incase the global copy is replaced */ - if (talloc_reference(ldb, global_schema) == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - return LDB_SUCCESS; -} - -/** - * Find the schema object for this ldb - */ - -struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb) -{ - const void *p; - struct dsdb_schema *schema; - - /* see if we have a cached copy */ - p = ldb_get_opaque(ldb, "dsdb_schema"); - if (!p) { - return NULL; - } - - schema = talloc_get_type(p, struct dsdb_schema); - if (!schema) { - return NULL; - } - - return schema; -} - -/** - * Make the schema found on this ldb the 'global' schema - */ - -void dsdb_make_schema_global(struct ldb_context *ldb) -{ - struct dsdb_schema *schema = dsdb_get_schema(ldb); - if (!schema) { - return; - } - - if (global_schema) { - talloc_unlink(talloc_autofree_context(), schema); - } - - talloc_steal(talloc_autofree_context(), schema); - global_schema = schema; - - dsdb_set_global_schema(ldb); -} - - -/** - * Rather than read a schema from the LDB itself, read it from an ldif - * file. This allows schema to be loaded and used while adding the - * schema itself to the directory. - */ - -WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df) -{ - struct ldb_ldif *ldif; - struct ldb_message *msg; - TALLOC_CTX *mem_ctx; - WERROR status; - int ret; - struct dsdb_schema *schema; - const struct ldb_val *prefix_val; - const struct ldb_val *info_val; - struct ldb_val info_val_default; - - mem_ctx = talloc_new(ldb); - if (!mem_ctx) { - goto nomem; - } - - schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm"))); - - schema->fsmo.we_are_master = true; - schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER"); - if (!schema->fsmo.master_dn) { - goto nomem; - } - - /* - * load the prefixMap attribute from pf - */ - ldif = ldb_ldif_read_string(ldb, &pf); - if (!ldif) { - status = WERR_INVALID_PARAM; - goto failed; - } - talloc_steal(mem_ctx, ldif); - - msg = ldb_msg_canonicalize(ldb, ldif->msg); - if (!msg) { - goto nomem; - } - talloc_steal(mem_ctx, msg); - talloc_free(ldif); - - prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap"); - if (!prefix_val) { - status = WERR_INVALID_PARAM; - goto failed; - } - - info_val = ldb_msg_find_ldb_val(msg, "schemaInfo"); - if (!info_val) { - info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000"); - if (!info_val_default.data) { - goto nomem; - } - talloc_steal(mem_ctx, info_val_default.data); - info_val = &info_val_default; - } - - status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val); - if (!W_ERROR_IS_OK(status)) { - goto failed; - } - - /* - * load the attribute and class definitions outof df - */ - while ((ldif = ldb_ldif_read_string(ldb, &df))) { - bool is_sa; - bool is_sc; - - talloc_steal(mem_ctx, ldif); - - msg = ldb_msg_canonicalize(ldb, ldif->msg); - if (!msg) { - goto nomem; - } - - talloc_steal(mem_ctx, msg); - talloc_free(ldif); - - is_sa = ldb_msg_check_string_attribute(msg, "objectClass", "attributeSchema"); - is_sc = ldb_msg_check_string_attribute(msg, "objectClass", "classSchema"); - - if (is_sa) { - struct dsdb_attribute *sa; - - sa = talloc_zero(schema, struct dsdb_attribute); - if (!sa) { - goto nomem; - } - - status = dsdb_attribute_from_ldb(schema, msg, sa, sa); - if (!W_ERROR_IS_OK(status)) { - goto failed; - } - - DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *); - } else if (is_sc) { - struct dsdb_class *sc; - - sc = talloc_zero(schema, struct dsdb_class); - if (!sc) { - goto nomem; - } - - status = dsdb_class_from_ldb(schema, msg, sc, sc); - if (!W_ERROR_IS_OK(status)) { - goto failed; - } - - DLIST_ADD_END(schema->classes, sc, struct dsdb_class *); - } - } - - ret = dsdb_set_schema(ldb, schema); - if (ret != LDB_SUCCESS) { - status = WERR_FOOBAR; - goto failed; - } - - goto done; - -nomem: - status = WERR_NOMEM; -failed: -done: - talloc_free(mem_ctx); - return status; -} diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c new file mode 100644 index 0000000000..ca26ffd206 --- /dev/null +++ b/source4/dsdb/schema/schema_query.c @@ -0,0 +1,344 @@ +/* + Unix SMB/CIFS mplementation. + DSDB schema header + + Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 "dsdb/samdb/samdb.h" + +const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema, + uint32_t id) +{ + struct dsdb_attribute *cur; + + /* + * 0xFFFFFFFF is used as value when no mapping table is available, + * so don't try to match with it + */ + if (id == 0xFFFFFFFF) return NULL; + + /* TODO: add binary search */ + for (cur = schema->attributes; cur; cur = cur->next) { + if (cur->attributeID_id != id) continue; + + return cur; + } + + return NULL; +} + +const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema, + const char *oid) +{ + struct dsdb_attribute *cur; + + if (!oid) return NULL; + + /* TODO: add binary search */ + for (cur = schema->attributes; cur; cur = cur->next) { + if (strcmp(cur->attributeID_oid, oid) != 0) continue; + + return cur; + } + + return NULL; +} + +const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema, + const char *name) +{ + struct dsdb_attribute *cur; + + if (!name) return NULL; + + /* TODO: add binary search */ + for (cur = schema->attributes; cur; cur = cur->next) { + if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue; + + return cur; + } + + return NULL; +} + +const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema, + int linkID) +{ + struct dsdb_attribute *cur; + + /* TODO: add binary search */ + for (cur = schema->attributes; cur; cur = cur->next) { + if (cur->linkID != linkID) continue; + + return cur; + } + + return NULL; +} + +const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema, + uint32_t id) +{ + struct dsdb_class *cur; + + /* + * 0xFFFFFFFF is used as value when no mapping table is available, + * so don't try to match with it + */ + if (id == 0xFFFFFFFF) return NULL; + + /* TODO: add binary search */ + for (cur = schema->classes; cur; cur = cur->next) { + if (cur->governsID_id != id) continue; + + return cur; + } + + return NULL; +} + +const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema, + const char *oid) +{ + struct dsdb_class *cur; + + if (!oid) return NULL; + + /* TODO: add binary search */ + for (cur = schema->classes; cur; cur = cur->next) { + if (strcmp(cur->governsID_oid, oid) != 0) continue; + + return cur; + } + + return NULL; +} + +const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema, + const char *name) +{ + struct dsdb_class *cur; + + if (!name) return NULL; + + /* TODO: add binary search */ + for (cur = schema->classes; cur; cur = cur->next) { + if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue; + + return cur; + } + + return NULL; +} + +const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema, + const char *cn) +{ + struct dsdb_class *cur; + + if (!cn) return NULL; + + /* TODO: add binary search */ + for (cur = schema->classes; cur; cur = cur->next) { + if (strcasecmp(cur->cn, cn) != 0) continue; + + return cur; + } + + return NULL; +} + +const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema, + uint32_t id) +{ + const struct dsdb_attribute *a; + const struct dsdb_class *c; + + /* TODO: add binary search */ + a = dsdb_attribute_by_attributeID_id(schema, id); + if (a) { + return a->lDAPDisplayName; + } + + c = dsdb_class_by_governsID_id(schema, id); + if (c) { + return c->lDAPDisplayName; + } + + return NULL; +} + +/** + Return a list of linked attributes, in lDAPDisplayName format. + + This may be used to determine if a modification would require + backlinks to be updated, for example +*/ + +WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret) +{ + const char **attr_list = NULL; + struct dsdb_attribute *cur; + int i = 0; + for (cur = schema->attributes; cur; cur = cur->next) { + if (cur->linkID == 0) continue; + + attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2); + if (!attr_list) { + return WERR_NOMEM; + } + attr_list[i] = cur->lDAPDisplayName; + i++; + } + attr_list[i] = NULL; + *attr_list_ret = attr_list; + return WERR_OK; +} + +char **merge_attr_list(TALLOC_CTX *mem_ctx, + char **attrs, const char **new_attrs) +{ + char **ret_attrs; + int i; + size_t new_len, orig_len = str_list_length((const char **)attrs); + if (!new_attrs) { + return attrs; + } + + ret_attrs = talloc_realloc(mem_ctx, + attrs, char *, orig_len + str_list_length(new_attrs) + 1); + if (ret_attrs) { + for (i=0; i < str_list_length(new_attrs); i++) { + ret_attrs[orig_len + i] = new_attrs[i]; + } + new_len = orig_len + str_list_length(new_attrs); + + ret_attrs[new_len] = NULL; + } + + return ret_attrs; +} + +/* + Return a merged list of the attributes of exactly one class (not + considering subclasses, auxillary classes etc) +*/ + +char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *class, enum dsdb_attr_list_query query) +{ + char **attr_list = NULL; + switch (query) { + case DSDB_SCHEMA_ALL_MAY: + attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain); + attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain); + break; + + case DSDB_SCHEMA_ALL_MUST: + attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain); + attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain); + break; + + case DSDB_SCHEMA_SYS_MAY: + attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain); + break; + + case DSDB_SCHEMA_SYS_MUST: + attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain); + break; + + case DSDB_SCHEMA_MAY: + attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain); + break; + + case DSDB_SCHEMA_MUST: + attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain); + break; + + case DSDB_SCHEMA_ALL: + attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain); + attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain); + attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain); + attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain); + break; + } + return attr_list; +} + +static char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, + const struct dsdb_schema *schema, + const char **class_list, + enum dsdb_attr_list_query query) +{ + int i; + const struct dsdb_class *class; + + char **attr_list = NULL; + char **this_class_list; + char **recursive_list; + + for (i=0; class_list && class_list[i]; i++) { + class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]); + + this_class_list = dsdb_attribute_list(mem_ctx, class, query); + attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)this_class_list); + + recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, + class->systemAuxiliaryClass, + query); + + attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list); + + recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, + class->auxiliaryClass, + query); + + attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list); + + } + return attr_list; +} + +char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx, + const struct dsdb_schema *schema, + const char **class_list, + enum dsdb_attr_list_query query) +{ + char **attr_list = dsdb_full_attribute_list_internal(mem_ctx, schema, class_list, query); + size_t new_len = str_list_length((const char **)attr_list); + + /* Remove duplicates */ + if (new_len > 1) { + int i; + qsort(attr_list, new_len, + sizeof(*attr_list), + (comparison_fn_t)strcasecmp); + + for (i=1 ; i < new_len; i++) { + char **val1 = &attr_list[i-1]; + char **val2 = &attr_list[i]; + if (ldb_attr_cmp(*val1, *val2) == 0) { + memmove(val1, val2, (new_len - i) * sizeof( *attr_list)); + new_len--; + i--; + } + } + } + return attr_list; +} diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c new file mode 100644 index 0000000000..431ea3da65 --- /dev/null +++ b/source4/dsdb/schema/schema_set.c @@ -0,0 +1,254 @@ +/* + Unix SMB/CIFS mplementation. + DSDB schema header + + Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 "dsdb/samdb/samdb.h" +#include "lib/ldb/include/ldb_errors.h" +#include "lib/util/dlinklist.h" +#include "param/param.h" + +/** + * Attach the schema to an opaque pointer on the ldb, so ldb modules + * can find it + */ + +int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema) +{ + int ret; + + ret = ldb_set_opaque(ldb, "dsdb_schema", schema); + if (ret != LDB_SUCCESS) { + return ret; + } + + talloc_steal(ldb, schema); + + return LDB_SUCCESS; +} + +/** + * Global variable to hold one copy of the schema, used to avoid memory bloat + */ +static struct dsdb_schema *global_schema; + +/** + * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process + */ +int dsdb_set_global_schema(struct ldb_context *ldb) +{ + int ret; + if (!global_schema) { + return LDB_SUCCESS; + } + ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* Keep a reference to this schema, just incase the global copy is replaced */ + if (talloc_reference(ldb, global_schema) == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} + +/** + * Find the schema object for this ldb + */ + +struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb) +{ + const void *p; + struct dsdb_schema *schema; + + /* see if we have a cached copy */ + p = ldb_get_opaque(ldb, "dsdb_schema"); + if (!p) { + return NULL; + } + + schema = talloc_get_type(p, struct dsdb_schema); + if (!schema) { + return NULL; + } + + return schema; +} + +/** + * Make the schema found on this ldb the 'global' schema + */ + +void dsdb_make_schema_global(struct ldb_context *ldb) +{ + struct dsdb_schema *schema = dsdb_get_schema(ldb); + if (!schema) { + return; + } + + if (global_schema) { + talloc_unlink(talloc_autofree_context(), schema); + } + + talloc_steal(talloc_autofree_context(), schema); + global_schema = schema; + + dsdb_set_global_schema(ldb); +} + + +/** + * Rather than read a schema from the LDB itself, read it from an ldif + * file. This allows schema to be loaded and used while adding the + * schema itself to the directory. + */ + +WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df) +{ + struct ldb_ldif *ldif; + struct ldb_message *msg; + TALLOC_CTX *mem_ctx; + WERROR status; + int ret; + struct dsdb_schema *schema; + const struct ldb_val *prefix_val; + const struct ldb_val *info_val; + struct ldb_val info_val_default; + + mem_ctx = talloc_new(ldb); + if (!mem_ctx) { + goto nomem; + } + + schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm"))); + + schema->fsmo.we_are_master = true; + schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER"); + if (!schema->fsmo.master_dn) { + goto nomem; + } + + /* + * load the prefixMap attribute from pf + */ + ldif = ldb_ldif_read_string(ldb, &pf); + if (!ldif) { + status = WERR_INVALID_PARAM; + goto failed; + } + talloc_steal(mem_ctx, ldif); + + msg = ldb_msg_canonicalize(ldb, ldif->msg); + if (!msg) { + goto nomem; + } + talloc_steal(mem_ctx, msg); + talloc_free(ldif); + + prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap"); + if (!prefix_val) { + status = WERR_INVALID_PARAM; + goto failed; + } + + info_val = ldb_msg_find_ldb_val(msg, "schemaInfo"); + if (!info_val) { + info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000"); + if (!info_val_default.data) { + goto nomem; + } + talloc_steal(mem_ctx, info_val_default.data); + info_val = &info_val_default; + } + + status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val); + if (!W_ERROR_IS_OK(status)) { + goto failed; + } + + /* + * load the attribute and class definitions outof df + */ + while ((ldif = ldb_ldif_read_string(ldb, &df))) { + bool is_sa; + bool is_sc; + + talloc_steal(mem_ctx, ldif); + + msg = ldb_msg_canonicalize(ldb, ldif->msg); + if (!msg) { + goto nomem; + } + + talloc_steal(mem_ctx, msg); + talloc_free(ldif); + + is_sa = ldb_msg_check_string_attribute(msg, "objectClass", "attributeSchema"); + is_sc = ldb_msg_check_string_attribute(msg, "objectClass", "classSchema"); + + if (is_sa) { + struct dsdb_attribute *sa; + + sa = talloc_zero(schema, struct dsdb_attribute); + if (!sa) { + goto nomem; + } + + status = dsdb_attribute_from_ldb(schema, msg, sa, sa); + if (!W_ERROR_IS_OK(status)) { + goto failed; + } + + DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *); + } else if (is_sc) { + struct dsdb_class *sc; + + sc = talloc_zero(schema, struct dsdb_class); + if (!sc) { + goto nomem; + } + + status = dsdb_class_from_ldb(schema, msg, sc, sc); + if (!W_ERROR_IS_OK(status)) { + goto failed; + } + + DLIST_ADD_END(schema->classes, sc, struct dsdb_class *); + } + } + + ret = dsdb_set_schema(ldb, schema); + if (ret != LDB_SUCCESS) { + status = WERR_FOOBAR; + goto failed; + } + + goto done; + +nomem: + status = WERR_NOMEM; +failed: +done: + talloc_free(mem_ctx); + return status; +} |