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'