From f784a37909b68b7dfc1eed8c3a0e014639c90e45 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Mon, 5 Sep 2011 16:26:37 +0000 Subject: [PATCH] Add new cache collection APIs * krb5_cc_get_full_name retrieves the full type:name of a cache. * krb5_cc_switch makes a cache the primary cache. * krb5_cc_cache_match searches the collection for a client principal. * krb5_free_string releases a string (for the krb5_cc_get_full_name result). All of these are from Heimdal except for krb5_free_string (Heimdal uses krb5_xfree). ticket: 6954 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25155 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/k5-int.h | 1 + src/include/krb5/krb5.hin | 69 ++++++++++++++++++++++++++++++++ src/lib/krb5/ccache/cc_dir.c | 25 ++++++++++++ src/lib/krb5/ccache/cc_file.c | 2 + src/lib/krb5/ccache/cc_keyring.c | 2 + src/lib/krb5/ccache/cc_memory.c | 1 + src/lib/krb5/ccache/cc_mslsa.c | 1 + src/lib/krb5/ccache/ccbase.c | 10 +++++ src/lib/krb5/ccache/cccursor.c | 44 ++++++++++++++++++++ src/lib/krb5/ccache/ccfns.c | 22 ++++++++++ src/lib/krb5/krb/kfree.c | 6 +++ src/lib/krb5/libkrb5.exports | 5 +++ src/lib/krb5_32.def | 5 +++ 13 files changed, 193 insertions(+) diff --git a/src/include/k5-int.h b/src/include/k5-int.h index c153a7e51..0e82ce8a9 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -2367,6 +2367,7 @@ struct _krb5_cc_ops { krb5_timestamp *); krb5_error_code (KRB5_CALLCONV *lock)(krb5_context, krb5_ccache); krb5_error_code (KRB5_CALLCONV *unlock)(krb5_context, krb5_ccache); + krb5_error_code (KRB5_CALLCONV *switch_to)(krb5_context, krb5_ccache); }; extern const krb5_cc_ops *krb5_cc_dfl_ops; diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index e594035bb..d1a7c83c6 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -2285,6 +2285,18 @@ typedef struct _krb5_cccol_cursor *krb5_cccol_cursor; const char * KRB5_CALLCONV krb5_cc_get_name(krb5_context context, krb5_ccache cache); +/* + * Retrieve the full name of a credential cache. + * + * @param [in] context Library context + * @param [in] cache Credential cache handle + * @param [out] fullname_out Full name of cache + * + */ +krb5_error_code KRB5_CALLCONV +krb5_cc_get_full_name(krb5_context context, krb5_ccache cache, + char **fullname_out); + #if KRB5_DEPRECATED krb5_error_code KRB5_CALLCONV krb5_cc_gen_new(krb5_context context, krb5_ccache *cache); @@ -4393,6 +4405,54 @@ krb5_cc_set_config(krb5_context context, krb5_ccache id, krb5_boolean KRB5_CALLCONV krb5_is_config_principal(krb5_context context, krb5_const_principal principal); +/** + * Make a credential cache the primary cache for its collection. + * + * @param [in] context Library context + * @param [in] cache Credential cache handle + * + * If the type of @a cache supports it, set @a cache to be the primary + * credential cache for the collection it belongs to. + * + * @retval + * 0 Success, or the type of @a cache doesn't support switching + * @return + * Kerberos error codes + */ +krb5_error_code KRB5_CALLCONV +krb5_cc_switch(krb5_context context, krb5_ccache cache); + +/** + * Determine whether a credential cache type supports switching. + * + * @param [in] context Library context + * @param [in] type Credential cache type + * + * @retval @c TRUE if @a type supports switching + * @retval @a FALSE if it does not or is not a valid credential cache type. + */ +krb5_boolean KRB5_CALLCONV +krb5_cc_support_switch(krb5_context context, const char *type); + +/** + * Find a credential cache with a specified client principal. + * + * @param [in] context Library context + * @param [in] client Client principal + * @param [out] cache_out Credential cache handle + * + * Find a cache within the collection whose default principal is @a client. + * Use @a krb5_cc_close to close @a ccache when it is no longer needed. + * + * @retval 0 Success + * @retval KRB5_CC_NOTFOUND + * + * @sa krb5_cccol_cursor_new + */ +krb5_error_code KRB5_CALLCONV +krb5_cc_cache_match(krb5_context context, krb5_principal client, + krb5_ccache *cache_out); + /* krb5_free.c */ /** * Free the storage assigned to a principal. @@ -4570,6 +4630,15 @@ krb5_free_data_contents(krb5_context context, krb5_data *val); void KRB5_CALLCONV krb5_free_unparsed_name(krb5_context context, char *val); +/** + * Free a string allocated by a krb5 function. + * + * @param [in] context Library context + * @param [in] val String to be freed + */ +void KRB5_CALLCONV +krb5_free_string(krb5_context context, char *val); + /** * Free an array of checksum types. * diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c index 1f32c389a..6cd192a71 100644 --- a/src/lib/krb5/ccache/cc_dir.c +++ b/src/lib/krb5/ccache/cc_dir.c @@ -672,6 +672,30 @@ dcc_unlock(krb5_context context, krb5_ccache cache) return krb5_fcc_ops.unlock(context, data->fcc); } +static krb5_error_code KRB5_CALLCONV +dcc_switch_to(krb5_context context, krb5_ccache cache) +{ + dcc_data *data = cache->data; + char *primary_path = NULL, *dirname = NULL, *filename = NULL; + krb5_error_code ret; + + ret = split_path(context, data->residual + 1, &dirname, &filename); + if (ret) + return ret; + + ret = primary_pathname(dirname, &primary_path); + if (ret) + goto cleanup; + + ret = write_primary_file(primary_path, filename); + +cleanup: + free(primary_path); + free(dirname); + free(filename); + return ret; +} + const krb5_cc_ops krb5_dcc_ops = { 0, "DIR", @@ -698,6 +722,7 @@ const krb5_cc_ops krb5_dcc_ops = { NULL, /* wasdefault */ dcc_lock, dcc_unlock, + dcc_switch_to, }; #endif /* not _WIN32 */ diff --git a/src/lib/krb5/ccache/cc_file.c b/src/lib/krb5/ccache/cc_file.c index aee8a8396..459930932 100644 --- a/src/lib/krb5/ccache/cc_file.c +++ b/src/lib/krb5/ccache/cc_file.c @@ -2557,6 +2557,7 @@ const krb5_cc_ops krb5_fcc_ops = { NULL, /* wasdefault */ krb5_fcc_lock, krb5_fcc_unlock, + NULL, /* switch_to */ }; #if defined(_WIN32) @@ -2626,4 +2627,5 @@ const krb5_cc_ops krb5_cc_file_ops = { NULL, /* wasdefault */ krb5_fcc_lock, krb5_fcc_unlock, + NULL, /* switch_to */ }; diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c index 2c77c3cda..fd1bcec38 100644 --- a/src/lib/krb5/ccache/cc_keyring.c +++ b/src/lib/krb5/ccache/cc_keyring.c @@ -2073,6 +2073,7 @@ const krb5_cc_ops krb5_krcc_ops = { NULL, /* wasdefault */ krb5_krcc_lock, krb5_krcc_unlock, + NULL, /* switch_to */ }; #else /* !USE_KEYRING_CCACHE */ @@ -2106,5 +2107,6 @@ const krb5_cc_ops krb5_krcc_ops = { NULL, NULL, NULL, + NULL, }; #endif /* USE_KEYRING_CCACHE */ diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c index 5ce6a0e6c..07d926144 100644 --- a/src/lib/krb5/ccache/cc_memory.c +++ b/src/lib/krb5/ccache/cc_memory.c @@ -827,4 +827,5 @@ const krb5_cc_ops krb5_mcc_ops = { NULL, /* wasdefault */ krb5_mcc_lock, krb5_mcc_unlock, + NULL, /* switch_to */ }; diff --git a/src/lib/krb5/ccache/cc_mslsa.c b/src/lib/krb5/ccache/cc_mslsa.c index 9727b4fea..600478a15 100644 --- a/src/lib/krb5/ccache/cc_mslsa.c +++ b/src/lib/krb5/ccache/cc_mslsa.c @@ -2758,5 +2758,6 @@ const krb5_cc_ops krb5_lcc_ops = { NULL, NULL, NULL, + NULL, }; #endif /* _WIN32 */ diff --git a/src/lib/krb5/ccache/ccbase.c b/src/lib/krb5/ccache/ccbase.c index b330784c9..a1fd3aa83 100644 --- a/src/lib/krb5/ccache/ccbase.c +++ b/src/lib/krb5/ccache/ccbase.c @@ -418,6 +418,16 @@ krb5_cc_move(krb5_context context, krb5_ccache src, krb5_ccache dst) return ret; } +krb5_boolean KRB5_CALLCONV +krb5_cc_support_switch(krb5_context context, const char *type) +{ + const krb5_cc_ops *ops; + krb5_error_code err; + + err = krb5int_cc_getops(context, type, &ops); + return (err ? FALSE : (ops->switch_to != NULL)); +} + krb5_error_code k5_cc_mutex_init(k5_cc_mutex *m) { diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c index 3d9bb7c8b..7bb074938 100644 --- a/src/lib/krb5/ccache/cccursor.c +++ b/src/lib/krb5/ccache/cccursor.c @@ -358,3 +358,47 @@ cccol_pertype_next(krb5_context context, errout: return ret; } + +krb5_error_code +krb5_cc_cache_match(krb5_context context, krb5_principal client, + krb5_ccache *cache_out) +{ + krb5_error_code ret; + krb5_cccol_cursor cursor; + krb5_ccache cache; + krb5_principal princ; + char *name; + krb5_boolean eq; + + *cache_out = NULL; + ret = krb5_cccol_cursor_new(context, &cursor); + if (ret) + return ret; + + while ((ret = krb5_cccol_cursor_next(context, cursor, &cache)) == 0 && + cache != NULL) { + ret = krb5_cc_get_principal(context, cache, &princ); + if (ret == 0) { + eq = krb5_principal_compare(context, princ, client); + krb5_free_principal(context, princ); + if (eq) + break; + } + krb5_cc_close(context, cache); + } + krb5_cccol_cursor_free(context, &cursor); + if (ret) + return ret; + if (cache == NULL) { + ret = krb5_unparse_name(context, client, &name); + if (ret == 0) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + _("Can't find client principal %s in " + "cache collection"), name); + krb5_free_unparsed_name(context, name); + } + ret = KRB5_CC_NOTFOUND; + } else + *cache_out = cache; + return ret; +} diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c index b92824d0a..70c607dfb 100644 --- a/src/lib/krb5/ccache/ccfns.c +++ b/src/lib/krb5/ccache/ccfns.c @@ -32,6 +32,20 @@ krb5_cc_get_name(krb5_context context, krb5_ccache cache) return cache->ops->get_name(context, cache); } +krb5_error_code KRB5_CALLCONV +krb5_cc_get_full_name(krb5_context context, krb5_ccache cache, + char **fullname_out) +{ + char *name; + + *fullname_out = NULL; + if (asprintf(&name, "%s:%s", cache->ops->prefix, + cache->ops->get_name(context, cache)) < 0) + return ENOMEM; + *fullname_out = name; + return 0; +} + krb5_error_code KRB5_CALLCONV krb5_cc_gen_new(krb5_context context, krb5_ccache *cache) { @@ -323,3 +337,11 @@ out: krb5_free_cred_contents(context, &mcred); return ret; } + +krb5_error_code KRB5_CALLCONV +krb5_cc_switch(krb5_context context, krb5_ccache cache) +{ + if (cache->ops->switch_to == NULL) + return 0; + return cache->ops->switch_to(context, cache); +} diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c index 31e786cd8..72b685759 100644 --- a/src/lib/krb5/krb/kfree.c +++ b/src/lib/krb5/krb/kfree.c @@ -521,6 +521,12 @@ krb5_free_unparsed_name(krb5_context context, char *val) free(val); } +void KRB5_CALLCONV +krb5_free_string(krb5_context context, char *val) +{ + free(val); +} + void KRB5_CALLCONV krb5_free_sam_challenge(krb5_context ctx, krb5_sam_challenge *sc) { diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index 20bb6803d..a5b05b5fb 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -183,6 +183,7 @@ krb5_build_principal krb5_build_principal_alloc_va krb5_build_principal_ext krb5_build_principal_va +krb5_cc_cache_match krb5_cc_close krb5_cc_copy_creds krb5_cc_default @@ -194,6 +195,7 @@ krb5_cc_end_seq_get krb5_cc_file_ops krb5_cc_gen_new krb5_cc_get_config +krb5_cc_get_full_name krb5_cc_get_name krb5_cc_get_principal krb5_cc_get_type @@ -210,6 +212,8 @@ krb5_cc_set_default_name krb5_cc_set_flags krb5_cc_start_seq_get krb5_cc_store_cred +krb5_cc_support_switch +krb5_cc_switch krb5_cccol_cursor_free krb5_cccol_cursor_new krb5_cccol_cursor_next @@ -322,6 +326,7 @@ krb5_free_sam_response krb5_free_sam_response_2 krb5_free_sam_response_2_contents krb5_free_sam_response_contents +krb5_free_string krb5_free_tgt_creds krb5_free_ticket krb5_free_tickets diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def index cff28772a..0afa6e499 100644 --- a/src/lib/krb5_32.def +++ b/src/lib/krb5_32.def @@ -412,3 +412,8 @@ EXPORTS krb5_init_context_profile @386 krb5int_c_mandatory_cksumtype @387 ; PRIVATE GSSAPI krb5int_arcfour_gsscrypt @388 ; PRIVATE GSSAPI + krb5_cc_cache_match @389 + krb5_cc_get_full_name @390 + krb5_cc_support_switch @391 + krb5_cc_switch @392 + krb5_free_string @393 -- 2.26.2