mirror of
https://github.com/samba-team/samba.git
synced 2025-11-11 00:23:51 +03:00
r21135: Instead of having hooks to update keytabs as an explicit thing, update
them as a hook on ldb modify, via a module. This should allow the secrets.ldb to be edited by the admin, and to have things update in the on-disk keytab just as an in-memory keytab would. This isn't really a dsdb plugin, but I don't have any other good ideas about where to put it. Andrew Bartlett
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
966c30ca59
commit
6ce557a1af
@@ -349,8 +349,12 @@ BOOL cli_credentials_set_nt_hash(struct cli_credentials *cred,
|
||||
{
|
||||
if (obtained >= cred->password_obtained) {
|
||||
cli_credentials_set_password(cred, NULL, obtained);
|
||||
if (nt_hash) {
|
||||
cred->nt_hash = talloc(cred, struct samr_Password);
|
||||
*cred->nt_hash = *nt_hash;
|
||||
} else {
|
||||
cred->nt_hash = NULL;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,12 +169,12 @@ BOOL cli_credentials_parse_file(struct cli_credentials *cred, const char *file,
|
||||
* @retval NTSTATUS error detailing any failure
|
||||
*/
|
||||
NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
|
||||
struct ldb_context *ldb,
|
||||
const char *base,
|
||||
const char *filter)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
struct ldb_context *ldb;
|
||||
int ldb_ret;
|
||||
struct ldb_message **msgs;
|
||||
const char *attrs[] = {
|
||||
@@ -209,6 +209,7 @@ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
|
||||
|
||||
mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password");
|
||||
|
||||
if (!ldb) {
|
||||
/* Local secrets are stored in secrets.ldb */
|
||||
ldb = secrets_db_connect(mem_ctx);
|
||||
if (!ldb) {
|
||||
@@ -217,6 +218,7 @@ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
|
||||
DEBUG(1, ("Could not open secrets.ldb\n"));
|
||||
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
/* search for the secret record */
|
||||
ldb_ret = gendb_search(ldb,
|
||||
@@ -327,7 +329,7 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
|
||||
cred->machine_account_pending = False;
|
||||
filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER,
|
||||
cli_credentials_get_domain(cred));
|
||||
return cli_credentials_set_secrets(cred, SECRETS_PRIMARY_DOMAIN_DN,
|
||||
return cli_credentials_set_secrets(cred, NULL, SECRETS_PRIMARY_DOMAIN_DN,
|
||||
filter);
|
||||
}
|
||||
|
||||
@@ -347,7 +349,7 @@ NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred)
|
||||
filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH,
|
||||
cli_credentials_get_realm(cred),
|
||||
cli_credentials_get_domain(cred));
|
||||
return cli_credentials_set_secrets(cred, SECRETS_PRINCIPALS_DN,
|
||||
return cli_credentials_set_secrets(cred, NULL, SECRETS_PRINCIPALS_DN,
|
||||
filter);
|
||||
}
|
||||
|
||||
@@ -369,7 +371,7 @@ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred,
|
||||
cli_credentials_get_realm(cred),
|
||||
cli_credentials_get_domain(cred),
|
||||
serviceprincipal);
|
||||
return cli_credentials_set_secrets(cred, SECRETS_PRINCIPALS_DN,
|
||||
return cli_credentials_set_secrets(cred, NULL, SECRETS_PRINCIPALS_DN,
|
||||
filter);
|
||||
}
|
||||
|
||||
@@ -388,66 +390,3 @@ void cli_credentials_set_machine_account_pending(struct cli_credentials *cred)
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS cli_credentials_update_all_keytabs(TALLOC_CTX *parent_ctx)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
int ldb_ret;
|
||||
struct ldb_context *ldb;
|
||||
struct ldb_message **msgs;
|
||||
const char *attrs[] = { NULL };
|
||||
struct cli_credentials *creds;
|
||||
const char *filter;
|
||||
NTSTATUS status;
|
||||
int i, ret;
|
||||
|
||||
mem_ctx = talloc_new(parent_ctx);
|
||||
if (!mem_ctx) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Local secrets are stored in secrets.ldb */
|
||||
ldb = secrets_db_connect(mem_ctx);
|
||||
if (!ldb) {
|
||||
DEBUG(1, ("Could not open secrets.ldb\n"));
|
||||
talloc_free(mem_ctx);
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
/* search for the secret record, but only of things we can
|
||||
* actually update */
|
||||
ldb_ret = gendb_search(ldb,
|
||||
mem_ctx, NULL,
|
||||
&msgs, attrs,
|
||||
"(&(objectClass=kerberosSecret)(|(secret=*)(ntPwdHash=*)))");
|
||||
if (ldb_ret == -1) {
|
||||
DEBUG(1, ("Error looking for kerberos type secrets to push into a keytab:: %s", ldb_errstring(ldb)));
|
||||
talloc_free(mem_ctx);
|
||||
return NT_STATUS_INTERNAL_DB_CORRUPTION;
|
||||
}
|
||||
|
||||
for (i=0; i < ldb_ret; i++) {
|
||||
/* Make a credentials structure from it */
|
||||
creds = cli_credentials_init(mem_ctx);
|
||||
if (!creds) {
|
||||
DEBUG(1, ("cli_credentials_init failed!"));
|
||||
talloc_free(mem_ctx);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
cli_credentials_set_conf(creds);
|
||||
filter = talloc_asprintf(mem_ctx, "dn=%s", ldb_dn_get_linearized(msgs[i]->dn));
|
||||
status = cli_credentials_set_secrets(creds, NULL, filter);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Failed to read secrets for keytab update for %s\n",
|
||||
filter));
|
||||
continue;
|
||||
}
|
||||
ret = cli_credentials_update_keytab(creds);
|
||||
if (ret != 0) {
|
||||
DEBUG(1, ("Failed to update keytab for %s\n",
|
||||
filter));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,8 +133,7 @@ OBJ_FILES = \
|
||||
SUBSYSTEM = ldb
|
||||
INIT_FUNCTION = password_hash_module_init
|
||||
OBJ_FILES = password_hash.o
|
||||
PUBLIC_DEPENDENCIES = HEIMDAL_KRB5
|
||||
PRIVATE_DEPENDENCIES = HEIMDAL_HDB_KEYS LIBTALLOC
|
||||
PRIVATE_DEPENDENCIES = HEIMDAL_HDB_KEYS LIBTALLOC HEIMDAL_KRB5
|
||||
#
|
||||
# End MODULE ldb_password_hash
|
||||
################################################
|
||||
@@ -212,3 +211,16 @@ OBJ_FILES = \
|
||||
# End MODULE ldb_schema
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE ldb_update_kt
|
||||
[MODULE::ldb_update_kt]
|
||||
SUBSYSTEM = ldb
|
||||
PRIVATE_DEPENDENCIES = LIBTALLOC CREDENTIALS_KRB5
|
||||
#Also depends on credentials, but that would loop
|
||||
INIT_FUNCTION = ldb_update_kt_init
|
||||
OBJ_FILES = \
|
||||
update_keytab.o
|
||||
#
|
||||
# End MODULE ldb_update_kt
|
||||
################################################
|
||||
|
||||
|
||||
189
source/dsdb/samdb/ldb_modules/update_keytab.c
Normal file
189
source/dsdb/samdb/ldb_modules/update_keytab.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
ldb database library
|
||||
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Name: ldb
|
||||
*
|
||||
* Component: ldb update_keytabs module
|
||||
*
|
||||
* Description: Update keytabs whenever their matching secret record changes
|
||||
*
|
||||
* Author: Andrew Bartlett
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb/include/includes.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
#include "auth/credentials/credentials_krb5.h"
|
||||
#include "system/kerberos.h"
|
||||
|
||||
struct dn_list {
|
||||
struct cli_credentials *creds;
|
||||
struct dn_list *prev, *next;
|
||||
};
|
||||
|
||||
struct update_kt_private {
|
||||
struct dn_list *changed_dns;
|
||||
};
|
||||
|
||||
static int add_modified(struct ldb_module *module, struct ldb_dn *dn, BOOL delete) {
|
||||
struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
|
||||
struct dn_list *item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
|
||||
char *filter;
|
||||
NTSTATUS status;
|
||||
if (!item) {
|
||||
ldb_oom(module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
item->creds = cli_credentials_init(item);
|
||||
if (!item->creds) {
|
||||
DEBUG(1, ("cli_credentials_init failed!"));
|
||||
ldb_oom(module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
cli_credentials_set_conf(item->creds);
|
||||
filter = talloc_asprintf(item, "(&(&(objectClass=kerberosSecret)(&(privateKeytab=*)(|(secret=*)(ntPwdHash=*))))(dn=%s))",
|
||||
ldb_dn_get_linearized(dn));
|
||||
status = cli_credentials_set_secrets(item->creds, module->ldb, NULL, filter);
|
||||
talloc_free(filter);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
if (delete) {
|
||||
/* Ensure we don't helpfully keep an old keytab entry */
|
||||
cli_credentials_set_kvno(item->creds, cli_credentials_get_kvno(item->creds)+2);
|
||||
/* Wipe passwords */
|
||||
cli_credentials_set_nt_hash(item->creds, NULL,
|
||||
CRED_SPECIFIED);
|
||||
}
|
||||
DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
|
||||
}
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
|
||||
/* add */
|
||||
static int update_kt_add(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
int ret;
|
||||
ret = ldb_next_request(module, req);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return add_modified(module, req->op.add.message->dn, False);
|
||||
}
|
||||
|
||||
/* modify */
|
||||
static int update_kt_modify(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
int ret;
|
||||
ret = ldb_next_request(module, req);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return add_modified(module, req->op.mod.message->dn, False);
|
||||
}
|
||||
|
||||
/* delete */
|
||||
static int update_kt_delete(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
int ret;
|
||||
/* Before we delete it, record the details */
|
||||
ret = add_modified(module, req->op.del.dn, True);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* rename */
|
||||
static int update_kt_rename(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
int ret;
|
||||
ret = ldb_next_request(module, req);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return add_modified(module, req->op.rename.newdn, False);
|
||||
}
|
||||
|
||||
/* end a transaction */
|
||||
static int update_kt_end_trans(struct ldb_module *module)
|
||||
{
|
||||
struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
|
||||
|
||||
struct dn_list *p;
|
||||
for (p=data->changed_dns; p; p = p->next) {
|
||||
int kret;
|
||||
kret = cli_credentials_update_keytab(p->creds);
|
||||
if (kret != 0) {
|
||||
talloc_free(data->changed_dns);
|
||||
data->changed_dns = NULL;
|
||||
ldb_asprintf_errstring(module->ldb, "Failed to update keytab: %s", error_message(kret));
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free(data->changed_dns);
|
||||
data->changed_dns = NULL;
|
||||
return ldb_next_end_trans(module);
|
||||
}
|
||||
|
||||
/* end a transaction */
|
||||
static int update_kt_del_trans(struct ldb_module *module)
|
||||
{
|
||||
struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
|
||||
|
||||
talloc_free(data->changed_dns);
|
||||
data->changed_dns = NULL;
|
||||
|
||||
return ldb_next_end_trans(module);
|
||||
}
|
||||
|
||||
static int update_kt_init(struct ldb_module *module)
|
||||
{
|
||||
struct update_kt_private *data;
|
||||
|
||||
data = talloc(module, struct update_kt_private);
|
||||
if (data == NULL) {
|
||||
ldb_oom(module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
module->private_data = data;
|
||||
data->changed_dns = NULL;
|
||||
|
||||
return ldb_next_init(module);
|
||||
}
|
||||
|
||||
static const struct ldb_module_ops update_kt_ops = {
|
||||
.name = "update_keytab",
|
||||
.init_context = update_kt_init,
|
||||
.add = update_kt_add,
|
||||
.modify = update_kt_modify,
|
||||
.rename = update_kt_rename,
|
||||
.del = update_kt_delete,
|
||||
.end_transaction = update_kt_end_trans,
|
||||
.del_transaction = update_kt_del_trans,
|
||||
};
|
||||
|
||||
int ldb_update_kt_init(void)
|
||||
{
|
||||
return ldb_register_module(&update_kt_ops);
|
||||
}
|
||||
@@ -266,23 +266,11 @@ int ejs_credentials_cmdline(int eid, int argc, struct MprVar **argv)
|
||||
return ejs_credentials_obj(obj, cmdline_credentials);
|
||||
}
|
||||
|
||||
static int ejs_credentials_update_all_keytabs(MprVarHandle eid, int argc, struct MprVar **argv)
|
||||
{
|
||||
if (!NT_STATUS_IS_OK(cli_credentials_update_all_keytabs(mprMemCtx()))) {
|
||||
mpr_Return(eid, mprCreateBoolVar(False));
|
||||
} else {
|
||||
mpr_Return(eid, mprCreateBoolVar(True));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
setup C functions that be called from ejs
|
||||
*/
|
||||
void smb_setup_ejs_credentials(void)
|
||||
{
|
||||
ejsDefineCFunction(-1, "credentials_init", ejs_credentials_init, NULL, MPR_VAR_SCRIPT_HANDLE);
|
||||
ejsDefineCFunction(-1, "credentials_update_all_keytabs", ejs_credentials_update_all_keytabs, NULL, MPR_VAR_SCRIPT_HANDLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -488,16 +488,14 @@ function provision_become_dc(subobj, message, paths, session_info)
|
||||
assert(ok);
|
||||
|
||||
message("Setting up " + paths.secrets + "\n");
|
||||
setup_ldb("secrets.ldif", info, paths.secrets);
|
||||
setup_ldb("secrets_init.ldif", info, paths.secrets);
|
||||
|
||||
setup_ldb("secrets.ldif", info, paths.secrets, false);
|
||||
|
||||
tmp = lp.get("secrets database");
|
||||
ok = lp.set("secrets database", paths.secrets);
|
||||
assert(ok);
|
||||
|
||||
message("Setting up keytabs\n");
|
||||
var keytab_ok = credentials_update_all_keytabs();
|
||||
assert(keytab_ok);
|
||||
|
||||
ok = lp.set("secrets database", tmp);
|
||||
assert(ok);
|
||||
|
||||
@@ -547,12 +545,9 @@ function provision(subobj, message, blank, paths, session_info, credentials, lda
|
||||
setup_ldb("share.ldif", info, paths.shareconf);
|
||||
}
|
||||
|
||||
message("Setting up secrets.ldb\n");
|
||||
setup_ldb("secrets.ldif", info, paths.secrets);
|
||||
|
||||
message("Setting up keytabs\n");
|
||||
var keytab_ok = credentials_update_all_keytabs();
|
||||
assert(keytab_ok);
|
||||
message("Setting up " + paths.secrets + "\n");
|
||||
setup_ldb("secrets_init.ldif", info, paths.secrets);
|
||||
setup_ldb("secrets.ldif", info, paths.secrets, false);
|
||||
|
||||
message("Setting up hklm.ldb\n");
|
||||
setup_ldb("hklm.ldif", info, paths.hklm);
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
dn: @INDEXLIST
|
||||
@IDXATTR: cn
|
||||
@IDXATTR: flatname
|
||||
@IDXATTR: realm
|
||||
|
||||
dn: @ATTRIBUTES
|
||||
realm: CASE_INSENSITIVE
|
||||
flatname: CASE_INSENSITIVE
|
||||
sAMAccountName: CASE_INSENSITIVE
|
||||
|
||||
#Add modules to the list to activate them by default
|
||||
#beware often order is important
|
||||
dn: @MODULES
|
||||
@LIST: operational
|
||||
|
||||
dn: CN=LSA Secrets
|
||||
objectClass: top
|
||||
objectClass: container
|
||||
|
||||
15
source/setup/secrets_init.ldif
Normal file
15
source/setup/secrets_init.ldif
Normal file
@@ -0,0 +1,15 @@
|
||||
dn: @INDEXLIST
|
||||
@IDXATTR: cn
|
||||
@IDXATTR: flatname
|
||||
@IDXATTR: realm
|
||||
|
||||
dn: @ATTRIBUTES
|
||||
realm: CASE_INSENSITIVE
|
||||
flatname: CASE_INSENSITIVE
|
||||
sAMAccountName: CASE_INSENSITIVE
|
||||
|
||||
#Add modules to the list to activate them by default
|
||||
#beware often order is important
|
||||
dn: @MODULES
|
||||
@LIST: update_keytab,operational,objectguid
|
||||
|
||||
Reference in New Issue
Block a user