From 6ce557a1aff4754d2622be8f1c6695d9ee788d54 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 4 Feb 2007 07:17:03 +0000 Subject: [PATCH] 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 --- source/auth/credentials/credentials.c | 8 +- source/auth/credentials/credentials_files.c | 85 ++---------- source/dsdb/samdb/ldb_modules/config.mk | 16 ++- source/dsdb/samdb/ldb_modules/update_keytab.c | 189 ++++++++++++++++++++++++++ source/scripting/ejs/smbcalls_creds.c | 12 -- source/scripting/libjs/provision.js | 17 +-- source/setup/secrets.ldif | 15 -- source/setup/secrets_init.ldif | 15 ++ 8 files changed, 242 insertions(+), 115 deletions(-) create mode 100644 source/dsdb/samdb/ldb_modules/update_keytab.c create mode 100644 source/setup/secrets_init.ldif diff --git a/source/auth/credentials/credentials.c b/source/auth/credentials/credentials.c index 2a64a7c50c5..48d44ad8e7a 100644 --- a/source/auth/credentials/credentials.c +++ b/source/auth/credentials/credentials.c @@ -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); - cred->nt_hash = talloc(cred, struct samr_Password); - *cred->nt_hash = *nt_hash; + if (nt_hash) { + cred->nt_hash = talloc(cred, struct samr_Password); + *cred->nt_hash = *nt_hash; + } else { + cred->nt_hash = NULL; + } return True; } diff --git a/source/auth/credentials/credentials_files.c b/source/auth/credentials/credentials_files.c index a0ce4a2fd1f..006f242de90 100644 --- a/source/auth/credentials/credentials_files.c +++ b/source/auth/credentials/credentials_files.c @@ -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,13 +209,15 @@ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password"); - /* Local secrets are stored in secrets.ldb */ - ldb = secrets_db_connect(mem_ctx); if (!ldb) { - /* set anonymous as the fallback, if the machine account won't work */ - cli_credentials_set_anonymous(cred); - DEBUG(1, ("Could not open secrets.ldb\n")); - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + /* Local secrets are stored in secrets.ldb */ + ldb = secrets_db_connect(mem_ctx); + if (!ldb) { + /* set anonymous as the fallback, if the machine account won't work */ + cli_credentials_set_anonymous(cred); + DEBUG(1, ("Could not open secrets.ldb\n")); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } } /* search for the secret record */ @@ -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; -} - diff --git a/source/dsdb/samdb/ldb_modules/config.mk b/source/dsdb/samdb/ldb_modules/config.mk index 929d0bceada..b50e275ebfa 100644 --- a/source/dsdb/samdb/ldb_modules/config.mk +++ b/source/dsdb/samdb/ldb_modules/config.mk @@ -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 +################################################ + diff --git a/source/dsdb/samdb/ldb_modules/update_keytab.c b/source/dsdb/samdb/ldb_modules/update_keytab.c new file mode 100644 index 00000000000..411f8c98ef2 --- /dev/null +++ b/source/dsdb/samdb/ldb_modules/update_keytab.c @@ -0,0 +1,189 @@ +/* + ldb database library + + Copyright (C) Andrew Bartlett 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); +} diff --git a/source/scripting/ejs/smbcalls_creds.c b/source/scripting/ejs/smbcalls_creds.c index c6ad64933bc..6e2c87a9b31 100644 --- a/source/scripting/ejs/smbcalls_creds.c +++ b/source/scripting/ejs/smbcalls_creds.c @@ -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); } diff --git a/source/scripting/libjs/provision.js b/source/scripting/libjs/provision.js index 3e409c0dfb8..23f26a6b86b 100644 --- a/source/scripting/libjs/provision.js +++ b/source/scripting/libjs/provision.js @@ -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); diff --git a/source/setup/secrets.ldif b/source/setup/secrets.ldif index 1617cfb9bf4..ef5cb695d01 100644 --- a/source/setup/secrets.ldif +++ b/source/setup/secrets.ldif @@ -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 diff --git a/source/setup/secrets_init.ldif b/source/setup/secrets_init.ldif new file mode 100644 index 00000000000..9eda47e4636 --- /dev/null +++ b/source/setup/secrets_init.ldif @@ -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 + -- 2.11.4.GIT