Proposed patch: --- src/lib/krb5/ccache/cc_dir.c +++ src/lib/krb5/ccache/cc_dir.c @@ -266,6 +266,46 @@ get_context_default_dir(krb5_context context, char **dirname_out) return 0; } +/* + * If the default ccache name for context is a subsidiary in a directory + * collection, set *dirname_out to the directory name for that collection and + * *residual_out to the residual value that we'd use if the named file was the + * primary. Otherwise set both to NULL. + */ +static krb5_error_code +get_context_specified_file(krb5_context context, char **dirname_out, + char **residual_out) +{ + krb5_error_code ret; + const char *defname; + char *filename; + + *dirname_out = NULL; + *residual_out = NULL; + defname = krb5_cc_default_name(context); + if (defname == NULL) + return 0; + if (strncmp(defname, "DIR:", 4) != 0 || defname[4] != ':') + return 0; + ret = split_path(context, defname + 5, dirname_out, &filename); + if (ret != 0) { + free(*dirname_out); + *dirname_out = NULL; + free(filename); + return ret; + } + ret = subsidiary_residual(*dirname_out, filename, residual_out); + free(filename); + if (ret != 0) { + free(*dirname_out); + *dirname_out = NULL; + free(*residual_out); + *residual_out = NULL; + return ret; + } + return 0; +} + static const char * KRB5_CALLCONV dcc_get_name(krb5_context context, krb5_ccache cache) { @@ -559,22 +599,31 @@ dcc_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor_out) krb5_error_code ret; char *dirname = NULL, *primary_path = NULL, *primary = NULL; DIR *dir = NULL; + krb5_boolean override_primary; *cursor_out = NULL; /* Open the directory for the context's default cache. */ ret = get_context_default_dir(context, &dirname); - if (ret || dirname == NULL) - goto cleanup; - dir = opendir(dirname); - if (dir == NULL) - goto cleanup; + override_primary = FALSE; + if (ret || dirname == NULL) { + ret = get_context_specified_file(context, &dirname, &primary); + if (ret || dirname == NULL || primary == NULL) + goto cleanup; + override_primary = TRUE; + } else { + dir = opendir(dirname); + if (dir == NULL) + goto cleanup; + } /* Fetch the primary cache name if possible. */ - ret = primary_pathname(dirname, &primary_path); - if (ret) - goto cleanup; - ret = read_primary_file(context, primary_path, dirname, &primary); + if (!override_primary) { + ret = primary_pathname(dirname, &primary_path); + if (ret) + goto cleanup; + ret = read_primary_file(context, primary_path, dirname, &primary); + } if (ret) krb5_clear_error_message(context); @@ -607,8 +656,6 @@ dcc_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor, struct stat sb; *cache_out = NULL; - if (data->dir == NULL) /* Empty cursor */ - return 0; /* Return the primary cache if we haven't yet. */ if (data->first) { @@ -616,6 +663,8 @@ dcc_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor, if (data->primary != NULL && stat(data->primary + 1, &sb) == 0) return dcc_resolve(context, cache_out, data->primary); } + if (data->dir == NULL) /* Empty cursor or one already-seen cache. */ + return 0; /* Look for the next filename of the correct form, without repeating the * primary cache. */ diff --git a/src/lib/krb5/ccache/t_cccol.py b/src/lib/krb5/ccache/t_cccol.py index acd2b6e..8a37f9b 100644 --- a/src/lib/krb5/ccache/t_cccol.py +++ b/src/lib/krb5/ccache/t_cccol.py @@ -30,6 +30,9 @@ cursor_test('file-default2', [realm.ccache], [fccname]) cursor_test('file-default3', [fccname], [fccname]) cursor_test('dir', [dccname], [duser, dalice, dbob]) +cursor_test('dir-user', [duser], [duser]) +cursor_test('dir-alice', [dalice], [dalice]) +cursor_test('dir-bob', [dbob], [dbob]) mfoo = 'MEMORY:foo' mbar = 'MEMORY:bar'