Skip to content

Commit

Permalink
krb5: Complete support for non-default cache collections (fix #1146)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicowilliams committed Jun 6, 2023
1 parent e1326e5 commit 36a9fa6
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 80 deletions.
3 changes: 2 additions & 1 deletion kcm/glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ kcmss_get_version(krb5_context context,
}

static const krb5_cc_ops krb5_kcmss_ops = {
KRB5_CC_OPS_VERSION_5,
KRB5_CC_OPS_VERSION_6,
"KCM",
NULL,
NULL,
Expand Down Expand Up @@ -289,6 +289,7 @@ static const krb5_cc_ops krb5_kcmss_ops = {
kcmss_resolve_2,
NULL,
NULL,
NULL,
0,
'\0',
':'
Expand Down
3 changes: 2 additions & 1 deletion lib/krb5/acache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ acc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
*/

KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = {
KRB5_CC_OPS_VERSION_5,
KRB5_CC_OPS_VERSION_6,
"API",
NULL,
NULL,
Expand Down Expand Up @@ -1125,6 +1125,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = {
acc_resolve_2,
NULL, /* acc_get_primary_name */
acc_gen_new_2,
NULL, /* acc_get_cache_first_2 */
0,
':',
'\0',
Expand Down
198 changes: 161 additions & 37 deletions lib/krb5/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1531,7 +1531,8 @@ struct krb5_cc_cache_cursor_data {
* krb5_cccol_cursor_new().
* @param context A Kerberos 5 context
* @param type optional type to iterate over, if NULL, the default cache is used.
* @param collection optional cache collection to iterate over;
* if NULL, the default collection will be used
* @param cursor cursor should be freed with krb5_cc_cache_end_seq_get().
*
* @return Return an error code or 0, see krb5_get_error_message().
Expand All @@ -1542,42 +1543,92 @@ struct krb5_cc_cache_cursor_data {

KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_cc_cache_get_first (krb5_context context,
const char *type,
const char *cc,
krb5_cc_cache_cursor *cursor)
{
const krb5_cc_ops *ops;
krb5_error_code ret;
const char *def_cctype = NULL;
const char *cctype = NULL;
char *def_cc = krb5_cccol_get_default_ccname(context);
char *def_ccname = NULL;
char *ccname = NULL;

if (type == NULL)
type = krb5_cc_default_name(context);
ret = krb5_cc_parse_name(context, def_cc, '\0', '\0', -1, &def_cctype,
NULL, &def_ccname, NULL);
if (ret) {
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
"Could not parse default credentials cache name: %s", cc);
free(def_cc);
return KRB5_CC_UNKNOWN_TYPE;
}

ops = krb5_cc_get_prefix_ops(context, type);
if (cc == NULL) {
cc = def_cc;
} else {
ret = krb5_cc_parse_name(context, cc, '\0', '\0', -1, &cctype, NULL,
&ccname, NULL);
if (ret) {
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
"Could not parse credentials cache name: %s", cc);
free(def_ccname);
free(def_cc);
return KRB5_CC_UNKNOWN_TYPE;
}
}

ops = krb5_cc_get_prefix_ops(context, cc);
if (ops == NULL) {
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
"Unknown type \"%s\" when iterating "
"trying to iterate the credential caches", type);
"Unknown type when trying to iterate "
"credential cache \"%s\"", cc);
free(def_ccname);
free(ccname);
free(def_cc);
return KRB5_CC_UNKNOWN_TYPE;
}

if (ops->get_cache_first == NULL) {
krb5_set_error_message(context, KRB5_CC_NOSUPP,
N_("Credential cache type %s doesn't support "
"iterations over caches", "type"),
ops->prefix);
return KRB5_CC_NOSUPP;
if (ops->get_cache_first_2 == NULL && ops->get_cache_first != NULL) {
if (def_ccname && ccname && strcmp(def_ccname, ccname) != 0) {
krb5_set_error_message(context, KRB5_CC_NOSUPP,
"Cache type %s does not support iteration "
"of non-default credentials cache "
"collections; could not list caches in %s",
def_cctype, cc);
free(def_ccname);
free(ccname);
free(def_cc);
return KRB5_CC_NOSUPP;
}
}

*cursor = calloc(1, sizeof(**cursor));
if (*cursor == NULL)
if (*cursor == NULL) {
free(def_ccname);
free(ccname);
free(def_cc);
return krb5_enomem(context);
}

(*cursor)->ops = ops;

ret = ops->get_cache_first(context, &(*cursor)->cursor);
if (ops->get_cache_first_2) {
ret = ops->get_cache_first_2(context, cc, &(*cursor)->cursor);
} else if (ops->get_cache_first) {
ret = ops->get_cache_first(context, &(*cursor)->cursor);
} else {
krb5_set_error_message(context, ret = KRB5_CC_NOSUPP,
N_("Credential cache type %s doesn't support "
"iterations over caches", "type"),
ops->prefix);
}
if (ret) {
free(*cursor);
*cursor = NULL;
}
free(def_ccname);
free(ccname);
free(def_cc);
return ret;
}

Expand Down Expand Up @@ -1625,9 +1676,9 @@ krb5_cc_cache_end_seq_get (krb5_context context,
}

/**
* Search for a matching credential cache that have the
* `principal' as the default principal. On success, `id' needs to be
* freed with krb5_cc_close() or krb5_cc_destroy().
* Search the default cache collection for a matching credential cache that
* has the given `principal' as the default principal. On success, `id' needs
* to be freed with krb5_cc_close() or krb5_cc_destroy().
*
* @param context A Kerberos 5 context
* @param client The principal to search for
Expand All @@ -1638,11 +1689,39 @@ krb5_cc_cache_end_seq_get (krb5_context context,
* @ingroup krb5_ccache
*/


KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_cc_cache_match (krb5_context context,
krb5_principal client,
krb5_ccache *id)
{
krb5_error_code ret;
char *collection = krb5_cccol_get_default_ccname(context);

ret = krb5_cc_cache_match2(context, collection, client, id);
free(collection);
return ret;
}

/**
* Search the named cache `collection' for a matching credential cache that has
* the `principal' as the default principal. On success, `id' needs to be
* freed with krb5_cc_close() or krb5_cc_destroy().
*
* @param context A Kerberos 5 context
* @param collection The name of a cache or cache collection to search
* @param client The principal to search for
* @param id the returned credential cache
*
* @return On failure, error code is returned and `id' is set to NULL.
*
* @ingroup krb5_ccache
*/

KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_cc_cache_match2(krb5_context context,
const char *collection,
krb5_principal client,
krb5_ccache *id)
{
krb5_cccol_cursor cursor;
krb5_error_code ret;
Expand All @@ -1651,7 +1730,7 @@ krb5_cc_cache_match (krb5_context context,

*id = NULL;

ret = krb5_cccol_cursor_new (context, &cursor);
ret = krb5_cccol_cursor_new2(context, collection, &cursor);
if (ret)
return ret;

Expand Down Expand Up @@ -1926,6 +2005,8 @@ krb5_cc_get_config(krb5_context context, krb5_ccache id,

struct krb5_cccol_cursor_data {
int idx;
char *collection;
const char *type;
krb5_cc_cache_cursor cursor;
};

Expand All @@ -1944,13 +2025,63 @@ struct krb5_cccol_cursor_data {
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor)
{
return krb5_cccol_cursor_new2(context, NULL, cursor);
}

/**
* Get a new cache interation cursor that will interate over all
* credentials caches independent of type.
*
* @param context a Kerberos context
* @param collection the name of a credentials cache or cache collection to iterate
* @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
*
* @return Returns 0 or and error code, see krb5_get_error_message().
*
* @ingroup krb5_ccache
*/

KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_cccol_cursor_new2(krb5_context context,
const char *collection,
krb5_cccol_cursor *cursor)
{
krb5_error_code ret;
char *s = NULL;

if (collection == NULL)
collection = s = krb5_cccol_get_default_ccname(context);

*cursor = calloc(1, sizeof(**cursor));
if (*cursor == NULL)
if (*cursor == NULL) {
free(s);
return krb5_enomem(context);
}
(*cursor)->idx = 0;
(*cursor)->cursor = NULL;
if (collection) {
(*cursor)->collection = strdup(collection);
if ((*cursor)->collection == NULL) {
ret = krb5_enomem(context);
goto out;
}
}

return 0;
ret = krb5_cc_parse_name(context, collection, '\0', '\0', -1,
&(*cursor)->type, NULL, NULL, NULL);
if (ret)
krb5_set_error_message(context, ret,
"Could not parse default credentials cache name: %s",
collection);

out:
if (ret) {
free((*cursor)->collection);
free(*cursor);
*cursor = NULL;
}
free(s);
return ret;
}

/**
Expand All @@ -1976,26 +2107,18 @@ krb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor,
krb5_ccache *cache)
{
krb5_error_code ret = 0;
const char *def_cctype = get_default_cc_type(context, 0);

*cache = NULL;

while (cursor->idx < context->num_cc_ops) {
if (strcmp(context->cc_ops[cursor->idx]->prefix, cursor->type) != 0) {
cursor->idx++;
continue;
}

if (cursor->cursor == NULL) {
if (!context->default_cc_name_defaulted &&
strcmp(def_cctype, context->cc_ops[cursor->idx]->prefix) != 0) {
/*
* If KRB5CCNAME is set then we don't list collections other
* than that one. If we ever add an ANY: ccache type then this
* will be more painful.
*/
cursor->idx++;
continue;
}
ret = krb5_cc_cache_get_first (context,
context->cc_ops[cursor->idx]->prefix,
&cursor->cursor);
ret = krb5_cc_cache_get_first(context, cursor->collection,
&cursor->cursor);
if (ret) {
/* No caches in this type's collection -> onto the next type */
cursor->idx++;
Expand Down Expand Up @@ -2041,6 +2164,7 @@ krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor)

*cursor = NULL;
if (c) {
free(c->collection);
if (c->cursor)
krb5_cc_cache_end_seq_get(context, c->cursor);
free(c);
Expand Down Expand Up @@ -2479,7 +2603,7 @@ krb5_cc_parse_name(krb5_context context,
else
p = strchr(p, subsep);

if (p) {
if (p && *p) {
*(p++) = '\0';
if (*p)
sub = p;
Expand Down
Loading

0 comments on commit 36a9fa6

Please sign in to comment.