From 69c2872dbd8e0ee53a47f13f5218ab069bf0187a Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Wed, 14 May 2014 21:42:45 -0400 Subject: [PATCH] kinit: get_switched_ccache Provide a new internal function called get_switched() to encapsulate the algorithm for selecting a credential cache when the selected ccache type supports switching. There is no change in behavior for UNIX which always calls krb5_cc_new_unique(). However, on Windows alternate behavior is provided when the ccache type is API or MSLSA. For the API ccache the default ccache name is stored in the Windows registry which is shared across all logon sessions belonging to a user. For users that are members of the Administrators group this includes both the UAC restricted and elevated sessions sharing the same desktop. It is very disconcerting when the elevated session obtains credentials for the same client principal as the restricted session and then all apps in the restricted session lose access to their credential cache. For Windows, the API credential caches are named after the principal that is stored within them. It provides for a better end user experience. For the MSLSA ccache tickets belonging to multiple principals are all stored within the MSLSA ccache. As a result, all attempts to switch ccache names default back to the one and only one name. Change-Id: I7865cd044cff01ff38ab107ec0961e42788fa073 --- kuser/kinit.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/kuser/kinit.c b/kuser/kinit.c index 1f6384306..5e6046dce 100644 --- a/kuser/kinit.c +++ b/kuser/kinit.c @@ -1137,6 +1137,59 @@ get_princ_kt(krb5_context context, free(def_realm); } +static krb5_error_code +get_switched_ccache(krb5_context context, + const char * type, + krb5_principal principal, + krb5_ccache *ccache) +{ + krb5_error_code ret; + +#ifdef _WIN32 + if (strcmp(type, "API") == 0) { + /* + * Windows stores the default ccache name in the + * registry which is shared across multiple logon + * sessions for the same user. The API credential + * cache provides a unique name space per logon + * session. Therefore there is no need to generate + * a unique ccache name. Instead use the principal + * name. This provides a friendlier user experience. + */ + char * unparsed_name; + char * cred_cache; + + ret = krb5_unparse_name(context, principal, + &unparsed_name); + if (ret) + krb5_err(context, 1, ret, + N_("unparsing principal name", "")); + + ret = asprintf(&cred_cache, "API:%s", unparsed_name); + krb5_free_unparsed_name(context, unparsed_name); + if (ret == -1 || cred_cache == NULL) + krb5_err(context, 1, ret, + N_("building credential cache name", "")); + + ret = krb5_cc_resolve(context, cred_cache, ccache); + free(cred_cache); + } else if (strcmp(type, "MSLSA") == 0) { + /* + * The Windows MSLSA cache when it is writeable + * stores tickets for multiple client principals + * in a single credential cache. + */ + ret = krb5_cc_resolve(context, "MSLSA:", ccache); + } else { + ret = krb5_cc_new_unique(context, type, NULL, ccache); + } +#else /* !_WIN32 */ + ret = krb5_cc_new_unique(context, type, NULL, ccache); +#endif /* _WIN32 */ + + return ret; +} + int main(int argc, char **argv) { @@ -1255,7 +1308,8 @@ main(int argc, char **argv) type = krb5_cc_get_type(context, ccache); if (krb5_cc_support_switch(context, type)) { krb5_cc_close(context, ccache); - ret = krb5_cc_new_unique(context, type, NULL, &ccache); + ret = get_switched_ccache(context, type, principal, + &ccache); } } }