summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/kcm/acquire.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/kcm/acquire.c')
-rw-r--r--crypto/heimdal/kcm/acquire.c531
1 files changed, 0 insertions, 531 deletions
diff --git a/crypto/heimdal/kcm/acquire.c b/crypto/heimdal/kcm/acquire.c
deleted file mode 100644
index 416881a..0000000
--- a/crypto/heimdal/kcm/acquire.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (c) 2005, PADL Software Pty Ltd.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of PADL Software nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "kcm_locl.h"
-
-RCSID("$Id: acquire.c 22118 2007-12-03 21:44:00Z lha $");
-
-static krb5_error_code
-change_pw_and_update_keytab(krb5_context context, kcm_ccache ccache);
-
-/*
- * Get a new ticket using a keytab/cached key and swap it into
- * an existing redentials cache
- */
-
-krb5_error_code
-kcm_ccache_acquire(krb5_context context,
- kcm_ccache ccache,
- krb5_creds **credp)
-{
- krb5_error_code ret = 0;
- krb5_creds cred;
- krb5_const_realm realm;
- krb5_get_init_creds_opt opt;
- krb5_ccache_data ccdata;
- char *in_tkt_service = NULL;
- int done = 0;
-
- memset(&cred, 0, sizeof(cred));
-
- KCM_ASSERT_VALID(ccache);
-
- /* We need a cached key or keytab to acquire credentials */
- if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) {
- if (ccache->key.keyblock.keyvalue.length == 0)
- krb5_abortx(context,
- "kcm_ccache_acquire: KCM_FLAGS_USE_CACHED_KEY without key");
- } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) {
- if (ccache->key.keytab == NULL)
- krb5_abortx(context,
- "kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab");
- } else {
- kcm_log(0, "Cannot acquire initial credentials for cache %s without key",
- ccache->name);
- return KRB5_FCC_INTERNAL;
- }
-
- HEIMDAL_MUTEX_lock(&ccache->mutex);
-
- /* Fake up an internal ccache */
- kcm_internal_ccache(context, ccache, &ccdata);
-
- /* Now, actually acquire the creds */
- if (ccache->server != NULL) {
- ret = krb5_unparse_name(context, ccache->server, &in_tkt_service);
- if (ret) {
- kcm_log(0, "Failed to unparse service principal name for cache %s: %s",
- ccache->name, krb5_get_err_text(context, ret));
- return ret;
- }
- }
-
- realm = krb5_principal_get_realm(context, ccache->client);
-
- krb5_get_init_creds_opt_init(&opt);
- krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, &opt);
- if (ccache->tkt_life != 0)
- krb5_get_init_creds_opt_set_tkt_life(&opt, ccache->tkt_life);
- if (ccache->renew_life != 0)
- krb5_get_init_creds_opt_set_renew_life(&opt, ccache->renew_life);
-
- if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) {
- ret = krb5_get_init_creds_keyblock(context,
- &cred,
- ccache->client,
- &ccache->key.keyblock,
- 0,
- in_tkt_service,
- &opt);
- } else {
- /* loosely based on lib/krb5/init_creds_pw.c */
- while (!done) {
- ret = krb5_get_init_creds_keytab(context,
- &cred,
- ccache->client,
- ccache->key.keytab,
- 0,
- in_tkt_service,
- &opt);
- switch (ret) {
- case KRB5KDC_ERR_KEY_EXPIRED:
- if (in_tkt_service != NULL &&
- strcmp(in_tkt_service, "kadmin/changepw") == 0) {
- goto out;
- }
-
- ret = change_pw_and_update_keytab(context, ccache);
- if (ret)
- goto out;
- break;
- case 0:
- default:
- done = 1;
- break;
- }
- }
- }
-
- if (ret) {
- kcm_log(0, "Failed to acquire credentials for cache %s: %s",
- ccache->name, krb5_get_err_text(context, ret));
- if (in_tkt_service != NULL)
- free(in_tkt_service);
- goto out;
- }
-
- if (in_tkt_service != NULL)
- free(in_tkt_service);
-
- /* Swap them in */
- kcm_ccache_remove_creds_internal(context, ccache);
-
- ret = kcm_ccache_store_cred_internal(context, ccache, &cred, 0, credp);
- if (ret) {
- kcm_log(0, "Failed to store credentials for cache %s: %s",
- ccache->name, krb5_get_err_text(context, ret));
- krb5_free_cred_contents(context, &cred);
- goto out;
- }
-
-out:
- HEIMDAL_MUTEX_unlock(&ccache->mutex);
-
- return ret;
-}
-
-static krb5_error_code
-change_pw(krb5_context context,
- kcm_ccache ccache,
- char *cpn,
- char *newpw)
-{
- krb5_error_code ret;
- krb5_creds cpw_cred;
- int result_code;
- krb5_data result_code_string;
- krb5_data result_string;
- krb5_get_init_creds_opt options;
-
- memset(&cpw_cred, 0, sizeof(cpw_cred));
-
- krb5_get_init_creds_opt_init(&options);
- krb5_get_init_creds_opt_set_tkt_life(&options, 60);
- krb5_get_init_creds_opt_set_forwardable(&options, FALSE);
- krb5_get_init_creds_opt_set_proxiable(&options, FALSE);
-
- krb5_data_zero(&result_code_string);
- krb5_data_zero(&result_string);
-
- ret = krb5_get_init_creds_keytab(context,
- &cpw_cred,
- ccache->client,
- ccache->key.keytab,
- 0,
- "kadmin/changepw",
- &options);
- if (ret) {
- kcm_log(0, "Failed to acquire password change credentials "
- "for principal %s: %s",
- cpn, krb5_get_err_text(context, ret));
- goto out;
- }
-
- ret = krb5_set_password(context,
- &cpw_cred,
- newpw,
- ccache->client,
- &result_code,
- &result_code_string,
- &result_string);
- if (ret) {
- kcm_log(0, "Failed to change password for principal %s: %s",
- cpn, krb5_get_err_text(context, ret));
- goto out;
- }
-
- if (result_code) {
- kcm_log(0, "Failed to change password for principal %s: %.*s",
- cpn,
- (int)result_string.length,
- result_string.length > 0 ? (char *)result_string.data : "");
- goto out;
- }
-
-out:
- krb5_data_free(&result_string);
- krb5_data_free(&result_code_string);
- krb5_free_cred_contents(context, &cpw_cred);
-
- return ret;
-}
-
-struct kcm_keyseed_data {
- krb5_salt salt;
- const char *password;
-};
-
-static krb5_error_code
-kcm_password_key_proc(krb5_context context,
- krb5_enctype etype,
- krb5_salt salt,
- krb5_const_pointer keyseed,
- krb5_keyblock **key)
-{
- krb5_error_code ret;
- struct kcm_keyseed_data *s = (struct kcm_keyseed_data *)keyseed;
-
- /* we may be called multiple times */
- krb5_free_salt(context, s->salt);
- krb5_data_zero(&s->salt.saltvalue);
-
- /* stash the salt */
- s->salt.salttype = salt.salttype;
-
- ret = krb5_data_copy(&s->salt.saltvalue,
- salt.saltvalue.data,
- salt.saltvalue.length);
- if (ret)
- return ret;
-
- *key = (krb5_keyblock *)malloc(sizeof(**key));
- if (*key == NULL) {
- return ENOMEM;
- }
-
- ret = krb5_string_to_key_salt(context, etype, s->password,
- s->salt, *key);
- if (ret) {
- free(*key);
- *key = NULL;
- }
-
- return ret;
-}
-
-static krb5_error_code
-get_salt_and_kvno(krb5_context context,
- kcm_ccache ccache,
- krb5_enctype *etypes,
- char *cpn,
- char *newpw,
- krb5_salt *salt,
- unsigned *kvno)
-{
- krb5_error_code ret;
- krb5_creds creds;
- krb5_ccache_data ccdata;
- krb5_flags options = 0;
- krb5_kdc_rep reply;
- struct kcm_keyseed_data s;
-
- memset(&creds, 0, sizeof(creds));
- memset(&reply, 0, sizeof(reply));
-
- s.password = NULL;
- s.salt.salttype = (int)ETYPE_NULL;
- krb5_data_zero(&s.salt.saltvalue);
-
- *kvno = 0;
- kcm_internal_ccache(context, ccache, &ccdata);
- s.password = newpw;
-
- /* Do an AS-REQ to determine salt and key version number */
- ret = krb5_copy_principal(context, ccache->client, &creds.client);
- if (ret)
- return ret;
-
- /* Yes, get a ticket to ourselves */
- ret = krb5_copy_principal(context, ccache->client, &creds.server);
- if (ret) {
- krb5_free_principal(context, creds.client);
- return ret;
- }
-
- ret = krb5_get_in_tkt(context,
- options,
- NULL,
- etypes,
- NULL,
- kcm_password_key_proc,
- &s,
- NULL,
- NULL,
- &creds,
- &ccdata,
- &reply);
- if (ret) {
- kcm_log(0, "Failed to get self ticket for principal %s: %s",
- cpn, krb5_get_err_text(context, ret));
- krb5_free_salt(context, s.salt);
- } else {
- *salt = s.salt; /* retrieve stashed salt */
- if (reply.kdc_rep.enc_part.kvno != NULL)
- *kvno = *(reply.kdc_rep.enc_part.kvno);
- }
- /* ccache may have been modified but it will get trashed anyway */
-
- krb5_free_cred_contents(context, &creds);
- krb5_free_kdc_rep(context, &reply);
-
- return ret;
-}
-
-static krb5_error_code
-update_keytab_entry(krb5_context context,
- kcm_ccache ccache,
- krb5_enctype etype,
- char *cpn,
- char *spn,
- char *newpw,
- krb5_salt salt,
- unsigned kvno)
-{
- krb5_error_code ret;
- krb5_keytab_entry entry;
- krb5_data pw;
-
- memset(&entry, 0, sizeof(entry));
-
- pw.data = (char *)newpw;
- pw.length = strlen(newpw);
-
- ret = krb5_string_to_key_data_salt(context, etype, pw,
- salt, &entry.keyblock);
- if (ret) {
- kcm_log(0, "String to key conversion failed for principal %s "
- "and etype %d: %s",
- cpn, etype, krb5_get_err_text(context, ret));
- return ret;
- }
-
- if (spn == NULL) {
- ret = krb5_copy_principal(context, ccache->client,
- &entry.principal);
- if (ret) {
- kcm_log(0, "Failed to copy principal name %s: %s",
- cpn, krb5_get_err_text(context, ret));
- return ret;
- }
- } else {
- ret = krb5_parse_name(context, spn, &entry.principal);
- if (ret) {
- kcm_log(0, "Failed to parse SPN alias %s: %s",
- spn, krb5_get_err_text(context, ret));
- return ret;
- }
- }
-
- entry.vno = kvno;
- entry.timestamp = time(NULL);
-
- ret = krb5_kt_add_entry(context, ccache->key.keytab, &entry);
- if (ret) {
- kcm_log(0, "Failed to update keytab for principal %s "
- "and etype %d: %s",
- cpn, etype, krb5_get_err_text(context, ret));
- }
-
- krb5_kt_free_entry(context, &entry);
-
- return ret;
-}
-
-static krb5_error_code
-update_keytab_entries(krb5_context context,
- kcm_ccache ccache,
- krb5_enctype *etypes,
- char *cpn,
- char *spn,
- char *newpw,
- krb5_salt salt,
- unsigned kvno)
-{
- krb5_error_code ret = 0;
- int i;
-
- for (i = 0; etypes[i] != ETYPE_NULL; i++) {
- ret = update_keytab_entry(context, ccache, etypes[i],
- cpn, spn, newpw, salt, kvno);
- if (ret)
- break;
- }
-
- return ret;
-}
-
-static void
-generate_random_pw(krb5_context context,
- char *buf,
- size_t bufsiz)
-{
- unsigned char x[512], *p;
- size_t i;
-
- memset(x, 0, sizeof(x));
- krb5_generate_random_block(x, sizeof(x));
- p = x;
-
- for (i = 0; i < bufsiz; i++) {
- while (isprint(*p) == 0)
- p++;
-
- if (p - x >= sizeof(x)) {
- krb5_generate_random_block(x, sizeof(x));
- p = x;
- }
- buf[i] = (char)*p++;
- }
- buf[bufsiz - 1] = '\0';
- memset(x, 0, sizeof(x));
-}
-
-static krb5_error_code
-change_pw_and_update_keytab(krb5_context context,
- kcm_ccache ccache)
-{
- char newpw[121];
- krb5_error_code ret;
- unsigned kvno;
- krb5_salt salt;
- krb5_enctype *etypes = NULL;
- int i;
- char *cpn = NULL;
- char **spns = NULL;
-
- krb5_data_zero(&salt.saltvalue);
-
- ret = krb5_unparse_name(context, ccache->client, &cpn);
- if (ret) {
- kcm_log(0, "Failed to unparse name: %s",
- krb5_get_err_text(context, ret));
- goto out;
- }
-
- ret = krb5_get_default_in_tkt_etypes(context, &etypes);
- if (ret) {
- kcm_log(0, "Failed to determine default encryption types: %s",
- krb5_get_err_text(context, ret));
- goto out;
- }
-
- /* Generate a random password (there is no set keys protocol) */
- generate_random_pw(context, newpw, sizeof(newpw));
-
- /* Change it */
- ret = change_pw(context, ccache, cpn, newpw);
- if (ret)
- goto out;
-
- /* Do an AS-REQ to determine salt and key version number */
- ret = get_salt_and_kvno(context, ccache, etypes, cpn, newpw,
- &salt, &kvno);
- if (ret) {
- kcm_log(0, "Failed to determine salting principal for principal %s: %s",
- cpn, krb5_get_err_text(context, ret));
- goto out;
- }
-
- /* Add canonical name */
- ret = update_keytab_entries(context, ccache, etypes, cpn,
- NULL, newpw, salt, kvno);
- if (ret)
- goto out;
-
- /* Add SPN aliases, if any */
- spns = krb5_config_get_strings(context, NULL, "kcm",
- "system_ccache", "spn_aliases", NULL);
- if (spns != NULL) {
- for (i = 0; spns[i] != NULL; i++) {
- ret = update_keytab_entries(context, ccache, etypes, cpn,
- spns[i], newpw, salt, kvno);
- if (ret)
- goto out;
- }
- }
-
- kcm_log(0, "Changed expired password for principal %s in cache %s",
- cpn, ccache->name);
-
-out:
- if (cpn != NULL)
- free(cpn);
- if (spns != NULL)
- krb5_config_free_strings(spns);
- if (etypes != NULL)
- free(etypes);
- krb5_free_salt(context, salt);
- memset(newpw, 0, sizeof(newpw));
-
- return ret;
-}
-
OpenPOWER on IntegriCloud