diff options
Diffstat (limited to 'source4/dsdb')
20 files changed, 1470 insertions, 781 deletions
diff --git a/source4/dsdb/common/flags.h b/source4/dsdb/common/flags.h index e8802fdf9c..bdd61a363c 100644 --- a/source4/dsdb/common/flags.h +++ b/source4/dsdb/common/flags.h @@ -119,6 +119,17 @@ #define SYSTEM_FLAG_CONFIG_ALLOW_RENAME 0x40000000 #define SYSTEM_FLAG_DISALLOW_DELTE 0x80000000 +#define SEARCH_FLAG_ATTINDEX 0x0000001 +#define SEARCH_FLAG_PDNTATTINDEX 0x0000002 +#define SEARCH_FLAG_ANR 0x0000004 +#define SEARCH_FLAG_PRESERVEONDELETE 0x0000008 +#define SEARCH_FLAG_COPY 0x0000010 +#define SEARCH_FLAG_TUPLEINDEX 0x0000020 +#define SEARCH_FLAG_SUBTREEATTRINDEX 0x0000040 +#define SEARCH_FLAG_CONFIDENTIAL 0x0000080 +#define SEARCH_FLAG_NEVERVALUEAUDIT 0x0000100 +#define SEARCH_FLAG_RODC_ATTRIBUTE 0x0000200 + #define DS_BEHAVIOR_WIN2000 0 #define DS_BEHAVIOR_WIN2003_INTERIM 1 #define DS_BEHAVIOR_WIN2003 2 diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index 7b700fda22..63e8a77ce4 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -34,8 +34,10 @@ PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \ schema_init.o \ + schema_set.o \ + schema_query.o \ schema_syntax.o \ - schema_constructed.o) + schema_description.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/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c index 3629a3b92b..80b398ef5c 100644 --- a/source4/dsdb/repl/drepl_out_helpers.c +++ b/source4/dsdb/repl/drepl_out_helpers.c @@ -314,27 +314,35 @@ static void dreplsrv_op_pull_source_get_changes_recv(struct rpc_request *req) if (*r->out.level == 1) { ctr_level = 1; ctr1 = &r->out.ctr.ctr1; - } else if (*r->out.level == 2) { + } else if (*r->out.level == 2 && + r->out.ctr.ctr2.mszip1.ts) { ctr_level = 1; - ctr1 = r->out.ctr.ctr2.mszip1.ctr1; + ctr1 = &r->out.ctr.ctr2.mszip1.ts->ctr1; } else if (*r->out.level == 6) { ctr_level = 6; ctr6 = &r->out.ctr.ctr6; } else if (*r->out.level == 7 && r->out.ctr.ctr7.level == 6 && - r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) { + r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP && + r->out.ctr.ctr7.ctr.mszip6.ts) { ctr_level = 6; - ctr6 = r->out.ctr.ctr7.ctr.mszip6.ctr6; + ctr6 = &r->out.ctr.ctr7.ctr.mszip6.ts->ctr6; } else if (*r->out.level == 7 && r->out.ctr.ctr7.level == 6 && - r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS) { + r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS && + r->out.ctr.ctr7.ctr.xpress6.ts) { ctr_level = 6; - ctr6 = r->out.ctr.ctr7.ctr.xpress6.ctr6; + ctr6 = &r->out.ctr.ctr7.ctr.xpress6.ts->ctr6; } else { composite_error(c, werror_to_ntstatus(WERR_BAD_NET_RESP)); return; } + if (!ctr1 && !ctr6) { + composite_error(c, werror_to_ntstatus(WERR_BAD_NET_RESP)); + return; + } + if (ctr_level == 6) { if (!W_ERROR_IS_OK(ctr6->drs_error)) { composite_error(c, werror_to_ntstatus(ctr6->drs_error)); diff --git a/source4/dsdb/samdb/ldb_modules/anr.c b/source4/dsdb/samdb/ldb_modules/anr.c index 1252c9ee42..4e2c527fe9 100644 --- a/source4/dsdb/samdb/ldb_modules/anr.c +++ b/source4/dsdb/samdb/ldb_modules/anr.c @@ -146,7 +146,7 @@ struct ldb_parse_tree *anr_replace_callback(TALLOC_CTX *mem_ctx, op = LDB_OP_SUBSTRING; } for (cur = schema->attributes; cur; cur = cur->next) { - if (!(cur->searchFlags & 0x4)) continue; + if (!(cur->searchFlags & SEARCH_FLAG_ANR)) continue; match_tree = make_match_tree(module, mem_ctx, op, cur->lDAPDisplayName, match); if (tree) { @@ -224,30 +224,26 @@ struct ldb_parse_tree *anr_replace_subtrees(struct ldb_parse_tree *tree, void *context) { int i; + struct ldb_parse_tree *tmp; + switch (tree->operation) { case LDB_OP_AND: case LDB_OP_OR: for (i=0;i<tree->u.list.num_elements;i++) { - tree->u.list.elements[i] = anr_replace_subtrees(tree->u.list.elements[i], - attr, callback, context); - if (!tree->u.list.elements[i]) { - return NULL; - } + tmp = anr_replace_subtrees(tree->u.list.elements[i], + attr, callback, context); + if (tmp) tree->u.list.elements[i] = tmp; } break; case LDB_OP_NOT: - tree->u.isnot.child = anr_replace_subtrees(tree->u.isnot.child, attr, callback, context); - if (!tree->u.isnot.child) { - return NULL; - } + tmp = anr_replace_subtrees(tree->u.isnot.child, attr, callback, context); + if (tmp) tree->u.isnot.child = tmp; break; case LDB_OP_EQUALITY: if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) { - tree = callback(tree, &tree->u.equality.value, + tmp = callback(tree, &tree->u.equality.value, context); - if (!tree) { - return NULL; - } + if (tmp) tree = tmp; } break; case LDB_OP_SUBSTRING: @@ -256,10 +252,8 @@ struct ldb_parse_tree *anr_replace_subtrees(struct ldb_parse_tree *tree, tree->u.substring.end_with_wildcard == 1 && tree->u.substring.chunks[0] != NULL && tree->u.substring.chunks[1] == NULL) { - tree = callback(tree, tree->u.substring.chunks[0], context); - if (!tree) { - return NULL; - } + tmp = callback(tree, tree->u.substring.chunks[0], context); + if (tmp) tree = tmp; } } break; @@ -280,17 +274,29 @@ static int anr_search(struct ldb_module *module, struct ldb_request *req) context->module = module; context->found_anr = false; +#if 0 + printf("oldanr : %s\n", ldb_filter_from_tree (0, req->op.search.tree)); +#endif + /* Yes, this is a problem with req->op.search.tree being const... */ anr_tree = anr_replace_subtrees(req->op.search.tree, "anr", anr_replace_callback, context); if (!anr_tree) { + talloc_free(context); return LDB_ERR_OPERATIONS_ERROR; } if (context->found_anr) { /* The above function modifies the tree if it finds "anr", so no * point just setting this on the down_req */ +#if 0 + printf("newtree: %s\n", ldb_filter_from_tree (0, anr_tree)); +#endif req->op.search.tree = talloc_steal(req, anr_tree); - + } else { + if (anr_tree != req->op.search.tree) { + talloc_free(anr_tree); + } + talloc_free(context); } return ldb_next_request(module, req); } diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 04b9987071..e64472432d 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -160,7 +160,7 @@ static int setup_modifies(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } - new_msg->dn = ldb_dn_new(new_msg, ldb, (char *)el->values[j].data); + new_msg->dn = ldb_dn_from_ldb_val(new_msg, ldb, &el->values[j]); if (!new_msg->dn) { ldb_asprintf_errstring(ldb, "attribute %s value %s was not a valid DN", msg->elements[i].name, @@ -330,7 +330,7 @@ static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb /* Add all the existing elements, marking as 'proposed for delete' by setting .add = false */ for (i=0; i < search_el->num_values; i++) { merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1); - merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)search_el->values[i].data); + merged_list[size].dn = ldb_dn_from_ldb_val(merged_list, ldb, &search_el->values[i]); merged_list[size].add = false; merged_list[size].ignore = false; size++; @@ -339,7 +339,7 @@ static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb /* Add all the new replacement elements, marking as 'proposed for add' by setting .add = true */ for (i=0; i < ac2->el->num_values; i++) { merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1); - merged_list[size].dn = ldb_dn_new(merged_list, ldb, (char *)ac2->el->values[i].data); + merged_list[size].dn = ldb_dn_from_ldb_val(merged_list, ldb, &ac2->el->values[i]); merged_list[size].add = true; merged_list[size].ignore = false; size++; @@ -610,7 +610,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } - new_msg->dn = ldb_dn_new(new_msg, module->ldb, (char *)el->values[j].data); + new_msg->dn = ldb_dn_from_ldb_val(new_msg, module->ldb, &el->values[j]); if (!new_msg->dn) { ldb_asprintf_errstring(module->ldb, "attribute %s value %s was not a valid DN", req->op.mod.message->elements[i].name, diff --git a/source4/dsdb/samdb/ldb_modules/normalise.c b/source4/dsdb/samdb/ldb_modules/normalise.c index 8de9e33002..3306fd3c33 100644 --- a/source4/dsdb/samdb/ldb_modules/normalise.c +++ b/source4/dsdb/samdb/ldb_modules/normalise.c @@ -112,7 +112,7 @@ static int normalise_search_callback(struct ldb_context *ldb, void *context, str } for (j = 0; j < ares->message->elements[i].num_values; j++) { const char *dn_str; - struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, (const char *)ares->message->elements[i].values[j].data); + struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, ldb, &ares->message->elements[i].values[j]); if (!dn) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index 9285d6d0d8..9cae6ab7b5 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -925,7 +925,7 @@ static int partition_init(struct ldb_module *module) } for (i=0; i < replicate_attributes->num_values; i++) { - data->replicate[i] = ldb_dn_new(data->replicate, module->ldb, (const char *)replicate_attributes->values[i].data); + data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, module->ldb, &replicate_attributes->values[i]); if (!ldb_dn_validate(data->replicate[i])) { ldb_asprintf_errstring(module->ldb, "partition_init: " diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 88590f306b..bd491bd011 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -768,6 +768,10 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_message_element *el, *el2; int ret; unsigned int group_type, user_account_control, account_type; + if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */ + return ldb_next_request(module, req); + } + if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) { ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified"); return LDB_ERR_UNWILLING_TO_PERFORM; diff --git a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c index 87ada855d3..968b19c038 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c @@ -32,6 +32,40 @@ #include "lib/util/dlinklist.h" #include "param/param.h" +static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); +static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); +static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); + +static const struct { + const char *attr; + int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *); +} generated_attrs[] = { + { + .attr = "objectClasses", + .fn = generate_objectClasses + }, + { + .attr = "attributeTypes", + .fn = generate_attributeTypes + }, + { + .attr = "dITContentRules", + .fn = generate_dITContentRules + } +}; + +struct schema_fsmo_private_data { + struct ldb_dn *aggregate_dn; +}; + +struct schema_fsmo_search_data { + struct schema_fsmo_private_data *module_context; + struct ldb_request *orig_req; +}; + static int schema_fsmo_init(struct ldb_module *module) { TALLOC_CTX *mem_ctx; @@ -39,10 +73,7 @@ static int schema_fsmo_init(struct ldb_module *module) struct dsdb_schema *schema; char *error_string = NULL; int ret; - - if (dsdb_get_schema(module->ldb)) { - return ldb_next_init(module); - } + struct schema_fsmo_private_data *data; schema_dn = samdb_schema_dn(module->ldb); if (!schema_dn) { @@ -52,6 +83,25 @@ static int schema_fsmo_init(struct ldb_module *module) return ldb_next_init(module); } + data = talloc(module, struct schema_fsmo_private_data); + if (data == NULL) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Check to see if this is a result on the CN=Aggregate schema */ + data->aggregate_dn = ldb_dn_copy(data, schema_dn); + if (!ldb_dn_add_child_fmt(data->aggregate_dn, "CN=Aggregate")) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + module->private_data = data; + + if (dsdb_get_schema(module->ldb)) { + return ldb_next_init(module); + } + mem_ctx = talloc_new(module); if (!mem_ctx) { ldb_oom(module->ldb); @@ -75,6 +125,7 @@ static int schema_fsmo_init(struct ldb_module *module) "schema_fsmo_init: dsdb_schema load failed: %s", error_string); talloc_free(mem_ctx); + return ret; } /* dsdb_set_schema() steal schema into the ldb_context */ @@ -208,9 +259,155 @@ static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *r return LDB_SUCCESS; } +static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_class *class; + int ret; + + for (class = schema->classes; class; class = class->next) { + ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, class)); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; +} +static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_attribute *attribute; + int ret; + + for (attribute = schema->attributes; attribute; attribute = attribute->next) { + ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute)); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; +} + +static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_class *class; + int ret; + + for (class = schema->classes; class; class = class->next) { + if (class->auxiliaryClass || class->systemAuxiliaryClass) { + char *ditcontentrule = schema_class_to_dITContentRule(msg, class, schema); + if (!ditcontentrule) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + return 0; +} + + + +/* Add objectClasses, attributeTypes and dITContentRules from the + schema object (they are not stored in the database) + */ +static int schema_fsmo_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + const struct dsdb_schema *schema = dsdb_get_schema(ldb); + struct schema_fsmo_search_data *search_data = talloc_get_type(context, struct schema_fsmo_search_data); + struct ldb_request *orig_req = search_data->orig_req; + TALLOC_CTX *mem_ctx; + int i, ret; + + /* Only entries are interesting, and we handle the case of the parent seperatly */ + if (ares->type != LDB_REPLY_ENTRY) { + return orig_req->callback(ldb, orig_req->context, ares); + } + + if (ldb_dn_compare(ares->message->dn, search_data->module_context->aggregate_dn) != 0) { + talloc_free(mem_ctx); + return orig_req->callback(ldb, orig_req->context, ares); + } + + mem_ctx = talloc_new(ares); + if (!mem_ctx) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { + if (ldb_attr_in_list(orig_req->op.search.attrs, generated_attrs[i].attr)) { + ret = generated_attrs[i].fn(ldb, ares->message, schema); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + + talloc_free(mem_ctx); + return orig_req->callback(ldb, orig_req->context, ares); +} + +/* search */ +static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req) +{ + int i, ret; + struct schema_fsmo_search_data *search_context; + struct ldb_request *down_req; + struct dsdb_schema *schema = dsdb_get_schema(module->ldb); + + if (!schema || !module->private_data) { + /* If there is no schema, there is little we can do */ + return ldb_next_request(module, req); + } + for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { + if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) { + break; + } + } + if (i == ARRAY_SIZE(generated_attrs)) { + /* No request for a generated attr found, nothing to + * see here, move along... */ + return ldb_next_request(module, req); + } + + search_context = talloc(req, struct schema_fsmo_search_data); + if (!search_context) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + down_req = talloc(req, struct ldb_request); + if (!down_req) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + *down_req = *req; + search_context->orig_req = req; + search_context->module_context = talloc_get_type(module->private_data, struct schema_fsmo_private_data); + down_req->context = search_context; + + down_req->callback = schema_fsmo_search_callback; + + ret = ldb_next_request(module, down_req); + + /* do not free down_req as the call results may be linked to it, + * it will be freed when the upper level request get freed */ + if (ret == LDB_SUCCESS) { + req->handle = down_req->handle; + } + return ret; +} + + _PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = { .name = "schema_fsmo", .init_context = schema_fsmo_init, .add = schema_fsmo_add, - .extended = schema_fsmo_extended + .extended = schema_fsmo_extended, + .search = schema_fsmo_search }; diff --git a/source4/dsdb/samdb/ldb_modules/schema_syntax.c b/source4/dsdb/samdb/ldb_modules/schema_syntax.c index d800e4b6d2..ab9f32c913 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_syntax.c +++ b/source4/dsdb/samdb/ldb_modules/schema_syntax.c @@ -248,7 +248,7 @@ static int schema_validate_dn(struct ldb_context *ldb, struct ldb_val *val, int struct ldb_dn *dn; int ret = LDB_SUCCESS; - dn = ldb_dn_new(ldb, ldb, (const char *)val->data); + dn = ldb_dn_from_ldb_val(ldb, ldb, val); if ( ! ldb_dn_validate(dn)) { ret = LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; } diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c index 6e967aab2f..8f92995145 100644 --- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c +++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c @@ -154,7 +154,7 @@ static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC struct ldb_val out = data_blob(NULL, 0); const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, "objectCategory"); - dn = ldb_dn_new(ctx, module->ldb, val->data); + dn = ldb_dn_from_ldb_val(ctx, module->ldb, val); if (dn && ldb_dn_validate(dn)) { talloc_free(dn); return val_copy(module, ctx, val); diff --git a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py index 7c408d0436..428e6b4d4b 100644 --- a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py +++ b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py @@ -47,7 +47,7 @@ class MapBaseTestCase(TestCaseInTempDir): ldb.add({"dn": "@PARTITION", "partition": [s4.basedn + ":" + s4.url, s3.basedn + ":" + s3.url], - "replicateEntries": ["@SUBCLASSES", "@ATTRIBUTES", "@INDEXLIST"]}) + "replicateEntries": ["@ATTRIBUTES", "@INDEXLIST"]}) def setUp(self): super(MapBaseTestCase, self).setUp() diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 3e92671fa0..f24a75fd8f 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -31,6 +31,7 @@ struct event_context; #include "librpc/gen_ndr/security.h" #include "lib/ldb/include/ldb.h" +#include "lib/ldb-samba/ldif_handlers.h" #include "librpc/gen_ndr/samr.h" #include "librpc/gen_ndr/drsuapi.h" #include "librpc/gen_ndr/drsblobs.h" diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index a4e455ae33..68dc8197cb 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -32,6 +32,10 @@ struct dsdb_syntax { uint32_t oMSyntax; struct ldb_val oMObjectClass; const char *attributeSyntax_oid; + const char *equality; + const char *substring; + const char *comment; + const char *ldb_syntax; WERROR (*drsuapi_to_ldb)(const struct dsdb_schema *schema, const struct dsdb_attribute *attr, @@ -168,6 +172,12 @@ enum dsdb_attr_list_query { DSDB_SCHEMA_ALL }; +enum dsdb_schema_convert_target { + TARGET_OPENLDAP, + TARGET_FEDORA_DS, + TARGET_AD_SCHEMA_SUBENTRY +}; + #include "dsdb/schema/proto.h" #endif /* _DSDB_SCHEMA_H */ diff --git a/source4/dsdb/schema/schema_constructed.c b/source4/dsdb/schema/schema_constructed.c deleted file mode 100644 index 51343817b0..0000000000 --- a/source4/dsdb/schema/schema_constructed.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - Unix SMB/CIFS mplementation. - DSDB schema constructed attributes - attributeTypes, objectClasses, dITContentRules... - - Copyright (C) Stefan Metzmacher 2006 - - 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 "librpc/gen_ndr/ndr_drsuapi.h" -#include "lib/ldb/include/ldb.h" -#include "system/time.h" -#include "lib/charset/charset.h" -#include "librpc/ndr/libndr.h" - -static char *dsdb_subSchema_list_append(char *v, const char *list_name) -{ - bool first = true; - uint32_t i; - const char *attrs[] = { - "attr1", - "attr2", - "attr3", - NULL - }; - - v = talloc_asprintf_append(v, "%s ( ", list_name); - if (!v) return NULL; - - for (i=0; attrs[i]; i++) { - v = talloc_asprintf_append(v, "%s%s ", - (!first ? "$ " : ""), - attrs[i]); - if (!v) return NULL; - first = false; - } - - v = talloc_asprintf_append(v, ") "); - if (!v) return NULL; - - return v; -} - -WERROR dsdb_subSchema_attributeTypes(const struct dsdb_schema *schema, - TALLOC_CTX *mem_ctx) -{ - struct ldb_message_element *e; - struct dsdb_attribute *a; - - e = talloc_zero(mem_ctx, struct ldb_message_element); - W_ERROR_HAVE_NO_MEMORY(e); - - for (a = schema->attributes; a; a = a->next) { - char *v; - - v = talloc_asprintf(e, "( %s NAME '%s' SYNTAX '%s' ", - a->attributeID_oid, a->lDAPDisplayName, - a->syntax->ldap_oid); - W_ERROR_HAVE_NO_MEMORY(v); - - if (a->isSingleValued) { - v = talloc_asprintf_append(v, "SINGLE-VALUE "); - W_ERROR_HAVE_NO_MEMORY(v); - } - - if (a->systemOnly) { - v = talloc_asprintf_append(v, "NO-USER-MODIFICATION "); - W_ERROR_HAVE_NO_MEMORY(v); - } - - v = talloc_asprintf_append(v, ")"); - W_ERROR_HAVE_NO_MEMORY(v); - - DEBUG(0,("%s\n", v)); - } - - return WERR_FOOBAR; -} - -WERROR dsdb_subSchema_objectClasses(const struct dsdb_schema *schema, - TALLOC_CTX *mem_ctx) -{ - struct ldb_message_element *e; - struct dsdb_class *c; - - e = talloc_zero(mem_ctx, struct ldb_message_element); - W_ERROR_HAVE_NO_MEMORY(e); - - for (c = schema->classes; c; c = c->next) { - const char *class_type; - char *v; - - switch (c->objectClassCategory) { - case 0: - /* - * NOTE: this is an type 88 class - * e.g. 2.5.6.6 NAME 'person' - * but w2k3 gives STRUCTURAL here! - */ - class_type = "STRUCTURAL"; - break; - case 1: - class_type = "STRUCTURAL"; - break; - case 2: - class_type = "ABSTRACT"; - break; - case 3: - class_type = "AUXILIARY"; - break; - default: - class_type = "UNKNOWN"; - break; - } - - v = talloc_asprintf(e, "( %s NAME '%s' SUB %s %s ", - c->governsID_oid, c->lDAPDisplayName, - c->subClassOf, class_type); - W_ERROR_HAVE_NO_MEMORY(v); - - v = dsdb_subSchema_list_append(v, "MUST"); - W_ERROR_HAVE_NO_MEMORY(v); - - v = dsdb_subSchema_list_append(v, "MAY"); - W_ERROR_HAVE_NO_MEMORY(v); - - v = talloc_asprintf_append(v, ")"); - W_ERROR_HAVE_NO_MEMORY(v); - - DEBUG(0,("%s\n", v)); - } - - return WERR_FOOBAR; -} - -WERROR dsdb_subSchema_dITContentRules(const struct dsdb_schema *schema, - TALLOC_CTX *mem_ctx) -{ - struct ldb_message_element *e; - struct dsdb_class *c; - - e = talloc_zero(mem_ctx, struct ldb_message_element); - W_ERROR_HAVE_NO_MEMORY(e); - - for (c = schema->classes; c; c = c->next) { - char *v; - - /* - * TODO: filter out classes without auxiliary classes - */ - - v = talloc_asprintf(e, "( %s NAME '%s' ", - c->governsID_oid, c->lDAPDisplayName); - W_ERROR_HAVE_NO_MEMORY(v); - - v = dsdb_subSchema_list_append(v, "AUX"); - W_ERROR_HAVE_NO_MEMORY(v); - - v = dsdb_subSchema_list_append(v, "MUST"); - W_ERROR_HAVE_NO_MEMORY(v); - - v = dsdb_subSchema_list_append(v, "MAY"); - W_ERROR_HAVE_NO_MEMORY(v); - - v = talloc_asprintf_append(v, ")"); - W_ERROR_HAVE_NO_MEMORY(v); - - DEBUG(0,("%s\n", v)); - } - - return WERR_FOOBAR; -} diff --git a/source4/dsdb/schema/schema_description.c b/source4/dsdb/schema/schema_description.c new file mode 100644 index 0000000000..9d93af9260 --- /dev/null +++ b/source4/dsdb/schema/schema_description.c @@ -0,0 +1,316 @@ +/* + Unix SMB/CIFS mplementation. + Print schema info into string format + + 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 "dsdb/samdb/samdb.h" + +#define IF_NULL_FAIL_RET(x) do { \ + if (!x) { \ + return NULL; \ + } \ + } while (0) + + +char *schema_attribute_description(TALLOC_CTX *mem_ctx, + enum dsdb_schema_convert_target target, + const char *seperator, + const char *oid, + const char *name, + const char *description, + const char *equality, + const char *substring, + const char *syntax, + bool single_value, bool operational) +{ + char *schema_entry = talloc_asprintf(mem_ctx, + "(%s%s%s", seperator, oid, seperator); + + schema_entry = talloc_asprintf_append(schema_entry, + "NAME '%s'%s", name, seperator); + IF_NULL_FAIL_RET(schema_entry); + + if (description) { +#if 0 + /* Need a way to escape ' characters from the description */ + schema_entry = talloc_asprintf_append(schema_entry, + "DESC '%s'%s", description, seperator); + IF_NULL_FAIL_RET(schema_entry); +#endif + } + + if (equality) { + schema_entry = talloc_asprintf_append(schema_entry, + "EQUALITY %s%s", equality, seperator); + IF_NULL_FAIL_RET(schema_entry); + } + if (substring) { + schema_entry = talloc_asprintf_append(schema_entry, + "SUBSTR %s%s", substring, seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + schema_entry = talloc_asprintf_append(schema_entry, + "SYNTAX %s%s", syntax, seperator); + IF_NULL_FAIL_RET(schema_entry); + + if (single_value) { + schema_entry = talloc_asprintf_append(schema_entry, + "SINGLE-VALUE%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + if (operational) { + schema_entry = talloc_asprintf_append(schema_entry, + "NO-USER-MODIFICATION%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + schema_entry = talloc_asprintf_append(schema_entry, + ")"); + return schema_entry; +} + +char *schema_attribute_to_description(TALLOC_CTX *mem_ctx, const struct dsdb_attribute *attribute) +{ + char *schema_description; + const struct dsdb_syntax *map = find_syntax_map_by_ad_oid(attribute->attributeSyntax_oid); + const char *syntax = map ? map->ldap_oid : attribute->attributeSyntax_oid; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + return NULL; + } + + + schema_description + = schema_attribute_description(mem_ctx, + TARGET_AD_SCHEMA_SUBENTRY, + " ", + attribute->attributeID_oid, + attribute->lDAPDisplayName, + NULL, NULL, NULL, talloc_asprintf(tmp_ctx, "'%s'", syntax), + attribute->isSingleValued, + attribute->systemOnly); + talloc_free(tmp_ctx); + return schema_description; +} + +#define APPEND_ATTRS(attributes) \ + do { \ + int k; \ + for (k=0; attributes && attributes[k]; k++) { \ + const char *attr_name = attributes[k]; \ + \ + schema_entry = talloc_asprintf_append(schema_entry, \ + "%s ", \ + attr_name); \ + IF_NULL_FAIL_RET(schema_entry); \ + if (attributes[k+1]) { \ + IF_NULL_FAIL_RET(schema_entry); \ + if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \ + schema_entry = talloc_asprintf_append(schema_entry, \ + "$%s ", seperator); \ + IF_NULL_FAIL_RET(schema_entry); \ + } else { \ + schema_entry = talloc_asprintf_append(schema_entry, \ + "$ "); \ + } \ + } \ + } \ + } while (0) + + +/* Print a schema class or dITContentRule as a string. + * + * To print a scheam class, specify objectClassCategory but not auxillary_classes + * To print a dITContentRule, specify auxillary_classes but set objectClassCategory == -1 + * + */ + +char *schema_class_description(TALLOC_CTX *mem_ctx, + enum dsdb_schema_convert_target target, + const char *seperator, + const char *oid, + const char *name, + const char **auxillary_classes, + const char *description, + const char *subClassOf, + int objectClassCategory, + char **must, + char **may) +{ + char *schema_entry = talloc_asprintf(mem_ctx, + "(%s%s%s", seperator, oid, seperator); + + IF_NULL_FAIL_RET(schema_entry); + + schema_entry = talloc_asprintf_append(schema_entry, + "NAME '%s'%s", name, seperator); + IF_NULL_FAIL_RET(schema_entry); + + if (description) { + schema_entry = talloc_asprintf_append(schema_entry, + "DESC '%s'%s", description, seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + if (auxillary_classes) { + schema_entry = talloc_asprintf_append(schema_entry, + "AUX ( "); + IF_NULL_FAIL_RET(schema_entry); + + APPEND_ATTRS(auxillary_classes); + + schema_entry = talloc_asprintf_append(schema_entry, + ")%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + if (subClassOf) { + schema_entry = talloc_asprintf_append(schema_entry, + "SUP %s%s", subClassOf, seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + switch (objectClassCategory) { + case -1: + break; + /* Dummy case for when used for printing ditContentRules */ + case 0: + /* + * NOTE: this is an type 88 class + * e.g. 2.5.6.6 NAME 'person' + * but w2k3 gives STRUCTURAL here! + */ + schema_entry = talloc_asprintf_append(schema_entry, + "STRUCTURAL%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + break; + case 1: + schema_entry = talloc_asprintf_append(schema_entry, + "STRUCTURAL%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + break; + case 2: + schema_entry = talloc_asprintf_append(schema_entry, + "ABSTRACT%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + break; + case 3: + schema_entry = talloc_asprintf_append(schema_entry, + "AUXILIARY%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + break; + } + + if (must) { + schema_entry = talloc_asprintf_append(schema_entry, + "MUST ( "); + IF_NULL_FAIL_RET(schema_entry); + + APPEND_ATTRS(must); + + schema_entry = talloc_asprintf_append(schema_entry, + ")%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + if (may) { + schema_entry = talloc_asprintf_append(schema_entry, + "MAY ( "); + IF_NULL_FAIL_RET(schema_entry); + + APPEND_ATTRS(may); + + schema_entry = talloc_asprintf_append(schema_entry, + ")%s", seperator); + IF_NULL_FAIL_RET(schema_entry); + } + + schema_entry = talloc_asprintf_append(schema_entry, + ")"); + return schema_entry; +} + +char *schema_class_to_description(TALLOC_CTX *mem_ctx, const struct dsdb_class *class) +{ + char *schema_description; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + return NULL; + } + + schema_description + = schema_class_description(mem_ctx, + TARGET_AD_SCHEMA_SUBENTRY, + " ", + class->governsID_oid, + class->lDAPDisplayName, + NULL, + NULL, + class->subClassOf, + class->objectClassCategory, + dsdb_attribute_list(tmp_ctx, + class, DSDB_SCHEMA_ALL_MUST), + dsdb_attribute_list(tmp_ctx, + class, DSDB_SCHEMA_ALL_MAY)); + talloc_free(tmp_ctx); + return schema_description; +} +char *schema_class_to_dITContentRule(TALLOC_CTX *mem_ctx, const struct dsdb_class *class, + const struct dsdb_schema *schema) +{ + int i; + char *schema_description; + char **aux_class_list = NULL; + char **attrs; + char **must_attr_list = NULL; + char **may_attr_list = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + const struct dsdb_class *aux_class; + if (!tmp_ctx) { + return NULL; + } + + aux_class_list = merge_attr_list(tmp_ctx, aux_class_list, class->systemAuxiliaryClass); + aux_class_list = merge_attr_list(tmp_ctx, aux_class_list, class->auxiliaryClass); + + for (i=0; aux_class_list && aux_class_list[i]; i++) { + aux_class = dsdb_class_by_lDAPDisplayName(schema, aux_class_list[i]); + + attrs = dsdb_attribute_list(mem_ctx, aux_class, DSDB_SCHEMA_ALL_MUST); + must_attr_list = merge_attr_list(mem_ctx, must_attr_list, attrs); + + attrs = dsdb_attribute_list(mem_ctx, aux_class, DSDB_SCHEMA_ALL_MAY); + may_attr_list = merge_attr_list(mem_ctx, may_attr_list, attrs); + } + + schema_description + = schema_class_description(mem_ctx, + TARGET_AD_SCHEMA_SUBENTRY, + " ", + class->governsID_oid, + class->lDAPDisplayName, + (const char **)aux_class_list, + NULL, + class->subClassOf, + -1, must_attr_list, may_attr_list); + talloc_free(tmp_ctx); + return schema_description; +} diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 85fdbe9e87..3ed7daee59 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -809,7 +809,6 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, if (!prefix_val) { *error_string = talloc_asprintf(mem_ctx, "schema_fsmo_init: no prefixMap attribute found"); - talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo"); @@ -828,7 +827,6 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, *error_string = talloc_asprintf(mem_ctx, "schema_fsmo_init: failed to load oid mappings: %s", win_errstr(status)); - talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } @@ -847,7 +845,6 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, "schema_fsmo_init: failed to load attribute definition: %s:%s", ldb_dn_get_linearized(attrs_res->msgs[i]->dn), win_errstr(status)); - talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } @@ -869,7 +866,6 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, "schema_fsmo_init: failed to load class definition: %s:%s", ldb_dn_get_linearized(objectclass_res->msgs[i]->dn), win_errstr(status)); - talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } @@ -914,7 +910,6 @@ static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn, "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))", name, name); if (ret != LDB_SUCCESS) { - printf("Search failed: %s\n", ldb_errstring(ldb)); return ret; } @@ -940,7 +935,8 @@ static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn, static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn, TALLOC_CTX *mem_ctx, - struct ldb_result **objectclasses_res) + struct ldb_result **objectclasses_res, + char **error_string) { TALLOC_CTX *local_ctx = talloc_new(mem_ctx); struct ldb_result *top_res, *ret_res; @@ -949,19 +945,23 @@ static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *sche return LDB_ERR_OPERATIONS_ERROR; } - /* Downlaod 'top' */ + /* Download 'top' */ ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, "(&(objectClass=classSchema)(lDAPDisplayName=top))", NULL, &top_res); if (ret != LDB_SUCCESS) { - printf("Search failed: %s\n", ldb_errstring(ldb)); - return LDB_ERR_OPERATIONS_ERROR; + *error_string = talloc_asprintf(mem_ctx, + "dsdb_schema: failed to search for top classSchema object: %s", + ldb_errstring(ldb)); + return ret; } talloc_steal(local_ctx, top_res); if (top_res->count != 1) { - return LDB_ERR_OPERATIONS_ERROR; + *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); @@ -972,8 +972,7 @@ static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *sche ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res); if (ret != LDB_SUCCESS) { - printf("Search failed: %s\n", ldb_errstring(ldb)); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } *objectclasses_res = talloc_move(mem_ctx, &ret_res); @@ -1051,10 +1050,10 @@ 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); + ret = fetch_objectclass_schema(ldb, schema_dn, tmp_ctx, &c_res, &error_string); if (ret != LDB_SUCCESS) { *error_string_out = talloc_asprintf(mem_ctx, - "Failed to fetch objectClass schema elements: %s\n", ldb_errstring(ldb)); + "Failed to fetch objectClass schema elements: %s", error_string); talloc_free(tmp_ctx); return ret; } @@ -1410,535 +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; -} - -static 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; -} - -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 **recursive_list; - - for (i=0; class_list && class_list[i]; i++) { - class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]); - - 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; - } - - 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..0ca26c0fc7 --- /dev/null +++ b/source4/dsdb/schema/schema_set.c @@ -0,0 +1,434 @@ +/* + 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/ldb/include/ldb_private.h" +#include "lib/util/dlinklist.h" +#include "param/param.h" + + +static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes) +{ + int ret = LDB_SUCCESS; + struct ldb_result *res; + struct ldb_result *res_idx; + struct dsdb_attribute *attr; + struct ldb_message *mod_msg; + TALLOC_CTX *mem_ctx = talloc_new(ldb); + + struct ldb_message *msg; + struct ldb_message *msg_idx; + + if (!mem_ctx) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg = ldb_msg_new(mem_ctx); + if (!msg) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + msg_idx = ldb_msg_new(mem_ctx); + if (!msg_idx) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES"); + if (!msg->dn) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + msg_idx->dn = ldb_dn_new(msg, ldb, "@INDEXLIST"); + if (!msg_idx->dn) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (attr = schema->attributes; attr; attr = attr->next) { + const struct ldb_schema_syntax *s; + const char *syntax = attr->syntax->ldb_syntax; + if (!syntax) { + syntax = attr->syntax->ldap_oid; + } + + /* Write out a rough approximation of the schema as an @ATTRIBUTES value, for bootstrapping */ + if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) { + ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER"); + } else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) { + ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE"); + } + if (ret != LDB_SUCCESS) { + return ret; + } + + if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) { + ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + if (!attr->syntax) { + continue; + } + + ret = ldb_schema_attribute_add(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED, + syntax); + if (ret != LDB_SUCCESS) { + s = ldb_samba_syntax_by_name(ldb, attr->syntax->ldap_oid); + if (s) { + ret = ldb_schema_attribute_add_with_syntax(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED, s); + } else { + ret = LDB_SUCCESS; /* Nothing to do here */ + } + } + + if (ret != LDB_SUCCESS) { + return ret; + } + } + + if (!write_attributes) { + talloc_free(mem_ctx); + return ret; + } + + + ret = ldb_transaction_start(ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* Try to avoid churning the attributes too much - we only want to do this if they have changed */ + ret = ldb_search_exp_fmt(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg->dn)); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ret = ldb_add(ldb, msg); + } else if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + ldb_transaction_cancel(ldb); + return ret; + } else { + + if (res->count != 1) { + talloc_free(mem_ctx); + ldb_transaction_cancel(ldb); + return LDB_ERR_NO_SUCH_OBJECT; + } + + ret = LDB_SUCCESS; + /* Annoyingly added to our search results */ + ldb_msg_remove_attr(res->msgs[0], "distinguishedName"); + + mod_msg = ldb_msg_diff(ldb, res->msgs[0], msg); + if (mod_msg->num_elements > 0) { + ret = ldb_modify(ldb, mod_msg); + } + } + + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + /* We might be on a read-only DB */ + talloc_free(mem_ctx); + ret = ldb_transaction_cancel(ldb); + return ret; + } else if (ret != LDB_SUCCESS) { + ldb_transaction_cancel(ldb); + return ret; + } + + /* Now write out the indexs, as found in the schema (if they have changed) */ + + ret = ldb_search_exp_fmt(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg_idx->dn)); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ret = ldb_add(ldb, msg_idx); + } else if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + ldb_transaction_cancel(ldb); + return ret; + } else { + if (res_idx->count != 1) { + talloc_free(mem_ctx); + ldb_transaction_cancel(ldb); + return LDB_ERR_NO_SUCH_OBJECT; + } + + /* Annoyingly added to our search results */ + ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName"); + + mod_msg = ldb_msg_diff(ldb, res_idx->msgs[0], msg_idx); + if (mod_msg->num_elements > 0) { + ret = ldb_modify(ldb, mod_msg); + } + } + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + /* We might be on a read-only DB */ + talloc_free(mem_ctx); + return ldb_transaction_cancel(ldb); + } else if (ret == LDB_SUCCESS) { + ret = ldb_transaction_commit(ldb); + } else { + ldb_transaction_cancel(ldb); + } + talloc_free(mem_ctx); + return ret; +} + + +/** + * 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; + } + + /* Set the new attributes based on the new schema */ + ret = dsdb_schema_set_attributes(ldb, schema, true); + 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; + } + + /* Set the new attributes based on the new schema */ + ret = dsdb_schema_set_attributes(ldb, global_schema, false); + 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_syntax.c b/source4/dsdb/schema/schema_syntax.c index beacfc49c2..97cd0020a9 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -3,7 +3,9 @@ DSDB schema syntaxes Copyright (C) Stefan Metzmacher <metze@samba.org> 2006 - + Copyright (C) Simo Sorce 2005 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 @@ -1109,7 +1111,6 @@ static WERROR dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi(const struct dsdb_ return WERR_OK; } - #define OMOBJECTCLASS(val) { .length = sizeof(val) - 1, .data = discard_const_p(uint8_t, val) } static const struct dsdb_syntax dsdb_syntaxes[] = { @@ -1120,27 +1121,36 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.8", .drsuapi_to_ldb = dsdb_syntax_BOOL_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_BOOL_ldb_to_drsuapi, + .equality = "booleanMatch", + .comment = "Boolean" },{ .name = "Integer", - .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.27", + .ldap_oid = LDB_SYNTAX_INTEGER, .oMSyntax = 2, .attributeSyntax_oid = "2.5.5.9", .drsuapi_to_ldb = dsdb_syntax_INT32_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_INT32_ldb_to_drsuapi, + .equality = "integerMatch", + .comment = "Integer", },{ .name = "String(Octet)", - .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.40", + .ldap_oid = LDB_SYNTAX_OCTET_STRING, .oMSyntax = 4, .attributeSyntax_oid = "2.5.5.10", .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi, + .equality = "octetStringMatch", + .comment = "Octet String", },{ .name = "String(Sid)", - .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.40", + .ldap_oid = LDB_SYNTAX_OCTET_STRING, .oMSyntax = 4, .attributeSyntax_oid = "2.5.5.17", .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi, + .equality = "octetStringMatch", + .comment = "Octet String - Security Identifier (SID)", + .ldb_syntax = LDB_SYNTAX_SAMBA_SID },{ .name = "String(Object-Identifier)", .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.38", @@ -1148,9 +1158,12 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.2", .drsuapi_to_ldb = dsdb_syntax_OID_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_OID_ldb_to_drsuapi, + .equality = "caseIgnoreMatch", /* Would use "objectIdentifierMatch" but most are ldap attribute/class names */ + .comment = "OID String", + .ldb_syntax = LDB_SYNTAX_DIRECTORY_STRING },{ .name = "Enumeration", - .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.27", + .ldap_oid = LDB_SYNTAX_INTEGER, .oMSyntax = 10, .attributeSyntax_oid = "2.5.5.9", .drsuapi_to_ldb = dsdb_syntax_INT32_drsuapi_to_ldb, @@ -1163,6 +1176,9 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.6", .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi, + .equality = "numericStringMatch", + .substring = "numericStringSubstringsMatch", + .comment = "Numeric String" },{ .name = "String(Printable)", .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.44", @@ -1177,6 +1193,10 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.4", .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi, + .equality = "caseIgnoreMatch", + .substring = "caseIgnoreSubstringsMatch", + .comment = "Case Insensitive String", + .ldb_syntax = LDB_SYNTAX_DIRECTORY_STRING, },{ .name = "String(IA5)", .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.26", @@ -1184,6 +1204,8 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.5", .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi, + .equality = "caseExactIA5Match", + .comment = "Printable String" },{ .name = "String(UTC-Time)", .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.53", @@ -1191,6 +1213,8 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.11", .drsuapi_to_ldb = dsdb_syntax_NTTIME_UTC_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_NTTIME_UTC_ldb_to_drsuapi, + .equality = "generalizedTimeMatch", + .comment = "UTC Time", },{ .name = "String(Generalized-Time)", .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.24", @@ -1198,6 +1222,9 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.11", .drsuapi_to_ldb = dsdb_syntax_NTTIME_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_NTTIME_ldb_to_drsuapi, + .equality = "generalizedTimeMatch", + .comment = "Generalized Time", + .ldb_syntax = LDB_SYNTAX_UTC_TIME, },{ /* not used in w2k3 schema */ .name = "String(Case Sensitive)", @@ -1208,11 +1235,14 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .ldb_to_drsuapi = dsdb_syntax_FOOBAR_ldb_to_drsuapi, },{ .name = "String(Unicode)", - .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.15", + .ldap_oid = LDB_SYNTAX_DIRECTORY_STRING, .oMSyntax = 64, .attributeSyntax_oid = "2.5.5.12", .drsuapi_to_ldb = dsdb_syntax_UNICODE_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_UNICODE_ldb_to_drsuapi, + .equality = "caseIgnoreMatch", + .substring = "caseIgnoreSubstringsMatch", + .comment = "Directory String", },{ .name = "Interval/LargeInteger", .ldap_oid = "1.2.840.113556.1.4.906", @@ -1220,21 +1250,26 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.16", .drsuapi_to_ldb = dsdb_syntax_INT64_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_INT64_ldb_to_drsuapi, + .equality = "integerMatch", + .comment = "Large Integer", + .ldb_syntax = LDB_SYNTAX_INTEGER, },{ .name = "String(NT-Sec-Desc)", - .ldap_oid = "1.2.840.113556.1.4.907", + .ldap_oid = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR, .oMSyntax = 66, .attributeSyntax_oid = "2.5.5.15", .drsuapi_to_ldb = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi, },{ .name = "Object(DS-DN)", - .ldap_oid = "1.3.6.1.4.1.1466.115.121.1.12", + .ldap_oid = LDB_SYNTAX_DN, .oMSyntax = 127, .oMObjectClass = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x4a"), .attributeSyntax_oid = "2.5.5.1", .drsuapi_to_ldb = dsdb_syntax_DN_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DN_ldb_to_drsuapi, + .equality = "distinguishedNameMatch", + .comment = "Object(DS-DN) == a DN", },{ .name = "Object(DN-Binary)", .ldap_oid = "1.2.840.113556.1.4.903", @@ -1243,6 +1278,9 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.7", .drsuapi_to_ldb = dsdb_syntax_DN_BINARY_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_DN_BINARY_ldb_to_drsuapi, + .equality = "distinguishedNameMatch", + .comment = "OctetString: Binary+DN", + .ldb_syntax = LDB_SYNTAX_DN, },{ /* not used in w2k3 schema */ .name = "Object(OR-Name)", @@ -1274,6 +1312,7 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.13", .drsuapi_to_ldb = dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi, + .comment = "Presentation Address" },{ /* not used in w2k3 schema */ .name = "Object(Access-Point)", @@ -1283,6 +1322,9 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.14", .drsuapi_to_ldb = dsdb_syntax_FOOBAR_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_FOOBAR_ldb_to_drsuapi, + .equality = "distinguishedNameMatch", + .comment = "OctetString: String+DN", + .ldb_syntax = LDB_SYNTAX_DN, },{ /* not used in w2k3 schema */ .name = "Object(DN-String)", @@ -1292,9 +1334,42 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .attributeSyntax_oid = "2.5.5.14", .drsuapi_to_ldb = dsdb_syntax_FOOBAR_drsuapi_to_ldb, .ldb_to_drsuapi = dsdb_syntax_FOOBAR_ldb_to_drsuapi, + .ldb_syntax = LDB_SYNTAX_DN, } }; +const struct dsdb_syntax *find_syntax_map_by_ad_oid(const char *ad_oid) +{ + int i; + for (i=0; dsdb_syntaxes[i].ldap_oid; i++) { + if (strcasecmp(ad_oid, dsdb_syntaxes[i].attributeSyntax_oid) == 0) { + return &dsdb_syntaxes[i]; + } + } + return NULL; +} + +const struct dsdb_syntax *find_syntax_map_by_ad_syntax(int oMSyntax) +{ + int i; + for (i=0; dsdb_syntaxes[i].ldap_oid; i++) { + if (oMSyntax == dsdb_syntaxes[i].oMSyntax) { + return &dsdb_syntaxes[i]; + } + } + return NULL; +} + +const struct dsdb_syntax *find_syntax_map_by_standard_oid(const char *standard_oid) +{ + int i; + for (i=0; dsdb_syntaxes[i].ldap_oid; i++) { + if (strcasecmp(standard_oid, dsdb_syntaxes[i].ldap_oid) == 0) { + return &dsdb_syntaxes[i]; + } + } + return NULL; +} const struct dsdb_syntax *dsdb_syntax_for_attribute(const struct dsdb_attribute *attr) { uint32_t i; |