From 629eeb811a411d703fd6c72b7fcab74967c7a762 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Wed, 25 Mar 2015 15:09:44 -0500 Subject: [PATCH] Add start_realm cc config --- lib/krb5/cache.c | 43 +++++++++++++++++++++++++++++++++++++++++-- lib/krb5/get_cred.c | 31 ++++++++++++++++++++++++------- lib/krb5/krb5.h | 1 + 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/lib/krb5/cache.c b/lib/krb5/cache.c index 6c0019114..6aeb8af6f 100644 --- a/lib/krb5/cache.c +++ b/lib/krb5/cache.c @@ -639,7 +639,12 @@ krb5_cc_initialize(krb5_context context, krb5_ccache id, krb5_principal primary_principal) { - return (*id->ops->init)(context, id, primary_principal); + krb5_error_code ret; + + ret = (*id->ops->init)(context, id, primary_principal); + if (ret == 0) + id->initialized = 1; + return ret; } @@ -696,7 +701,36 @@ krb5_cc_store_cred(krb5_context context, krb5_ccache id, krb5_creds *creds) { - return (*id->ops->store)(context, id, creds); + krb5_error_code ret; + krb5_data realm; + + ret = (*id->ops->store)(context, id, creds); + + /* Look for and mark the first root TGT's realm as the start realm */ + if (ret == 0 && id->initialized && + !krb5_is_config_principal(context, creds->server) && + krb5_principal_is_root_krbtgt(context, creds->server)) { + + id->initialized = 1; + realm.length = strlen(creds->server->realm) + 1; + realm.data = creds->server->realm; + (void) krb5_cc_set_config(context, id, NULL, "start_realm", &realm); + } else if (ret == 0 && id->initialized && + krb5_is_config_principal(context, creds->server) && + strcmp(creds->server->name.name_string.val[1], "start_realm") == 0) { + + /* + * But if the caller is storing a start_realm ccconfig, then + * stop looking for root TGTs to mark as the start_realm. + * + * By honoring any start_realm cc config stored, we interop + * both, with ccache implementations that don't preserve + * insertion order, and Kerberos implementations that store this + * cc config before the TGT. + */ + id->initialized = 1; + } + return ret; } /** @@ -1679,6 +1713,11 @@ krb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t) /** * If we find a krbtgt in the cache, use that as the lifespan. */ + /* + * FIXME We should try to find the start_realm cc config and + * look for root TGTs for that realm instead of any random + * (first) root TGT. + */ if (krb5_principal_is_root_krbtgt(context, cred.server)) { if (now < cred.times.endtime) endtime = cred.times.endtime; diff --git a/lib/krb5/get_cred.c b/lib/krb5/get_cred.c index 713baa388..96ae5cf01 100644 --- a/lib/krb5/get_cred.c +++ b/lib/krb5/get_cred.c @@ -951,7 +951,8 @@ get_cred_kdc_referral(krb5_context context, Ticket *second_ticket, krb5_creds **out_creds) { - krb5_const_realm client_realm; + krb5_realm start_realm = NULL; + krb5_data config_start_realm; krb5_error_code ret; krb5_creds tgt, referral, ticket; krb5_creds **referral_tgts = NULL; /* used for loop detection */ @@ -972,33 +973,49 @@ get_cred_kdc_referral(krb5_context context, *out_creds = NULL; - client_realm = krb5_principal_get_realm(context, in_creds->client); + + ret = krb5_cc_get_config(context, ccache, NULL, "start_realm", &config_start_realm); + if (ret == 0) { + start_realm = strndup(config_start_realm.data, config_start_realm.length); + krb5_data_free(&config_start_realm); + } else { + start_realm = strdup(krb5_principal_get_realm(context, in_creds->client)); + } + if (start_realm == NULL) + return krb5_enomem(context); /* find tgt for the clients base realm */ { krb5_principal tgtname; ret = krb5_make_principal(context, &tgtname, - client_realm, + start_realm, KRB5_TGS_NAME, - client_realm, + start_realm, NULL); - if(ret) + if (ret) { + free(start_realm); return ret; + } ret = find_cred(context, ccache, tgtname, NULL, &tgt); krb5_free_principal(context, tgtname); - if (ret) + if (ret) { + free(start_realm); return ret; + } } referral = *in_creds; ret = krb5_copy_principal(context, in_creds->server, &referral.server); if (ret) { krb5_free_cred_contents(context, &tgt); + free(start_realm); return ret; } - ret = krb5_principal_set_realm(context, referral.server, client_realm); + ret = krb5_principal_set_realm(context, referral.server, start_realm); + free(start_realm); + start_realm = NULL; if (ret) { krb5_free_cred_contents(context, &tgt); krb5_free_principal(context, referral.server); diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 2eb3afa8e..199eed983 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -381,6 +381,7 @@ typedef struct krb5_cccol_cursor_data *krb5_cccol_cursor; typedef struct krb5_ccache_data { const struct krb5_cc_ops *ops; krb5_data data; + int initialized; /* if non-zero: krb5_cc_initialize() called, now empty */ }krb5_ccache_data; typedef struct krb5_ccache_data *krb5_ccache; -- 2.11.4.GIT