From 3f2ca10d2d86f0cd64822f9e5f95633f41263237 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 13 Nov 2007 22:38:55 +0100 Subject: r25940: Rework the samldb and templates handling. Templates just don't belong in the sam.ldb, as they don't obey any of the other rules. This moves them to a seperate templates.ldb. In samldb, this patch reworks the duplicate SID and Name detection code, to use ldb_search_exp_fmt() rather than gendb_search. This returns far more useful errors, which we now handle and report better. The call to samdb_search_for_parent_domain() has been moved in samldb, to allow both the account and SID uniqueness checks to be in the same domain. This function also returns better errors. dcesrv_drsuapi.c is updated for the new prototype of samdb_search_for_parent_domain() Andrew Bartlett (This used to be commit f1ab90c88c782c693b41795d70368650806543b5) --- source4/dsdb/samdb/ldb_modules/samldb.c | 83 ++++++++++++++++++------------- source4/dsdb/samdb/samdb.c | 87 +++++++++++++++++++++++++++++---- 2 files changed, 125 insertions(+), 45 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 128ec13242..e2e914ee82 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -190,24 +190,16 @@ static int samldb_allocate_next_rid(struct ldb_module *module, TALLOC_CTX *mem_c */ static int samldb_get_new_sid(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn, + struct ldb_dn *dom_dn, struct dom_sid **sid) { const char * const attrs[2] = { "objectSid", NULL }; struct ldb_result *res = NULL; - struct ldb_dn *dom_dn; int ret; struct dom_sid *dom_sid; /* get the domain component part of the provided dn */ - dom_dn = samdb_search_for_parent_domain(module->ldb, mem_ctx, obj_dn); - if (dom_dn == NULL) { - ldb_asprintf_errstring(module->ldb, - "Invalid dn (%s) not child of a domain object!\n", - ldb_dn_get_linearized(obj_dn)); - return LDB_ERR_CONSTRAINT_VIOLATION; - } - /* find the domain sid */ ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res); @@ -338,13 +330,14 @@ int samldb_notice_sid(struct ldb_module *module, } static int samldb_handle_sid(struct ldb_module *module, - TALLOC_CTX *mem_ctx, struct ldb_message *msg2) + TALLOC_CTX *mem_ctx, struct ldb_message *msg2, + struct ldb_dn *parent_dn) { int ret; struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg2, "objectSid"); if (sid == NULL) { - ret = samldb_get_new_sid(module, msg2, msg2->dn, &sid); + ret = samldb_get_new_sid(module, msg2, msg2->dn, parent_dn, &sid); if (ret != 0) { return ret; } @@ -361,31 +354,35 @@ static int samldb_handle_sid(struct ldb_module *module, return ret; } -static char *samldb_generate_samAccountName(struct ldb_module *module, TALLOC_CTX *mem_ctx) +static int samldb_generate_samAccountName(struct ldb_module *module, TALLOC_CTX *mem_ctx, + struct ldb_dn *dom_dn, char **name) { - char *name; const char *attrs[] = { NULL }; - struct ldb_message **msgs; + struct ldb_result *res; int ret; /* Format: $000000-000000000000 */ do { - name = talloc_asprintf(mem_ctx, "$%.6X-%.6X%.6X", (unsigned int)random(), (unsigned int)random(), (unsigned int)random()); + *name = talloc_asprintf(mem_ctx, "$%.6X-%.6X%.6X", (unsigned int)random(), (unsigned int)random(), (unsigned int)random()); /* TODO: Figure out exactly what this is meant to conflict with */ - ret = gendb_search(module->ldb, - mem_ctx, NULL, &msgs, attrs, - "samAccountName=%s", - ldb_binary_encode_string(mem_ctx, name)); - if (ret == 0) { + ret = ldb_search_exp_fmt(module->ldb, + mem_ctx, &res, dom_dn, LDB_SCOPE_SUBTREE, attrs, + "samAccountName=%s", + ldb_binary_encode_string(mem_ctx, *name)); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(module->ldb, "samldb: Failure searching to determine if samAccountName %s is unique: %s", + *name, ldb_errstring(module->ldb)); + return ret; + } + + if (res->count == 0) { + talloc_free(res); /* Great. There are no conflicting users/groups/etc */ - return name; - } else if (ret == -1) { - /* Bugger, there is a problem, and we don't know what it is until gendb_search improves */ - return NULL; + return LDB_SUCCESS; } else { - talloc_free(name); - /* gah, there are conflicting sids, lets move around the loop again... */ + talloc_free(*name); + /* gah, there is a conflicting name, lets move around the loop again... */ } } while (1); } @@ -394,8 +391,9 @@ static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_ struct ldb_message **ret_msg) { int ret; - const char *name; + char *name; struct ldb_message *msg2; + struct ldb_dn *dom_dn; const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; @@ -428,12 +426,19 @@ static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_ return LDB_ERR_CONSTRAINT_VIOLATION; } + ret = samdb_search_for_parent_domain(module->ldb, mem_ctx, msg2->dn, &dom_dn, &errstr); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(module->ldb, + "samldb_fill_group_object: %s", errstr); + return ret; + } + /* Generate a random name, if no samAccountName was supplied */ if (ldb_msg_find_element(msg2, "samAccountName") == NULL) { - name = samldb_generate_samAccountName(module, mem_ctx); - if (!name) { + ret = samldb_generate_samAccountName(module, mem_ctx, dom_dn, &name); + if (ret != LDB_SUCCESS) { talloc_free(mem_ctx); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name); if (ret) { @@ -443,7 +448,7 @@ static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_ } /* Manage SID allocation, conflicts etc */ - ret = samldb_handle_sid(module, mem_ctx, msg2); + ret = samldb_handle_sid(module, mem_ctx, msg2, dom_dn); if (ret == LDB_SUCCESS) { talloc_steal(msg, msg2); @@ -459,6 +464,7 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const int ret; char *name; struct ldb_message *msg2; + struct ldb_dn *dom_dn; const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; @@ -514,11 +520,18 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const return LDB_ERR_CONSTRAINT_VIOLATION; } + ret = samdb_search_for_parent_domain(module->ldb, mem_ctx, msg2->dn, &dom_dn, &errstr); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(module->ldb, + "samldb_fill_group_object: %s", errstr); + return ret; + } + if (ldb_msg_find_element(msg2, "samAccountName") == NULL) { - name = samldb_generate_samAccountName(module, mem_ctx); - if (!name) { + ret = samldb_generate_samAccountName(module, mem_ctx, dom_dn, &name); + if (ret != LDB_SUCCESS) { talloc_free(mem_ctx); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name); if (ret) { @@ -532,7 +545,7 @@ static int samldb_fill_user_or_computer_object(struct ldb_module *module, const */ /* Manage SID allocation, conflicts etc */ - ret = samldb_handle_sid(module, mem_ctx, msg2); + ret = samldb_handle_sid(module, mem_ctx, msg2, dom_dn); /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */ diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c index 36e12e859e..96e526d319 100644 --- a/source4/dsdb/samdb/samdb.c +++ b/source4/dsdb/samdb/samdb.c @@ -37,6 +37,34 @@ #include "dsdb/common/flags.h" #include "param/param.h" +char *samdb_relative_path(struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + const char *name) +{ + const char *base_url = + (const char *)ldb_get_opaque(ldb, "ldb_url"); + char *path, *p, *full_name; + if (name == NULL) { + return NULL; + } + if (name[0] == 0 || name[0] == '/' || strstr(name, ":/")) { + return talloc_strdup(mem_ctx, name); + } + path = talloc_strdup(mem_ctx, base_url); + if (path == NULL) { + return NULL; + } + if ( (p = strrchr(path, '/')) != NULL) { + p[0] = '\0'; + full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name); + } else { + full_name = talloc_asprintf(mem_ctx, "./%s", name); + } + talloc_free(path); + return full_name; +} + + /* connect to the SAM database return an opaque context pointer on success, or NULL on failure @@ -682,21 +710,49 @@ int samdb_copy_template(struct ldb_context *ldb, struct ldb_result *res; struct ldb_message *t; int ret, i, j; - struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates"); + struct ldb_context *templates_ldb; + char *templates_ldb_path; + struct ldb_dn *basedn; + + templates_ldb = talloc_get_type(ldb_get_opaque(ldb, "templates_ldb"), struct ldb_context); + + if (!templates_ldb) { + templates_ldb_path = samdb_relative_path(ldb, + msg, + "templates.ldb"); + if (!templates_ldb_path) { + *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct path for template db"); + return LDB_ERR_OPERATIONS_ERROR; + } + templates_ldb = ldb_wrap_connect(ldb, global_loadparm, + templates_ldb_path, NULL, + NULL, 0, NULL); + talloc_free(templates_ldb_path); + if (!templates_ldb) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_set_opaque(ldb, "templates_ldb", templates_ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + } *errstring = NULL; + basedn = ldb_dn_new(templates_ldb, ldb, "cn=Templates"); if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) { + talloc_free(basedn); *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'", name); return LDB_ERR_OPERATIONS_ERROR; } /* pull the template record */ - ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, "cn=*", NULL, &res); + ret = ldb_search(templates_ldb, basedn, LDB_SCOPE_BASE, "(dn=*)", NULL, &res); talloc_free(basedn); if (ret != LDB_SUCCESS) { - *errstring = talloc_steal(msg, ldb_errstring(ldb)); + *errstring = talloc_steal(msg, ldb_errstring(templates_ldb)); return ret; } if (res->count != 1) { @@ -1439,7 +1495,8 @@ failed: /* Find a domain object in the parents of a particular DN. */ -struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn) +int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, + struct ldb_dn **parent_dn, const char **errstring) { TALLOC_CTX *local_ctx; struct ldb_dn *sdn = dn; @@ -1448,7 +1505,7 @@ struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CT const char *attrs[] = { NULL }; local_ctx = talloc_new(mem_ctx); - if (local_ctx == NULL) return NULL; + if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR; while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) { ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, @@ -1458,18 +1515,28 @@ struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CT if (res->count == 1) { break; } + } else { + break; } } - if (ret != LDB_SUCCESS || res->count != 1) { + if (ret != LDB_SUCCESS) { + *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s: %s", + ldb_dn_get_linearized(sdn), + ldb_errstring(ldb)); talloc_free(local_ctx); - return NULL; + return ret; + } + if (res->count != 1) { + *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object", + ldb_dn_get_linearized(sdn)); + talloc_free(local_ctx); + return LDB_ERR_CONSTRAINT_VIOLATION; } - talloc_steal(mem_ctx, sdn); + *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn); talloc_free(local_ctx); - - return sdn; + return ret; } /* -- cgit