From afaaf3d89d86bb33f42a63767b41f57c24238aed Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Wed, 10 Jul 2019 00:51:49 -0500 Subject: [PATCH] Add krb5_cc_configured_default_name() Refactor krb5_cc_set_default_name() by splitting out the part that looks for a configured default ccache name. This will allow one to check if a given ccache is a default ccache for a process ignoring KRB5CCNAME, which might prove useful in the kx509 client. --- lib/krb5/cache.c | 240 ++++++++++++++++++-------------- lib/krb5/context.c | 5 + lib/krb5/krb5_locl.h | 1 + lib/krb5/libkrb5-exports.def.in | 1 + lib/krb5/version-script.map | 1 + 5 files changed, 147 insertions(+), 101 deletions(-) diff --git a/lib/krb5/cache.c b/lib/krb5/cache.c index a206f75c2..5a7bf6758 100644 --- a/lib/krb5/cache.c +++ b/lib/krb5/cache.c @@ -508,117 +508,61 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_cc_set_default_name(krb5_context context, const char *name) { krb5_error_code ret = 0; - char *p = NULL, *exp_p = NULL; - int filepath; - const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE; + char *p = NULL; if (name == NULL) { - const char *e = NULL; + const char *e; - e = secure_getenv("KRB5CCNAME"); - if (e) { - p = strdup(e); - if (context->default_cc_name_env) - free(context->default_cc_name_env); - context->default_cc_name_env = strdup(e); - } + if ((e = secure_getenv("KRB5CCNAME"))) { + if ((p = strdup(e)) == NULL) + return krb5_enomem(context); -#ifdef _WIN32 - if (p == NULL) { - p = _krb5_get_default_cc_name_from_registry(context); + free(context->default_cc_name_env); + context->default_cc_name_env = p; + + if ((p = strdup(e)) == NULL) + return krb5_enomem(context); + + /* + * We're resetting the default ccache name. Recall that we got + * this from the environment, which might change. + */ + context->default_cc_name_set = 0; + } else if ((e = krb5_cc_configured_default_name(context))) { + if ((p = strdup(e)) == NULL) + return krb5_enomem(context); + + /* + * Since $KRB5CCNAME was not set, and since we got the default + * ccache name from configuration, we'll not want + * environment_changed() to return true to avoid re-doing the + * krb5_cc_configured_default_name() call unnecessarily. + * + * XXX Perhaps if we got the ccache name from the registry then + * we'd want to recheck it? If so we might need an indication + * from krb5_cc_configured_default_name() about that! + */ + context->default_cc_name_set = 1; } -#endif - if (p == NULL) { - e = krb5_config_get_string(context, NULL, "libdefaults", - "default_cc_name", NULL); - if (e) { - ret = _krb5_expand_default_cc_name(context, e, &p); - if (ret) - return ret; - } - } - if (p == NULL) { - /* MIT compatibility */ - e = krb5_config_get_string(context, NULL, "libdefaults", - "default_ccache_name", NULL); - if (e) { - ret = _krb5_expand_default_cc_name(context, e, &p); - if (ret) - return ret; - } - } - if (p == NULL) { - e = krb5_config_get_string(context, NULL, "libdefaults", - "default_cc_type", NULL); - if (e) { - ops = krb5_cc_get_prefix_ops(context, e); - if (ops == NULL) { - krb5_set_error_message(context, - KRB5_CC_UNKNOWN_TYPE, - "Credential cache type %s " - "is unknown", e); - return KRB5_CC_UNKNOWN_TYPE; - } - } - } -#ifdef _WIN32 - if (p == NULL) { - /* - * If the MSLSA ccache type has a principal name, - * use it as the default. - */ - krb5_ccache id; - ret = krb5_cc_resolve(context, "MSLSA:", &id); - if (ret == 0) { - krb5_principal princ; - ret = krb5_cc_get_principal(context, id, &princ); - if (ret == 0) { - krb5_free_principal(context, princ); - p = strdup("MSLSA:"); - } - krb5_cc_close(context, id); - } - } - if (p == NULL) { - /* - * If the API:krb5cc ccache can be resolved, - * use it as the default. - */ - krb5_ccache api_id; - ret = krb5_cc_resolve(context, "API:krb5cc", &api_id); - if (ret == 0) - krb5_cc_close(context, api_id); - } - /* Otherwise, fallback to the FILE ccache */ -#endif - if (p == NULL) { - ret = (*ops->get_default_name)(context, &p); - if (ret) - return ret; - } - context->default_cc_name_set = 0; } else { - p = strdup(name); - if (p == NULL) - return krb5_enomem(context); + int filepath = (strncmp("FILE:", name, 5) == 0 || + strncmp("DIR:", name, 4) == 0 || + strncmp("SCC:", name, 4) == 0); + + ret = _krb5_expand_path_tokens(context, name, filepath, &p); + if (ret) + return ret; + + /* + * Since the default ccache name was set explicitly, we won't want + * environment_changed() to return true until the default ccache name + * is reset. + */ context->default_cc_name_set = 1; } - filepath = (strncmp("FILE:", p, 5) == 0 - || strncmp("DIR:", p, 4) == 0 - || strncmp("SCC:", p, 4) == 0); - - ret = _krb5_expand_path_tokens(context, p, filepath, &exp_p); - free(p); - p = exp_p; - if (ret) - return ret; - - if (context->default_cc_name) - free(context->default_cc_name); - + free(context->default_cc_name); context->default_cc_name = p; - return 0; } @@ -641,6 +585,100 @@ krb5_cc_default_name(krb5_context context) return context->default_cc_name; } +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_cc_configured_default_name(krb5_context context) +{ + krb5_error_code ret = 0; +#ifdef _WIN32 + krb5_ccache id; +#endif + const char *cfg; + char *expanded; + + if (context->configured_default_cc_name) + return context->configured_default_cc_name; + +#ifdef _WIN32 + if ((expanded = _krb5_get_default_cc_name_from_registry(context))) + return context->configured_default_cc_name = expanded; +#endif + + /* If there's a configured default, expand the tokens and use it */ + cfg = krb5_config_get_string(context, NULL, "libdefaults", + "default_cc_name", NULL); + if (cfg == NULL) + cfg = krb5_config_get_string(context, NULL, "libdefaults", + "default_ccache_name", NULL); + if (cfg) { + ret = _krb5_expand_default_cc_name(context, cfg, &expanded); + if (ret) { + krb5_set_error_message(context, ret, + "token expansion failed for %s", cfg); + return NULL; + } + return context->configured_default_cc_name = expanded; + } + + /* Else try a configured default ccache type's default */ + cfg = krb5_config_get_string(context, NULL, "libdefaults", + "default_cc_type", NULL); + if (cfg) { + const krb5_cc_ops *ops; + + if ((ops = krb5_cc_get_prefix_ops(context, cfg)) == NULL) { + krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, + "unknown configured credential cache " + "type %s", cfg); + return NULL; + } + + /* The get_default_name() method expands any tokens */ + ret = (*ops->get_default_name)(context, &expanded); + if (ret) { + krb5_set_error_message(context, ret, "failed to find a default " + "ccache for default ccache type %s", cfg); + return NULL; + } + return context->configured_default_cc_name = expanded; + } +#ifdef _WIN32 + /* + * If the MSLSA ccache type has a principal name, + * use it as the default. + */ + ret = krb5_cc_resolve(context, "MSLSA:", &id); + if (ret == 0) { + krb5_principal princ; + ret = krb5_cc_get_principal(context, id, &princ); + krb5_cc_close(context, id); + if (ret == 0) { + krb5_free_principal(context, princ); + if ((expanded = strdup("MSLSA:"))) + return context->configured_default_cc_name = expanded; + krb5_enomem(context); + return NULL; + } + } + /* + * If the API:krb5cc ccache can be resolved, + * use it as the default. + */ + ret = krb5_cc_resolve(context, "API:krb5cc", &id); + krb5_cc_close(context, id); + if (ret == 0) { + if ((expanded = strdup("MSLSA:"))) + return context->configured_default_cc_name = expanded; + krb5_enomem(context); + return NULL; + } + /* Otherwise, fallback to the FILE ccache */ +#endif + ret = (*(KRB5_DEFAULT_CCTYPE)->get_default_name)(context, &expanded); + if (ret == 0) + return context->configured_default_cc_name = expanded; + return NULL; +} + /** * Open the default ccache in `id'. * diff --git a/lib/krb5/context.c b/lib/krb5/context.c index 64e844df6..56ffede87 100644 --- a/lib/krb5/context.c +++ b/lib/krb5/context.c @@ -239,6 +239,7 @@ init_context_from_config_file(krb5_context context) free(context->default_cc_name); context->default_cc_name = NULL; context->default_cc_name_set = 0; + context->configured_default_cc_name = NULL; tmp = secure_getenv("KRB5_TRACE"); s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL); @@ -551,6 +552,8 @@ krb5_copy_context(krb5_context context, krb5_context *out) p->default_cc_name = strdup(context->default_cc_name); if (context->default_cc_name_env) p->default_cc_name_env = strdup(context->default_cc_name_env); + if (context->configured_default_cc_name) + p->configured_default_cc_name = strdup(context->configured_default_cc_name); if (context->etypes) { ret = copy_etypes(context, context->etypes, &p->etypes); @@ -630,6 +633,8 @@ krb5_free_context(krb5_context context) free(context->default_cc_name); if (context->default_cc_name_env) free(context->default_cc_name_env); + if (context->configured_default_cc_name) + free(context->configured_default_cc_name); free(context->etypes); free(context->cfg_etypes); free(context->etypes_des); diff --git a/lib/krb5/krb5_locl.h b/lib/krb5/krb5_locl.h index 916ef6ed2..8bc273eb5 100644 --- a/lib/krb5/krb5_locl.h +++ b/lib/krb5/krb5_locl.h @@ -273,6 +273,7 @@ typedef struct krb5_context_data { krb5_addresses *ignore_addresses; char *default_cc_name; char *default_cc_name_env; + char *configured_default_cc_name; int default_cc_name_set; HEIMDAL_MUTEX mutex; /* protects error_string */ int large_msg_size; diff --git a/lib/krb5/libkrb5-exports.def.in b/lib/krb5/libkrb5-exports.def.in index 19f7cc2a7..cf06021d8 100644 --- a/lib/krb5/libkrb5-exports.def.in +++ b/lib/krb5/libkrb5-exports.def.in @@ -82,6 +82,7 @@ EXPORTS krb5_cc_cache_next krb5_cc_clear_mcred krb5_cc_close + krb5_cc_configured_default_name krb5_cc_copy_cache krb5_cc_copy_creds ;! krb5_cc_copy_match_f diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index 023f9bd68..e58baaed0 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -83,6 +83,7 @@ HEIMDAL_KRB5_2.0 { krb5_cc_cache_next; krb5_cc_clear_mcred; krb5_cc_close; + krb5_cc_configured_default_name; krb5_cc_copy_cache; krb5_cc_copy_match_f; krb5_cc_default;