mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
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 commit is contained in:
parent
e47df4a0fe
commit
f1ab90c88c
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -570,6 +570,7 @@ static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_sta
|
||||
ret = ldb_search_exp_fmt(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
|
||||
LDB_SCOPE_BASE, attrs_account_1, "objectClass=computer");
|
||||
if (ret == LDB_SUCCESS && res_account->count == 1) {
|
||||
const char *errstr;
|
||||
ctr1->array[i].dns_name
|
||||
= ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
|
||||
ctr1->array[i].netbios_name
|
||||
@ -578,10 +579,11 @@ static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_sta
|
||||
= ldb_dn_get_linearized(res_account->msgs[0]->dn);
|
||||
|
||||
/* Determine if this is the PDC */
|
||||
domain_dn = samdb_search_for_parent_domain(b_state->sam_ctx,
|
||||
mem_ctx, res_account->msgs[0]->dn);
|
||||
ret = samdb_search_for_parent_domain(b_state->sam_ctx,
|
||||
mem_ctx, res_account->msgs[0]->dn,
|
||||
&domain_dn, &errstr);
|
||||
|
||||
if (domain_dn) {
|
||||
if (ret == LDB_SUCCESS) {
|
||||
ret = ldb_search_exp_fmt(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
|
||||
LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
|
||||
ldb_dn_get_linearized(ntds_dn));
|
||||
@ -664,6 +666,7 @@ static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_sta
|
||||
ret = ldb_search_exp_fmt(b_state->sam_ctx, mem_ctx, &res_account, ref_dn,
|
||||
LDB_SCOPE_BASE, attrs_account_2, "objectClass=computer");
|
||||
if (ret == LDB_SUCCESS && res_account->count == 1) {
|
||||
const char *errstr;
|
||||
ctr2->array[i].dns_name
|
||||
= ldb_msg_find_attr_as_string(res_account->msgs[0], "dNSHostName", NULL);
|
||||
ctr2->array[i].netbios_name
|
||||
@ -673,10 +676,11 @@ static WERROR dcesrv_drsuapi_DsGetDomainControllerInfo_1(struct drsuapi_bind_sta
|
||||
= samdb_result_guid(res_account->msgs[0], "objectGUID");
|
||||
|
||||
/* Determine if this is the PDC */
|
||||
domain_dn = samdb_search_for_parent_domain(b_state->sam_ctx,
|
||||
mem_ctx, res_account->msgs[0]->dn);
|
||||
ret = samdb_search_for_parent_domain(b_state->sam_ctx,
|
||||
mem_ctx, res_account->msgs[0]->dn,
|
||||
&domain_dn, &errstr);
|
||||
|
||||
if (domain_dn) {
|
||||
if (ret == LDB_SUCCESS) {
|
||||
ret = ldb_search_exp_fmt(b_state->sam_ctx, mem_ctx, &res_domain, domain_dn,
|
||||
LDB_SCOPE_BASE, attrs_none, "fSMORoleOwner=%s",
|
||||
ldb_dn_get_linearized(ntds_dn));
|
||||
|
@ -383,6 +383,7 @@ function provision_default_paths(subobj)
|
||||
paths.shareconf = lp.get("private dir") + "/" + "share.ldb";
|
||||
paths.samdb = lp.get("sam database");
|
||||
paths.secrets = lp.get("secrets database");
|
||||
paths.templates = lp.get("private dir") + "/" + "templates.ldb";
|
||||
paths.keytab = "secrets.keytab";
|
||||
paths.dns_keytab = "dns.keytab";
|
||||
paths.dns_keytab_abs = lp.get("private dir") + "/" + paths.dns_keytab;
|
||||
@ -528,6 +529,9 @@ function provision_become_dc(subobj, message, erase, paths, session_info)
|
||||
info.message = message;
|
||||
info.session_info = session_info;
|
||||
|
||||
message("Setting up teplates into " + paths.templates + "\n");
|
||||
setup_ldb("provision_templates.ldif", info, paths.templates);
|
||||
|
||||
/* Also wipes the database */
|
||||
message("Setting up " + paths.samdb + " partitions\n");
|
||||
setup_ldb("provision_partitions.ldif", info, paths.samdb);
|
||||
@ -548,9 +552,6 @@ function provision_become_dc(subobj, message, erase, paths, session_info)
|
||||
message("Setting up " + paths.samdb + " indexes\n");
|
||||
setup_add_ldif("provision_index.ldif", info, samdb, false);
|
||||
|
||||
message("Setting up " + paths.samdb + " templates\n");
|
||||
setup_add_ldif("provision_templates.ldif", info, samdb, false);
|
||||
|
||||
ok = samdb.transaction_commit();
|
||||
assert(ok);
|
||||
|
||||
@ -623,6 +624,9 @@ function provision(subobj, message, blank, paths, session_info, credentials, lda
|
||||
var reg = reg_open();
|
||||
reg.apply_patchfile(lp.get("setup directory") + "/provision.reg")
|
||||
|
||||
message("Setting up teplates into " + paths.templates + "\n");
|
||||
setup_ldb("provision_templates.ldif", info, paths.templates);
|
||||
|
||||
message("Setting up sam.ldb partitions\n");
|
||||
/* Also wipes the database */
|
||||
setup_ldb("provision_partitions.ldif", info, paths.samdb);
|
||||
@ -707,8 +711,6 @@ function provision(subobj, message, blank, paths, session_info, credentials, lda
|
||||
|
||||
message("Setting up display specifiers\n");
|
||||
setup_add_ldif("display_specifiers.ldif", info, samdb, false);
|
||||
message("Setting up sam.ldb templates\n");
|
||||
setup_add_ldif("provision_templates.ldif", info, samdb, false);
|
||||
|
||||
message("Adding users container (permitted to fail)\n");
|
||||
var add_ok = setup_add_ldif("provision_users_add.ldif", info, samdb, true);
|
||||
|
@ -1,15 +1,21 @@
|
||||
###
|
||||
# Templates to be put in templates.ldb. Not part of main samdb any more.
|
||||
###
|
||||
|
||||
dn: @OPTIONS
|
||||
checkBaseOnSearch: TRUE
|
||||
|
||||
dn: @INDEXLIST
|
||||
@IDXATTR: cn
|
||||
|
||||
dn: @ATTRIBUTES
|
||||
cn: CASE_INSENSITIVE
|
||||
dn: CASE_INSENSITIVE
|
||||
|
||||
dn: CN=Templates
|
||||
objectClass: top
|
||||
objectClass: container
|
||||
description: Container for SAM account templates
|
||||
showInAdvancedViewOnly: TRUE
|
||||
systemFlags: 2348810240
|
||||
isCriticalSystemObject: TRUE
|
||||
|
||||
###
|
||||
# note! the template users must not match normal searches. Be careful
|
||||
# with what classes you put them in
|
||||
###
|
||||
|
||||
dn: CN=TemplateUser,CN=Templates
|
||||
userAccountControl: 514
|
||||
|
Loading…
Reference in New Issue
Block a user