159769Sgrog/*
259769Sgrog * Copyright (c) 2005, PADL Software Pty Ltd.
324424Swosch * All rights reserved.
424424Swosch *
524424Swosch * Redistribution and use in source and binary forms, with or without
624424Swosch * modification, are permitted provided that the following conditions
724424Swosch * are met:
824424Swosch *
924424Swosch * 1. Redistributions of source code must retain the above copyright
1024424Swosch *    notice, this list of conditions and the following disclaimer.
1124424Swosch *
1224424Swosch * 2. Redistributions in binary form must reproduce the above copyright
1324424Swosch *    notice, this list of conditions and the following disclaimer in the
1424424Swosch *    documentation and/or other materials provided with the distribution.
1542704Swosch *
1642704Swosch * 3. Neither the name of PADL Software nor the names of its contributors
1742704Swosch *    may be used to endorse or promote products derived from this software
1824424Swosch *    without specific prior written permission.
1942704Swosch *
2042704Swosch * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
2142704Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2242704Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2342704Swosch * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
2442704Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2542704Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2642704Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2742704Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2842704Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2942704Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3059769Sgrog * SUCH DAMAGE.
3159769Sgrog */
3259769Sgrog
3359769Sgrog#include "kcm_locl.h"
3459769Sgrog
3559769Sgrog/*
3659769Sgrog * Get a new ticket using a keytab/cached key and swap it into
3759769Sgrog * an existing redentials cache
3859769Sgrog */
3924424Swosch
4042704Swoschkrb5_error_code
4124424Swoschkcm_ccache_acquire(krb5_context context,
4242704Swosch		   kcm_ccache ccache,
4324424Swosch		   krb5_creds **credp)
4442704Swosch{
4524424Swosch    krb5_error_code ret = 0;
4624424Swosch    krb5_creds cred;
4724424Swosch    krb5_const_realm realm;
4842704Swosch    krb5_get_init_creds_opt *opt = NULL;
4925031Swosch    krb5_ccache_data ccdata;
5059156Swosch    char *in_tkt_service = NULL;
5125031Swosch
5225031Swosch    memset(&cred, 0, sizeof(cred));
5324424Swosch
5424424Swosch    KCM_ASSERT_VALID(ccache);
5524424Swosch
5624424Swosch    /* We need a cached key or keytab to acquire credentials */
5771231Sitojun    if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) {
5824424Swosch	if (ccache->key.keyblock.keyvalue.length == 0)
5971231Sitojun	    krb5_abortx(context,
6025031Swosch			"kcm_ccache_acquire: KCM_FLAGS_USE_CACHED_KEY without key");
6171231Sitojun    } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) {
6224424Swosch	if (ccache->key.keytab == NULL)
6325031Swosch	    krb5_abortx(context,
6425031Swosch			"kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab");
6571231Sitojun    } else {
6625031Swosch	kcm_log(0, "Cannot acquire initial credentials for cache %s without key",
6771231Sitojun		ccache->name);
6870110Swosch	return KRB5_FCC_INTERNAL;
6970110Swosch    }
7070110Swosch
7170110Swosch    HEIMDAL_MUTEX_lock(&ccache->mutex);
7270110Swosch
7370110Swosch    /* Fake up an internal ccache */
7470110Swosch    kcm_internal_ccache(context, ccache, &ccdata);
7570110Swosch
7670110Swosch    /* Now, actually acquire the creds */
7770110Swosch    if (ccache->server != NULL) {
7870110Swosch	ret = krb5_unparse_name(context, ccache->server, &in_tkt_service);
7980675Sasmodai	if (ret) {
8080675Sasmodai	    kcm_log(0, "Failed to unparse service principal name for cache %s: %s",
8180675Sasmodai		    ccache->name, krb5_get_err_text(context, ret));
8280675Sasmodai	    return ret;
8380675Sasmodai	}
8480675Sasmodai    }
8580675Sasmodai
8680675Sasmodai    realm = krb5_principal_get_realm(context, ccache->client);
8780675Sasmodai
8880675Sasmodai    ret = krb5_get_init_creds_opt_alloc(context, &opt);
8980675Sasmodai    if (ret)
9080675Sasmodai	goto out;
9180675Sasmodai    krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, opt);
9280675Sasmodai    if (ccache->tkt_life != 0)
9380675Sasmodai	krb5_get_init_creds_opt_set_tkt_life(opt, ccache->tkt_life);
9480675Sasmodai    if (ccache->renew_life != 0)
9580675Sasmodai	krb5_get_init_creds_opt_set_renew_life(opt, ccache->renew_life);
9680675Sasmodai
9780675Sasmodai    if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) {
9880675Sasmodai	ret = krb5_get_init_creds_keyblock(context,
9980675Sasmodai					   &cred,
10080675Sasmodai					   ccache->client,
10180675Sasmodai					   &ccache->key.keyblock,
10280675Sasmodai					   0,
10380675Sasmodai					   in_tkt_service,
10480675Sasmodai					   opt);
10580675Sasmodai    } else {
10680675Sasmodai	/* loosely based on lib/krb5/init_creds_pw.c */
10780675Sasmodai	ret = krb5_get_init_creds_keytab(context,
10880675Sasmodai					 &cred,
10980675Sasmodai					 ccache->client,
11080675Sasmodai					 ccache->key.keytab,
11180675Sasmodai					 0,
11280675Sasmodai					 in_tkt_service,
11380675Sasmodai					 opt);
11480675Sasmodai    }
11580675Sasmodai
11680675Sasmodai    if (ret) {
11780675Sasmodai	kcm_log(0, "Failed to acquire credentials for cache %s: %s",
11880675Sasmodai		ccache->name, krb5_get_err_text(context, ret));
11980675Sasmodai	if (in_tkt_service != NULL)
12080675Sasmodai	    free(in_tkt_service);
12180675Sasmodai	goto out;
12280675Sasmodai    }
12380675Sasmodai
12480675Sasmodai    if (in_tkt_service != NULL)
12580675Sasmodai	free(in_tkt_service);
12680675Sasmodai
12780675Sasmodai    /* Swap them in */
12880675Sasmodai    kcm_ccache_remove_creds_internal(context, ccache);
12980675Sasmodai
13080675Sasmodai    ret = kcm_ccache_store_cred_internal(context, ccache, &cred, 0, credp);
13180675Sasmodai    if (ret) {
13280675Sasmodai	kcm_log(0, "Failed to store credentials for cache %s: %s",
13380675Sasmodai		ccache->name, krb5_get_err_text(context, ret));
13480675Sasmodai	krb5_free_cred_contents(context, &cred);
13580675Sasmodai	goto out;
13680675Sasmodai    }
13780675Sasmodai
138101401Swoschout:
13980675Sasmodai    if (opt)
14087200Swosch	krb5_get_init_creds_opt_free(context, opt);
14187200Swosch
14287200Swosch    HEIMDAL_MUTEX_unlock(&ccache->mutex);
14380675Sasmodai
144104772Smaxim    return ret;
145104772Smaxim}
146104772Smaxim