diff options
39 files changed, 1186 insertions, 721 deletions
diff --git a/source4/cldap_server/netlogon.c b/source4/cldap_server/netlogon.c index f263f33d48..d4242061f4 100644 --- a/source4/cldap_server/netlogon.c +++ b/source4/cldap_server/netlogon.c @@ -71,6 +71,7 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, struct ldb_dn *partitions_basedn; struct interface *ifaces; bool user_known; + NTSTATUS status; partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx); @@ -87,7 +88,7 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, partitions_basedn, LDB_SCOPE_ONELEVEL, ref_attrs, "(&(&(objectClass=crossRef)(dnsRoot=%s))(nETBIOSName=*))", - domain); + ldb_binary_encode_string(mem_ctx, domain)); if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find referece to '%s' in sam: %s\n", @@ -126,7 +127,7 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, partitions_basedn, LDB_SCOPE_ONELEVEL, ref_attrs, "(&(objectClass=crossRef)(ncName=*)(nETBIOSName=%s))", - netbios_domain); + ldb_binary_encode_string(mem_ctx, netbios_domain)); if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find referece to '%s' in sam: %s\n", @@ -161,17 +162,45 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, ref_res = NULL; if (domain_guid) { + struct GUID binary_guid; + struct ldb_val guid_val; + enum ndr_err_code ndr_err; + + /* By this means, we ensure we don't have funny stuff in the GUID */ + + status = GUID_from_string(domain_guid, &binary_guid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* And this gets the result into the binary format we want anyway */ + ndr_err = ndr_push_struct_blob(&guid_val, mem_ctx, NULL, &binary_guid, + (ndr_push_flags_fn_t)ndr_push_GUID); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return NT_STATUS_INVALID_PARAMETER; + } ret = ldb_search_exp_fmt(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, - "(&(objectClass=domainDNS)(objectGUID=%s))", - domain_guid); + "(&(objectCategory=Domain-DNS)(objectGUID=%s))", + ldb_binary_encode(mem_ctx, guid_val)); } else { /* domain_sid case */ + struct dom_sid *sid; + struct ldb_val sid_val; + enum ndr_err_code ndr_err; + + /* Rather than go via the string, just push into the NDR form */ + ndr_err = ndr_push_struct_blob(&sid_val, mem_ctx, NULL, &sid, + (ndr_push_flags_fn_t)ndr_push_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return NT_STATUS_INVALID_PARAMETER; + } + ret = ldb_search_exp_fmt(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, - "(&(objectClass=domainDNS)(objectSID=%s))", - dom_sid_string(mem_ctx, domain_sid)); + "(&(objectCategory=Domain-DNS)(objectSID=%s))", + ldb_binary_encode(mem_ctx, sid_val)); } if (ret != LDB_SUCCESS) { @@ -237,7 +266,8 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, "(&(objectClass=user)(samAccountName=%s)" "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))" "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", - user, UF_ACCOUNTDISABLE, samdb_acb2uf(acct_control)); + ldb_binary_encode_string(mem_ctx, user), + UF_ACCOUNTDISABLE, samdb_acb2uf(acct_control)); if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find referece to user '%s' with ACB 0x%8x under %s: %s\n", user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn), @@ -256,7 +286,8 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, server_type = NBT_SERVER_DS | NBT_SERVER_TIMESERV | NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE | - NBT_SERVER_GOOD_TIMESERV; + NBT_SERVER_GOOD_TIMESERV | NBT_SERVER_DS_DNS_CONTR | + NBT_SERVER_DS_DNS_DOMAIN; if (samdb_is_pdc(sam_ctx)) { server_type |= NBT_SERVER_PDC; @@ -274,6 +305,10 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, server_type |= NBT_SERVER_KDC; } + if (!ldb_dn_compare_base(ldb_get_root_basedn(sam_ctx), ldb_get_default_basedn(sam_ctx))) { + server_type |= NBT_SERVER_DS_DNS_FOREST; + } + pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name(lp_ctx)); domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); realm = samdb_result_string(ref_res->msgs[0], "dnsRoot", lp_realm(lp_ctx)); @@ -285,6 +320,7 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, flatname = samdb_result_string(ref_res->msgs[0], "nETBIOSName", lp_workgroup(lp_ctx)); + /* FIXME: Hardcoded site names */ server_site = "Default-First-Site-Name"; client_site = "Default-First-Site-Name"; load_interfaces(mem_ctx, lp_interfaces(lp_ctx), &ifaces); 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 ae35078537..63e8a77ce4 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -34,6 +34,8 @@ 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_description.o) 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_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/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..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/lib/charset/charset.h b/source4/lib/charset/charset.h index baa7df532b..c49745cd7f 100644 --- a/source4/lib/charset/charset.h +++ b/source4/lib/charset/charset.h @@ -97,6 +97,7 @@ size_t count_chars_w(const char *s, char c); void strupper_m(char *s); void strlower_m(char *s); char *strupper_talloc(TALLOC_CTX *ctx, const char *src); +char *strupper_talloc_n(TALLOC_CTX *ctx, const char *src, size_t n); char *strlower_talloc(TALLOC_CTX *ctx, const char *src); bool strhasupper(const char *string); bool strhaslower(const char *string); diff --git a/source4/lib/charset/util_unistr.c b/source4/lib/charset/util_unistr.c index 19a4f3236c..09ec7b0471 100644 --- a/source4/lib/charset/util_unistr.c +++ b/source4/lib/charset/util_unistr.c @@ -518,8 +518,9 @@ _PUBLIC_ char *strlower_talloc(TALLOC_CTX *ctx, const char *src) /** Convert a string to UPPER case, allocated with talloc + source length limited to n bytes **/ -_PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src) +_PUBLIC_ char *strupper_talloc_n(TALLOC_CTX *ctx, const char *src, size_t n) { size_t size=0; char *dest; @@ -531,12 +532,12 @@ _PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src) /* this takes advantage of the fact that upper/lower can't change the length of a character by more than 1 byte */ - dest = talloc_array(ctx, char, 2*(strlen(src))+1); + dest = talloc_array(ctx, char, 2*(n+1)); if (dest == NULL) { return NULL; } - while (*src) { + while (*src && n--) { size_t c_size; codepoint_t c = next_codepoint(iconv_convenience, src, &c_size); src += c_size; @@ -562,6 +563,16 @@ _PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src) } /** + Convert a string to UPPER case, allocated with talloc +**/ +_PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src) +{ + return strupper_talloc_n(ctx, src, src?strlen(src):0); +} + + + +/** Convert a string to lower case. **/ _PUBLIC_ void strlower_m(char *s) diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c index 22a57da10b..a16582d294 100644 --- a/source4/lib/ldb-samba/ldif_handlers.c +++ b/source4/lib/ldb-samba/ldif_handlers.c @@ -38,7 +38,7 @@ static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx, { enum ndr_err_code ndr_err; struct dom_sid *sid; - sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data); + sid = dom_sid_parse_length(mem_ctx, in); if (sid == NULL) { return -1; } @@ -70,12 +70,11 @@ static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx, talloc_free(sid); return -1; } - out->data = (uint8_t *)dom_sid_string(mem_ctx, sid); + *out = data_blob_string_const(dom_sid_string(mem_ctx, sid)); talloc_free(sid); if (out->data == NULL) { return -1; } - out->length = strlen((const char *)out->data); return 0; } @@ -97,13 +96,14 @@ static int ldb_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *v1, const struct ldb_val *v2) { if (ldb_comparision_objectSid_isString(v1) && ldb_comparision_objectSid_isString(v2)) { - return strcmp((const char *)v1->data, (const char *)v2->data); + return ldb_comparison_binary(ldb, mem_ctx, v1, v2); } else if (ldb_comparision_objectSid_isString(v1) && !ldb_comparision_objectSid_isString(v2)) { struct ldb_val v; int ret; if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) { - return -1; + /* Perhaps not a string after all */ + return ldb_comparison_binary(ldb, mem_ctx, v1, v2); } ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2); talloc_free(v.data); @@ -113,7 +113,8 @@ static int ldb_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx, struct ldb_val v; int ret; if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) { - return -1; + /* Perhaps not a string after all */ + return ldb_comparison_binary(ldb, mem_ctx, v1, v2); } ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v); talloc_free(v.data); @@ -129,7 +130,11 @@ static int ldb_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { if (ldb_comparision_objectSid_isString(in)) { - return ldif_read_objectSid(ldb, mem_ctx, in, out); + if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) { + /* Perhaps not a string after all */ + return ldb_handler_copy(ldb, mem_ctx, in, out); + } + return 0; } return ldb_handler_copy(ldb, mem_ctx, in, out); } @@ -141,10 +146,16 @@ static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { struct GUID guid; + char *guid_string; NTSTATUS status; enum ndr_err_code ndr_err; + guid_string = talloc_strndup(mem_ctx, (const char *)in->data, in->length); + if (!guid_string) { + return -1; + } - status = GUID_from_string((const char *)in->data, &guid); + status = GUID_from_string(guid_string, &guid); + talloc_free(guid_string); if (!NT_STATUS_IS_OK(status)) { return -1; } @@ -203,13 +214,14 @@ static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *v1, const struct ldb_val *v2) { if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) { - return strcmp((const char *)v1->data, (const char *)v2->data); + return ldb_comparison_binary(ldb, mem_ctx, v1, v2); } else if (ldb_comparision_objectGUID_isString(v1) && !ldb_comparision_objectGUID_isString(v2)) { struct ldb_val v; int ret; if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) { - return -1; + /* Perhaps it wasn't a valid string after all */ + return ldb_comparison_binary(ldb, mem_ctx, v1, v2); } ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2); talloc_free(v.data); @@ -219,7 +231,8 @@ static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx, struct ldb_val v; int ret; if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) { - return -1; + /* Perhaps it wasn't a valid string after all */ + return ldb_comparison_binary(ldb, mem_ctx, v1, v2); } ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v); talloc_free(v.data); @@ -235,7 +248,11 @@ static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { if (ldb_comparision_objectGUID_isString(in)) { - return ldif_read_objectGUID(ldb, mem_ctx, in, out); + if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) { + /* Perhaps it wasn't a valid string after all */ + return ldb_handler_copy(ldb, mem_ctx, in, out); + } + return 0; } return ldb_handler_copy(ldb, mem_ctx, in, out); } @@ -314,7 +331,7 @@ static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_c } return LDB_SUCCESS; } - dn1 = ldb_dn_new(tmp_ctx, ldb, (char *)in->data); + dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in); if ( ! ldb_dn_validate(dn1)) { const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length); class = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName); @@ -617,19 +634,6 @@ static const struct { { "fRSReplicaSetGUID", LDB_SYNTAX_SAMBA_GUID }, { "netbootGUID", LDB_SYNTAX_SAMBA_GUID }, { "objectCategory", LDB_SYNTAX_SAMBA_OBJECT_CATEGORY }, - { "member", LDB_SYNTAX_DN }, - { "memberOf", LDB_SYNTAX_DN }, - { "nCName", LDB_SYNTAX_DN }, - { "schemaNamingContext", LDB_SYNTAX_DN }, - { "configurationNamingContext", LDB_SYNTAX_DN }, - { "rootDomainNamingContext", LDB_SYNTAX_DN }, - { "defaultNamingContext", LDB_SYNTAX_DN }, - { "subRefs", LDB_SYNTAX_DN }, - { "dMDLocation", LDB_SYNTAX_DN }, - { "serverReference", LDB_SYNTAX_DN }, - { "masteredBy", LDB_SYNTAX_DN }, - { "msDs-masteredBy", LDB_SYNTAX_DN }, - { "fSMORoleOwner", LDB_SYNTAX_DN }, { "prefixMap", LDB_SYNTAX_SAMBA_PREFIX_MAP } }; @@ -669,7 +673,7 @@ int ldb_register_samba_handlers(struct ldb_context *ldb) return -1; } - ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, 0, s); + ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s); if (ret != LDB_SUCCESS) { return ret; } diff --git a/source4/lib/ldb/common/attrib_handlers.c b/source4/lib/ldb/common/attrib_handlers.c index 8ed2763d4d..fb57e2dadc 100644 --- a/source4/lib/ldb/common/attrib_handlers.c +++ b/source4/lib/ldb/common/attrib_handlers.c @@ -55,11 +55,12 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, { char *s, *t; int l; + if (!in || !out || !(in->data)) { return -1; } - out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data)); + out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length); if (out->data == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data); return -1; @@ -153,13 +154,14 @@ int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *v1, const struct ldb_val *v2) { const char *s1=(const char *)v1->data, *s2=(const char *)v2->data; + size_t n1 = v1->length, n2 = v2->length; const char *u1, *u2; char *b1, *b2; int ret; - while (*s1 == ' ') s1++; - while (*s2 == ' ') s2++; + while (*s1 == ' ' && n1) { s1++; n1--; }; + while (*s2 == ' ' && n2) { s2++; n2--; }; /* TODO: make utf8 safe, possibly with helper function from application */ - while (*s1 && *s2) { + while (*s1 && *s2 && n1 && n2) { /* the first 127 (0x7F) chars are ascii and utf8 guarantes they * never appear in multibyte sequences */ if (((unsigned char)s1[0]) & 0x80) goto utf8str; @@ -167,10 +169,11 @@ int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2)) break; if (*s1 == ' ') { - while (s1[0] == s1[1]) s1++; - while (s2[0] == s2[1]) s2++; + while (s1[0] == s1[1] && n1) { s1++; n1--; } + while (s2[0] == s2[1] && n2) { s2++; n2--; } } s1++; s2++; + n1--; n2--; } if (! (*s1 && *s2)) { /* check for trailing spaces only if one of the pointers @@ -178,15 +181,18 @@ int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, * can mistakenly match. * ex. "domain users" <-> "domainUpdates" */ - while (*s1 == ' ') s1++; - while (*s2 == ' ') s2++; + while (*s1 == ' ') { s1++; n1--; } + while (*s2 == ' ') { s2++; n2--; } + } + if (n1 != n2) { + return n1 - n2; } return (int)(toupper(*s1)) - (int)(toupper(*s2)); utf8str: /* no need to recheck from the start, just from the first utf8 char found */ - b1 = ldb_casefold(ldb, mem_ctx, s1); - b2 = ldb_casefold(ldb, mem_ctx, s2); + b1 = ldb_casefold(ldb, mem_ctx, s1, n1); + b2 = ldb_casefold(ldb, mem_ctx, s2, n2); if (b1 && b2) { /* Both strings converted correctly */ @@ -221,6 +227,7 @@ utf8str: return ret; } + /* canonicalise a attribute in DN format */ diff --git a/source4/lib/ldb/common/ldb_attributes.c b/source4/lib/ldb/common/ldb_attributes.c index 3b9d01682c..747f241781 100644 --- a/source4/lib/ldb/common/ldb_attributes.c +++ b/source4/lib/ldb/common/ldb_attributes.c @@ -51,6 +51,10 @@ int ldb_schema_attribute_add_with_syntax(struct ldb_context *ldb, int i, n; struct ldb_schema_attribute *a; + if (!syntax) { + return LDB_ERR_OPERATIONS_ERROR; + } + n = ldb->schema.num_attributes + 1; a = talloc_realloc(ldb, ldb->schema.attributes, diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c index 08911344b7..c0d36cfbf3 100644 --- a/source4/lib/ldb/common/ldb_dn.c +++ b/source4/lib/ldb/common/ldb_dn.c @@ -71,7 +71,7 @@ struct ldb_dn { }; /* strdn may be NULL */ -struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *strdn) +struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx, struct ldb_context *ldb, const struct ldb_val *strdn) { struct ldb_dn *dn; @@ -82,27 +82,27 @@ struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *st dn->ldb = ldb; - if (strdn) { - if (strdn[0] == '@') { + if (strdn->data && strdn->length) { + if (strdn->data[0] == '@') { dn->special = true; } - if (strncasecmp(strdn, "<GUID=", 6) == 0) { + if (strdn->length >= 6 && strncasecmp((const char *)strdn->data, "<GUID=", 6) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a GUID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "<SID=", 8) == 0) { + } else if (strdn->length >= 8 && strncasecmp((const char *)strdn->data, "<SID=", 8) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a SID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "<WKGUID=", 8) == 0) { + } else if (strdn->length >= 8 && strncasecmp((const char *)strdn->data, "<WKGUID=", 8) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a WKGUID string to ldb_dn structure */ } - dn->linearized = talloc_strdup(dn, strdn); + dn->linearized = talloc_strndup(dn, (const char *)strdn->data, strdn->length); } else { dn->linearized = talloc_strdup(dn, ""); } @@ -115,6 +115,15 @@ failed: return NULL; } +/* strdn may be NULL */ +struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *strdn) +{ + struct ldb_val blob; + blob.data = strdn; + blob.length = strdn ? strlen(strdn) : 0; + return ldb_dn_from_ldb_val(mem_ctx, ldb, &blob); +} + struct ldb_dn *ldb_dn_new_fmt(void *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...) { struct ldb_dn *dn; diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c index c1ea9db56b..2f5fe1d18c 100644 --- a/source4/lib/ldb/common/ldb_msg.c +++ b/source4/lib/ldb/common/ldb_msg.c @@ -389,10 +389,10 @@ int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, if (!v || !v->data) { return default_value; } - if (strcasecmp((const char *)v->data, "FALSE") == 0) { + if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) { return 0; } - if (strcasecmp((const char *)v->data, "TRUE") == 0) { + if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) { return 1; } return default_value; @@ -421,7 +421,7 @@ struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb, if (!v || !v->data) { return NULL; } - res_dn = ldb_dn_new(mem_ctx, ldb, (const char *)v->data); + res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v); if ( ! ldb_dn_validate(res_dn)) { talloc_free(res_dn); return NULL; diff --git a/source4/lib/ldb/common/ldb_utf8.c b/source4/lib/ldb/common/ldb_utf8.c index b7b4a60122..69ee2b6964 100644 --- a/source4/lib/ldb/common/ldb_utf8.c +++ b/source4/lib/ldb/common/ldb_utf8.c @@ -40,8 +40,8 @@ function to handle utf8 caseless comparisons */ void ldb_set_utf8_fns(struct ldb_context *ldb, - void *context, - char *(*casefold)(void *, void *, const char *)) + void *context, + char *(*casefold)(void *, void *, const char *, size_t)) { if (context) ldb->utf8_fns.context = context; @@ -53,10 +53,10 @@ void ldb_set_utf8_fns(struct ldb_context *ldb, a simple case folding function NOTE: does not handle UTF8 */ -char *ldb_casefold_default(void *context, void *mem_ctx, const char *s) +char *ldb_casefold_default(void *context, void *mem_ctx, const char *s, size_t n) { int i; - char *ret = talloc_strdup(mem_ctx, s); + char *ret = talloc_strndup(mem_ctx, s, n); if (!s) { errno = ENOMEM; return NULL; @@ -72,9 +72,9 @@ void ldb_set_utf8_default(struct ldb_context *ldb) ldb_set_utf8_fns(ldb, NULL, ldb_casefold_default); } -char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s) +char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s, size_t n) { - return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s); + return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s, n); } /* diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 7ce6103422..937029f52c 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -203,7 +203,7 @@ struct ldb_debug_ops { */ struct ldb_utf8_fns { void *context; - char *(*casefold)(void *context, TALLOC_CTX *mem_ctx, const char *s); + char *(*casefold)(void *context, TALLOC_CTX *mem_ctx, const char *s, size_t n); }; /** @@ -1216,7 +1216,7 @@ void ldb_set_utf8_default(struct ldb_context *ldb); \note The default function is not yet UTF8 aware. Provide your own set of functions through ldb_set_utf8_fns() */ -char *ldb_casefold(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *s); +char *ldb_casefold(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *s, size_t n); /** Check the attribute name is valid according to rfc2251 @@ -1381,6 +1381,7 @@ int ldb_base64_decode(char *s); struct ldb_dn *ldb_dn_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *dn); struct ldb_dn *ldb_dn_new_fmt(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...) PRINTF_ATTRIBUTE(3,4); +struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx, struct ldb_context *ldb, const struct ldb_val *strdn); bool ldb_dn_validate(struct ldb_dn *dn); char *ldb_dn_escape_value(TALLOC_CTX *mem_ctx, struct ldb_val value); @@ -1602,8 +1603,8 @@ int ldb_set_debug(struct ldb_context *ldb, this allows the user to set custom utf8 function for error reporting */ void ldb_set_utf8_fns(struct ldb_context *ldb, - void *context, - char *(*casefold)(void *, void *, const char *)); + void *context, + char *(*casefold)(void *, void *, const char *, size_t n)); /** this sets up debug to print messages on stderr diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h index d7c2efe8a1..e1026ab781 100644 --- a/source4/lib/ldb/include/ldb_private.h +++ b/source4/lib/ldb/include/ldb_private.h @@ -91,13 +91,6 @@ struct ldb_schema { /* attribute handling table */ unsigned num_attributes; struct ldb_schema_attribute *attributes; - - /* objectclass information */ - unsigned num_classes; - struct ldb_subclass { - char *name; - char **subclasses; - } *classes; }; /* @@ -242,7 +235,7 @@ int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct l int check_critical_controls(struct ldb_control **controls); /* The following definitions come from lib/ldb/common/ldb_utf8.c */ -char *ldb_casefold_default(void *context, void *mem_ctx, const char *s); +char *ldb_casefold_default(void *context, void *mem_ctx, const char *s, size_t n); void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el); diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c index 1b6d9feed6..269305a468 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_index.c +++ b/source4/lib/ldb/ldb_tdb/ldb_index.c @@ -767,7 +767,7 @@ int ltdb_search_indexed(struct ldb_handle *handle) if ((ac->scope == LDB_SCOPE_ONELEVEL && (idxattr+idxone == 0)) || (ac->scope == LDB_SCOPE_SUBTREE && idxattr == 0)) { - /* no indexs? must do full search */ + /* no indexes? must do full search */ return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source4/lib/ldb/modules/operational.c b/source4/lib/ldb/modules/operational.c index 7dc4ae08c3..a59e81becd 100644 --- a/source4/lib/ldb/modules/operational.c +++ b/source4/lib/ldb/modules/operational.c @@ -291,12 +291,6 @@ static int operational_init(struct ldb_module *ctx) { int ret = 0; - /* setup some standard attribute handlers */ - ret |= ldb_schema_attribute_add(ctx->ldb, "whenCreated", 0, LDB_SYNTAX_UTC_TIME); - ret |= ldb_schema_attribute_add(ctx->ldb, "whenChanged", 0, LDB_SYNTAX_UTC_TIME); - ret |= ldb_schema_attribute_add(ctx->ldb, "subschemaSubentry", 0, LDB_SYNTAX_DN); - ret |= ldb_schema_attribute_add(ctx->ldb, "structuralObjectClass", 0, LDB_SYNTAX_OBJECTCLASS); - if (ret != 0) { return ret; } diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 13d4adf6d4..11a824a549 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -331,15 +331,15 @@ servicePrincipalName: host/ldaptest2computer29 print "Testing Ambigious Name Resolution" # Testing ldb.search for (&(anr=ldap testy)(objectClass=user)) res = ldb.search(expression="(&(anr=ldap testy)(objectClass=user))") - self.assertEquals(len(res), 3, "Could not find (&(anr=ldap testy)(objectClass=user))") + self.assertEquals(len(res), 3, "Found only %d of 3 for (&(anr=ldap testy)(objectClass=user))" % len(res)) # Testing ldb.search for (&(anr=testy ldap)(objectClass=user)) res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))") - self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res)) + self.assertEquals(len(res), 2, "Found only %d of 2 for (&(anr=testy ldap)(objectClass=user))" % len(res)) # Testing ldb.search for (&(anr=ldap)(objectClass=user)) res = ldb.search(expression="(&(anr=ldap)(objectClass=user))") - self.assertEquals(len(res), 4, "Found only %d for (&(anr=ldap)(objectClass=user))" % len(res)) + self.assertEquals(len(res), 4, "Found only %d of 4 for (&(anr=ldap)(objectClass=user))" % len(res)) # Testing ldb.search for (&(anr==ldap)(objectClass=user)) res = ldb.search(expression="(&(anr==ldap)(objectClass=user))") @@ -353,13 +353,13 @@ servicePrincipalName: host/ldaptest2computer29 res = ldb.search(expression="(&(anr=testy)(objectClass=user))") self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy)(objectClass=user))" % len(res)) - # Testing ldb.search for (&(anr=ldap testy)(objectClass=user)) + # Testing ldb.search for (&(anr=testy ldap)(objectClass=user)) res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))") - self.assertEquals(len(res), 2, "Found only %d for (&(anr=ldap testy)(objectClass=user))" % len(res)) + self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res)) - # Testing ldb.search for (&(anr==ldap testy)(objectClass=user)) + # Testing ldb.search for (&(anr==testy ldap)(objectClass=user)) res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))") - self.assertEquals(len(res), 1, "Found only %d for (&(anr==ldap testy)(objectClass=user))" % len(res)) + self.assertEquals(len(res), 1, "Found only %d for (&(anr==testy ldap)(objectClass=user))" % len(res)) self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn)) self.assertEquals(res[0]["cn"][0], "ldaptestuser") diff --git a/source4/lib/ldb/tools/ldbtest.c b/source4/lib/ldb/tools/ldbtest.c index 6d141478ad..169ff02da1 100644 --- a/source4/lib/ldb/tools/ldbtest.c +++ b/source4/lib/ldb/tools/ldbtest.c @@ -93,7 +93,7 @@ static void add_records(struct ldb_context *ldb, el[2].name = talloc_strdup(tmp_ctx, "uid"); el[2].num_values = 1; el[2].values = vals[2]; - vals[2][0].data = (uint8_t *)ldb_casefold(ldb, tmp_ctx, name); + vals[2][0].data = (uint8_t *)ldb_casefold(ldb, tmp_ctx, name, strlen(name)); vals[2][0].length = strlen((char *)vals[2][0].data); el[3].flags = 0; diff --git a/source4/lib/ldb_wrap.c b/source4/lib/ldb_wrap.c index 883597108a..6c683a1e33 100644 --- a/source4/lib/ldb_wrap.c +++ b/source4/lib/ldb_wrap.c @@ -147,17 +147,21 @@ struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx, talloc_free(ldb); return NULL; } - - if (lp_ctx != NULL && strcmp(lp_sam_url(lp_ctx), url) == 0) { - dsdb_set_global_schema(ldb); - } + /* This must be done before we load the schema, as these + * handlers for objectSid and objectGUID etc must take + * precedence over the 'binary attribute' declaration in the + * schema */ ret = ldb_register_samba_handlers(ldb); if (ret == -1) { talloc_free(ldb); return NULL; } + if (lp_ctx != NULL && strcmp(lp_sam_url(lp_ctx), url) == 0) { + dsdb_set_global_schema(ldb); + } + ldb_set_debug(ldb, ldb_wrap_debug, NULL); ldb_set_utf8_fns(ldb, NULL, wrap_casefold); diff --git a/source4/lib/ldb_wrap.h b/source4/lib/ldb_wrap.h index e626b6ef8a..f2982302ab 100644 --- a/source4/lib/ldb_wrap.h +++ b/source4/lib/ldb_wrap.h @@ -29,7 +29,7 @@ struct cli_credentials; struct loadparm_context; struct event_context; -char *wrap_casefold(void *context, void *mem_ctx, const char *s); +char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n); struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, diff --git a/source4/lib/util/data_blob.c b/source4/lib/util/data_blob.c index b258e47bba..57b34b7ae7 100644 --- a/source4/lib/util/data_blob.c +++ b/source4/lib/util/data_blob.c @@ -176,7 +176,7 @@ _PUBLIC_ DATA_BLOB data_blob_string_const(const char *str) { DATA_BLOB blob; blob.data = discard_const_p(uint8_t, str); - blob.length = strlen(str); + blob.length = str ? strlen(str) : 0; return blob; } diff --git a/source4/lib/util/util_ldb.c b/source4/lib/util/util_ldb.c index 0a7433696e..fab729c036 100644 --- a/source4/lib/util/util_ldb.c +++ b/source4/lib/util/util_ldb.c @@ -125,9 +125,9 @@ int gendb_add_ldif(struct ldb_context *ldb, const char *ldif_string) return ret; } -char *wrap_casefold(void *context, void *mem_ctx, const char *s) +char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n) { - return strupper_talloc(mem_ctx, s); + return strupper_talloc_n(mem_ctx, s, n); } diff --git a/source4/lib/util/util_ldb.h b/source4/lib/util/util_ldb.h index 030ba7ebee..43f98ae1a9 100644 --- a/source4/lib/util/util_ldb.h +++ b/source4/lib/util/util_ldb.h @@ -22,6 +22,6 @@ int gendb_search_dn(struct ldb_context *ldb, struct ldb_message ***res, const char * const *attrs); int gendb_add_ldif(struct ldb_context *ldb, const char *ldif_string); -char *wrap_casefold(void *context, void *mem_ctx, const char *s); +char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n); #endif /* __LIB_UTIL_UTIL_LDB_H__ */ diff --git a/source4/libcli/security/dom_sid.c b/source4/libcli/security/dom_sid.c index f5457e7e0e..1a7519e362 100644 --- a/source4/libcli/security/dom_sid.c +++ b/source4/libcli/security/dom_sid.c @@ -152,6 +152,21 @@ struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr) } /* + convert a string to a dom_sid, returning a talloc'd dom_sid +*/ +struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid) +{ + struct dom_sid *ret; + char *p = talloc_strndup(mem_ctx, sid->data, sid->length); + if (!p) { + return NULL; + } + ret = dom_sid_parse_talloc(mem_ctx, p); + talloc_free(p); + return ret; +} + +/* copy a dom_sid structure */ struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid) diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl index a6d0245455..63be489e0d 100644 --- a/source4/librpc/idl/nbt.idl +++ b/source4/librpc/idl/nbt.idl @@ -353,7 +353,13 @@ interface nbt NBT_SERVER_TIMESERV = 0x00000040, NBT_SERVER_CLOSEST = 0x00000080, NBT_SERVER_WRITABLE = 0x00000100, - NBT_SERVER_GOOD_TIMESERV = 0x00000200 + NBT_SERVER_GOOD_TIMESERV = 0x00000200, + NBT_SERVER_NDNC = 0x00000400, + NBT_SERVER_SEL_SEC_DOM_6 = 0x00000800, + NBT_SERVER_FUL_SEC_DOM_6 = 0x00001000, + NBT_SERVER_DS_DNS_CONTR = 0x04000000, + NBT_SERVER_DS_DNS_DOMAIN = 0x02000000, + NBT_SERVER_DS_DNS_FOREST = 0x01000000 } nbt_server_type; typedef [bitmap32bit,public] bitmap { diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0855efe3bb..9c2a208460 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -745,12 +745,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) - if fill == FILL_DRS: - # We want to finish here, but setup the index before we do so - message("Setting up sam.ldb index") - samdb.load_ldif_file_add(setup_path("provision_index.ldif")) - return samdb - message("Pre-loading the Samba 4 and AD schema") samdb.set_domain_sid(domainsid) if serverrole == "domain controller": @@ -886,9 +880,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, domainsid=domainsid, policyguid=policyguid, setup_path=setup_path) - #We want to setup the index last, as adds are faster unindexed - message("Setting up sam.ldb index") - samdb.load_ldif_file_add(setup_path("provision_index.ldif")) except: samdb.transaction_cancel() raise @@ -1281,39 +1272,38 @@ def provision_backend(setup_dir=None, message=None, mmr_syncrepl_user_config = "" if ol_mmr_urls is not None: - mmr_hosts=filter(None,ol_mmr_urls.split(' ')) - if (len(mmr_hosts) == 1): - mmr_hosts=filter(None,ol_mmr_urls.split(',')) + url_list=filter(None,ol_mmr_urls.split(' ')) + if (len(url_list) == 1): + url_list=filter(None,ol_mmr_urls.split(',')) mmr_on_config = "MirrorMode On" - - z=0 - for i in mmr_hosts: - z=z+1 + serverid=0 + for url in url_list: + serverid=serverid+1 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"), - { "SERVERID" : str(z), - "LDAPSERVER" : i }) - - z=z+1 + { "SERVERID" : str(serverid), + "LDAPSERVER" : url }) + rid=serverid*10 + rid=rid+1 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), - { "RID" : str(z), + { "RID" : str(rid), "MMRDN": names.schemadn, - "LDAPSERVER" : i, + "LDAPSERVER" : url, "MMR_PASSWORD": adminpass}) - z=z+1 + rid=rid+1 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), - { "RID" : str(z), + { "RID" : str(rid), "MMRDN": names.configdn, - "LDAPSERVER" : i, + "LDAPSERVER" : url, "MMR_PASSWORD": adminpass}) - z=z+1 + rid=rid+1 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), - { "RID" : str(z), + { "RID" : str(rid), "MMRDN": names.domaindn, - "LDAPSERVER" : i, + "LDAPSERVER" : url, "MMR_PASSWORD": adminpass }) diff --git a/source4/setup/provision-backend b/source4/setup/provision-backend index 049b8752a6..0943da29b6 100755 --- a/source4/setup/provision-backend +++ b/source4/setup/provision-backend @@ -65,7 +65,7 @@ parser.add_option("--server-role", type="choice", metavar="ROLE", parser.add_option("--targetdir", type="string", metavar="DIR", help="Set target directory") parser.add_option("--ol-mmr-urls", type="string", metavar="LDAPSERVER", - help="List of LDAP-URLS separated with whitespaces for Use with OpenLDAP-MMR") + help="List of LDAP-URLS [ ldap://<FQDN>:port/ (where port != 389) ] separated with whitespaces for use with OpenLDAP-MMR") opts = parser.parse_args()[0] diff --git a/source4/setup/provision_index.ldif b/source4/setup/provision_index.ldif deleted file mode 100644 index 95970817f3..0000000000 --- a/source4/setup/provision_index.ldif +++ /dev/null @@ -1,19 +0,0 @@ -dn: @INDEXLIST -@IDXATTR: name -@IDXATTR: cn -@IDXATTR: userPrincipalName -@IDXATTR: servicePrincipalName -@IDXATTR: sAMAccountName -@IDXATTR: objectSid -@IDXATTR: objectCategory -@IDXATTR: member -@IDXATTR: uidNumber -@IDXATTR: gidNumber -@IDXATTR: unixName -@IDXATTR: privilege -@IDXATTR: nCName -@IDXATTR: lDAPDisplayName -@IDXATTR: subClassOf -@IDXATTR: dnsRoot -@IDXATTR: nETBIOSName -@IDXATTR: objectGUID diff --git a/source4/setup/provision_init.ldif b/source4/setup/provision_init.ldif index 65a12f1afa..a6c591dd51 100644 --- a/source4/setup/provision_init.ldif +++ b/source4/setup/provision_init.ldif @@ -1,3 +1,8 @@ +#These attributes are only used as far as the bootstrapping of the +# schema. After that, the attributes from the schema are used. +# +# Therefore, they must strictly match the schema + dn: @ATTRIBUTES userPrincipalName: CASE_INSENSITIVE servicePrincipalName: CASE_INSENSITIVE @@ -7,6 +12,8 @@ nETBIOSName: CASE_INSENSITIVE cn: CASE_INSENSITIVE dc: CASE_INSENSITIVE name: CASE_INSENSITIVE +lDAPDisplayName: CASE_INSENSITIVE +subClassOf: CASE_INSENSITIVE dn: CASE_INSENSITIVE sAMAccountName: CASE_INSENSITIVE objectClass: CASE_INSENSITIVE diff --git a/source4/torture/ldap/cldap.c b/source4/torture/ldap/cldap.c index 1631297793..3730193c86 100644 --- a/source4/torture/ldap/cldap.c +++ b/source4/torture/ldap/cldap.c @@ -228,6 +228,75 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest) } /* + test cldap netlogon server type flags +*/ +static bool test_cldap_netlogon_flags(struct torture_context *tctx, + const char *dest) +{ + struct cldap_socket *cldap; + NTSTATUS status; + struct cldap_netlogon search; + struct netlogon_samlogon_response n1; + uint32_t server_type; + + cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx)); + + printf("Printing out netlogon server type flags:\n"); + + ZERO_STRUCT(search); + search.in.dest_address = dest; + search.in.dest_port = lp_cldap_port(tctx->lp_ctx); + search.in.acct_control = -1; + search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; + search.in.map_response = true; + + status = cldap_netlogon(cldap, tctx, &search); + CHECK_STATUS(status, NT_STATUS_OK); + + n1 = search.out.netlogon; + if (n1.ntver == NETLOGON_NT_VERSION_5) + server_type = n1.nt5.server_type; + else if (n1.ntver == NETLOGON_NT_VERSION_5EX) + server_type = n1.nt5_ex.server_type; + + printf("The word is: %i\n", server_type); + if (server_type & NBT_SERVER_PDC) + printf("NBT_SERVER_PDC "); + if (server_type & NBT_SERVER_GC) + printf("NBT_SERVER_GC "); + if (server_type & NBT_SERVER_LDAP) + printf("NBT_SERVER_LDAP "); + if (server_type & NBT_SERVER_DS) + printf("NBT_SERVER_DS "); + if (server_type & NBT_SERVER_KDC) + printf("NBT_SERVER_KDC "); + if (server_type & NBT_SERVER_TIMESERV) + printf("NBT_SERVER_TIMESERV "); + if (server_type & NBT_SERVER_CLOSEST) + printf("NBT_SERVER_CLOSEST "); + if (server_type & NBT_SERVER_WRITABLE) + printf("NBT_SERVER_WRITABLE "); + if (server_type & NBT_SERVER_GOOD_TIMESERV) + printf("NBT_SERVER_GOOD_TIMESERV "); + if (server_type & NBT_SERVER_NDNC) + printf("NBT_SERVER_NDNC "); + if (server_type & NBT_SERVER_SEL_SEC_DOM_6) + printf("NBT_SERVER_SEL_SEC_DOM_6 "); + if (server_type & NBT_SERVER_FUL_SEC_DOM_6) + printf("NBT_SERVER_FUL_SEC_DOM_6 "); + if (server_type & NBT_SERVER_DS_DNS_CONTR) + printf("NBT_SERVER_DS_DNS_CONTR "); + if (server_type & NBT_SERVER_DS_DNS_DOMAIN) + printf("NBT_SERVER_DS_DNS_DOMAIN "); + if (server_type & NBT_SERVER_DS_DNS_FOREST) + printf("NBT_SERVER_DS_DNS_FOREST "); + + printf("\n"); + + return true; +} + +/* convert a ldap result message to a ldb message. This allows us to use the convenient ldif dump routines in ldb to print out cldap search results @@ -266,6 +335,81 @@ static void cldap_dump_results(struct cldap_search *search) talloc_free(ldb); } + +/* + test cldap netlogon server type flag "NBT_SERVER_DS_DNS_FOREST" +*/ +static bool test_cldap_netlogon_flag_ds_dns_forest(struct torture_context *tctx, + const char *dest) +{ + struct cldap_socket *cldap; + NTSTATUS status; + struct cldap_netlogon search; + uint32_t server_type; + struct netlogon_samlogon_response n1; + + bool result = true; + + cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx)); + + printf("Testing netlogon server type flag NBT_SERVER_DS_DNS_FOREST: "); + + ZERO_STRUCT(search); + search.in.dest_address = dest; + search.in.dest_port = lp_cldap_port(tctx->lp_ctx); + search.in.acct_control = -1; + search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; + search.in.map_response = true; + + status = cldap_netlogon(cldap, tctx, &search); + CHECK_STATUS(status, NT_STATUS_OK); + + n1 = search.out.netlogon; + if (n1.ntver == NETLOGON_NT_VERSION_5) + server_type = n1.nt5.server_type; + else if (n1.ntver == NETLOGON_NT_VERSION_5EX) + server_type = n1.nt5_ex.server_type; + + if (server_type & NBT_SERVER_DS_DNS_FOREST) { + struct cldap_search search2; + const char *attrs[] = { "defaultNamingContext", "rootDomainNamingContext", + NULL }; + struct ldb_context *ldb; + struct ldb_message *msg; + + /* Trying to fetch the attributes "defaultNamingContext" and + "rootDomainNamingContext" */ + ZERO_STRUCT(search2); + search2.in.dest_address = dest; + search2.in.dest_port = lp_cldap_port(tctx->lp_ctx); + search2.in.timeout = 10; + search2.in.retries = 3; + search2.in.filter = "(objectclass=*)"; + search2.in.attributes = attrs; + + status = cldap_search(cldap, tctx, &search2); + CHECK_STATUS(status, NT_STATUS_OK); + + ldb = ldb_init(NULL, NULL); + + msg = ldap_msg_to_ldb(ldb, ldb, search2.out.response); + + /* Try to compare the two attributes */ + if (ldb_msg_element_compare(ldb_msg_find_element(msg, attrs[0]), + ldb_msg_find_element(msg, attrs[1]))) + result = false; + + talloc_free(ldb); + } + + if (result) + printf("passed\n"); + else + printf("failed\n"); + + return result; +} + /* test generic cldap operations */ @@ -343,6 +487,8 @@ bool torture_cldap(struct torture_context *torture) const char *host = torture_setting_string(torture, "host", NULL); ret &= test_cldap_netlogon(torture, host); + ret &= test_cldap_netlogon_flags(torture, host); + ret &= test_cldap_netlogon_flag_ds_dns_forest(torture, host); ret &= test_cldap_generic(torture, host); return ret; |