/* simulate a kinit, putting the tgt in the given credentials cache. Orignally by [email protected] This version is built to use a keyblock, rather than needing the original password. */ int kerberos_kinit_keyblock_cc(krb5_context ctx, krb5_ccache cc, krb5_principal principal, krb5_keyblock *keyblock, time_t *expire_time, time_t *kdc_time) { krb5_error_code code = 0; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, &options); if ((code = krb5_get_init_creds_keyblock(ctx, &my_creds, principal, keyblock, 0, NULL, &options))) { return code; } if ((code = krb5_cc_initialize(ctx, cc, principal))) { krb5_free_cred_contents(ctx, &my_creds); return code; } if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) { krb5_free_cred_contents(ctx, &my_creds); return code; } if (expire_time) { *expire_time = (time_t) my_creds.times.endtime; } if (kdc_time) { *kdc_time = (time_t) my_creds.times.starttime; } krb5_free_cred_contents(ctx, &my_creds); return 0; }
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; }