summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/k5-int.h44
-rw-r--r--src/include/krb5/krb5.hin19
-rw-r--r--src/lib/krb5/ccache/Makefile.in7
-rw-r--r--src/lib/krb5/ccache/cc_file.c6
-rw-r--r--src/lib/krb5/ccache/cc_memory.c109
-rw-r--r--src/lib/krb5/ccache/cc_mslsa.c8
-rw-r--r--src/lib/krb5/ccache/ccapi/stdcc.c16
-rw-r--r--src/lib/krb5/ccache/ccbase.c72
-rw-r--r--src/lib/krb5/ccache/cccursor.c330
-rw-r--r--src/lib/krb5/ccache/t_cccursor.c234
-rw-r--r--src/lib/krb5/os/ccdefname.c19
11 files changed, 861 insertions, 3 deletions
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 53b2acbf2b..8455fe47d8 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -1758,6 +1758,15 @@ struct _krb5_ccache {
krb5_pointer data;
};
+/*
+ * Per-type ccache cursor.
+ */
+struct krb5_cc_ptcursor {
+ const struct _krb5_cc_ops *ops;
+ krb5_pointer data;
+};
+typedef struct krb5_cc_ptcursor *krb5_cc_ptcursor;
+
struct _krb5_cc_ops {
krb5_magic magic;
char *prefix;
@@ -1788,10 +1797,45 @@ struct _krb5_cc_ops {
krb5_flags);
krb5_error_code (KRB5_CALLCONV *get_flags) (krb5_context, krb5_ccache,
krb5_flags *);
+ krb5_error_code (KRB5_CALLCONV *ptcursor_new)(krb5_context,
+ krb5_cc_ptcursor *);
+ krb5_error_code (KRB5_CALLCONV *ptcursor_next)(krb5_context,
+ krb5_cc_ptcursor,
+ krb5_ccache *);
+ krb5_error_code (KRB5_CALLCONV *ptcursor_free)(krb5_context,
+ krb5_cc_ptcursor *);
+ krb5_error_code (KRB5_CALLCONV *move)(krb5_context, krb5_ccache);
+ krb5_error_code (KRB5_CALLCONV *lastchange)(krb5_context,
+ krb5_ccache, krb5_timestamp *);
+ krb5_error_code (KRB5_CALLCONV *wasdefault)(krb5_context, krb5_ccache,
+ krb5_timestamp *);
};
extern const krb5_cc_ops *krb5_cc_dfl_ops;
+krb5_error_code
+krb5int_cc_os_default_name(krb5_context context, char **name);
+
+/*
+ * Cursor for iterating over ccache types
+ */
+struct krb5_cc_typecursor;
+typedef struct krb5_cc_typecursor *krb5_cc_typecursor;
+
+krb5_error_code
+krb5int_cc_typecursor_new(krb5_context context, krb5_cc_typecursor *cursor);
+
+krb5_error_code
+krb5int_cc_typecursor_next(
+ krb5_context context,
+ krb5_cc_typecursor cursor,
+ const struct _krb5_cc_ops **ops);
+
+krb5_error_code
+krb5int_cc_typecursor_free(
+ krb5_context context,
+ krb5_cc_typecursor *cursor);
+
typedef struct _krb5_donot_replay {
krb5_magic magic;
krb5_ui_4 hash;
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 32b714adb1..354ff12b11 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -1212,6 +1212,12 @@ typedef struct _krb5_ccache *krb5_ccache;
struct _krb5_cc_ops;
typedef struct _krb5_cc_ops krb5_cc_ops;
+/*
+ * Cursor for iterating over all ccaches
+ */
+struct krb5_cccol_cursor;
+typedef struct krb5_cccol_cursor *krb5_cccol_cursor;
+
/* for retrieve_cred */
#define KRB5_TC_MATCH_TIMES 0x00000001
#define KRB5_TC_MATCH_IS_SKEY 0x00000002
@@ -1282,6 +1288,19 @@ krb5_cc_get_flags (krb5_context context, krb5_ccache cache, krb5_flags *flags);
const char * KRB5_CALLCONV
krb5_cc_get_type (krb5_context context, krb5_ccache cache);
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_cursor_next(
+ krb5_context context,
+ krb5_cccol_cursor cursor,
+ krb5_ccache *ccache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor);
+
+
/*
* end "ccache.h"
*/
diff --git a/src/lib/krb5/ccache/Makefile.in b/src/lib/krb5/ccache/Makefile.in
index 7d611f8392..f2c137e5ea 100644
--- a/src/lib/krb5/ccache/Makefile.in
+++ b/src/lib/krb5/ccache/Makefile.in
@@ -23,6 +23,7 @@ LOCALINCLUDES = -I$(srcdir)$(S)ccapi $(WIN_INCLUDES)
STLIBOBJS= \
ccbase.o \
cccopy.o \
+ cccursor.o \
ccdefault.o \
ccdefops.o \
cc_retr.o \
@@ -34,6 +35,7 @@ STLIBOBJS= \
OBJS= $(OUTPRE)ccbase.$(OBJEXT) \
$(OUTPRE)cccopy.$(OBJEXT) \
+ $(OUTPRE)cccursor.$(OBJEXT) \
$(OUTPRE)ccdefault.$(OBJEXT) \
$(OUTPRE)ccdefops.$(OBJEXT) \
$(OUTPRE)cc_retr.$(OBJEXT) \
@@ -45,6 +47,7 @@ OBJS= $(OUTPRE)ccbase.$(OBJEXT) \
SRCS= $(srcdir)/ccbase.c \
$(srcdir)/cccopy.c \
+ $(srcdir)/cccursor.c \
$(srcdir)/ccdefault.c \
$(srcdir)/ccdefops.c \
$(srcdir)/cc_retr.c \
@@ -89,6 +92,10 @@ T_CC_OBJS=t_cc.o
t_cc: $(T_CC_OBJS) $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o t_cc $(T_CC_OBJS) $(KRB5_BASE_LIBS)
+T_CCCURSOR_OBJS = t_cccursor.o
+t_cccursor: $(T_CCCURSOR_OBJS) $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o $@ $(T_CCCURSOR_OBJS) $(KRB5_BASE_LIBS)
+
check-unix:: t_cc
KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\
$(RUN_SETUP) ./t_cc
diff --git a/src/lib/krb5/ccache/cc_file.c b/src/lib/krb5/ccache/cc_file.c
index 8c35acd45c..5b11a0e01b 100644
--- a/src/lib/krb5/ccache/cc_file.c
+++ b/src/lib/krb5/ccache/cc_file.c
@@ -2371,4 +2371,10 @@ const krb5_cc_ops krb5_cc_file_ops = {
krb5_fcc_remove_cred,
krb5_fcc_set_flags,
krb5_fcc_get_flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
};
diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c
index 9b5ee9f388..88cd6fbbfa 100644
--- a/src/lib/krb5/ccache/cc_memory.c
+++ b/src/lib/krb5/ccache/cc_memory.c
@@ -75,6 +75,19 @@ static krb5_error_code KRB5_CALLCONV krb5_mcc_store
static krb5_error_code KRB5_CALLCONV krb5_mcc_set_flags
(krb5_context, krb5_ccache id , krb5_flags flags );
+static krb5_error_code KRB5_CALLCONV krb5_mcc_ptcursor_new(
+ krb5_context,
+ krb5_cc_ptcursor *);
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_ptcursor_next(
+ krb5_context,
+ krb5_cc_ptcursor,
+ krb5_ccache *);
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_ptcursor_free(
+ krb5_context,
+ krb5_cc_ptcursor *);
+
extern const krb5_cc_ops krb5_mcc_ops;
extern krb5_error_code krb5_change_cache (void);
@@ -97,6 +110,10 @@ typedef struct krb5_mcc_list_node {
krb5_mcc_data *cache;
} krb5_mcc_list_node;
+struct krb5_mcc_ptcursor_data {
+ struct krb5_mcc_list_node *cur;
+};
+
k5_mutex_t krb5int_mcc_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
static krb5_mcc_list_node *mcc_head = 0;
@@ -651,6 +668,92 @@ krb5_mcc_store(krb5_context ctx, krb5_ccache id, krb5_creds *creds)
return 0;
}
+static krb5_error_code KRB5_CALLCONV
+krb5_mcc_ptcursor_new(
+ krb5_context context,
+ krb5_cc_ptcursor *cursor)
+{
+ krb5_error_code ret = 0;
+ krb5_cc_ptcursor n = NULL;
+ struct krb5_mcc_ptcursor_data *cdata = NULL;
+
+ *cursor = NULL;
+
+ n = malloc(sizeof(*n));
+ if (n == NULL)
+ return ENOMEM;
+ n->ops = &krb5_mcc_ops;
+ cdata = malloc(sizeof(struct krb5_mcc_ptcursor_data));
+ if (cdata == NULL) {
+ ret = ENOMEM;
+ goto errout;
+ }
+ n->data = cdata;
+ ret = k5_mutex_lock(&krb5int_mcc_mutex);
+ if (ret)
+ goto errout;
+ cdata->cur = mcc_head;
+ ret = k5_mutex_unlock(&krb5int_mcc_mutex);
+ if (ret)
+ goto errout;
+
+errout:
+ if (ret) {
+ krb5_mcc_ptcursor_free(context, &n);
+ }
+ *cursor = n;
+ return ret;
+}
+
+static krb5_error_code KRB5_CALLCONV
+krb5_mcc_ptcursor_next(
+ krb5_context context,
+ krb5_cc_ptcursor cursor,
+ krb5_ccache *ccache)
+{
+ krb5_error_code ret = 0;
+ struct krb5_mcc_ptcursor_data *cdata = NULL;
+
+ *ccache = NULL;
+ cdata = cursor->data;
+ if (cdata->cur == NULL)
+ return 0;
+
+ *ccache = malloc(sizeof(**ccache));
+ if (*ccache == NULL)
+ return ENOMEM;
+
+ (*ccache)->ops = &krb5_mcc_ops;
+ (*ccache)->data = cdata->cur->cache;
+ ret = k5_mutex_lock(&krb5int_mcc_mutex);
+ if (ret)
+ goto errout;
+ cdata->cur = cdata->cur->next;
+ ret = k5_mutex_unlock(&krb5int_mcc_mutex);
+ if (ret)
+ goto errout;
+errout:
+ if (ret && *ccache != NULL) {
+ free(*ccache);
+ *ccache = NULL;
+ }
+ return ret;
+}
+
+static krb5_error_code KRB5_CALLCONV
+krb5_mcc_ptcursor_free(
+ krb5_context context,
+ krb5_cc_ptcursor *cursor)
+{
+ if (*cursor == NULL)
+ return 0;
+ if ((*cursor)->data != NULL)
+ free((*cursor)->data);
+ free(*cursor);
+ *cursor = NULL;
+ return 0;
+}
+
const krb5_cc_ops krb5_mcc_ops = {
0,
"MEMORY",
@@ -669,4 +772,10 @@ const krb5_cc_ops krb5_mcc_ops = {
krb5_mcc_remove_cred,
krb5_mcc_set_flags,
krb5_mcc_get_flags,
+ krb5_mcc_ptcursor_new,
+ krb5_mcc_ptcursor_next,
+ krb5_mcc_ptcursor_free,
+ NULL,
+ NULL,
+ NULL,
};
diff --git a/src/lib/krb5/ccache/cc_mslsa.c b/src/lib/krb5/ccache/cc_mslsa.c
index 4bb6d752bf..381484ca50 100644
--- a/src/lib/krb5/ccache/cc_mslsa.c
+++ b/src/lib/krb5/ccache/cc_mslsa.c
@@ -2648,6 +2648,12 @@ const krb5_cc_ops krb5_lcc_ops = {
krb5_lcc_end_seq_get,
krb5_lcc_remove_cred,
krb5_lcc_set_flags,
- krb5_lcc_get_flags
+ krb5_lcc_get_flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
};
#endif /* _WIN32 */
diff --git a/src/lib/krb5/ccache/ccapi/stdcc.c b/src/lib/krb5/ccache/ccapi/stdcc.c
index b4354c7a24..c9133efcd5 100644
--- a/src/lib/krb5/ccache/ccapi/stdcc.c
+++ b/src/lib/krb5/ccache/ccapi/stdcc.c
@@ -83,7 +83,13 @@ krb5_cc_ops krb5_cc_stdcc_ops = {
krb5_stdccv3_end_seq_get,
krb5_stdccv3_remove,
krb5_stdccv3_set_flags,
- krb5_stdccv3_get_flags
+ krb5_stdccv3_get_flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
#else
krb5_stdcc_get_name,
krb5_stdcc_resolve,
@@ -99,7 +105,13 @@ krb5_cc_ops krb5_cc_stdcc_ops = {
krb5_stdcc_end_seq_get,
krb5_stdcc_remove,
krb5_stdcc_set_flags,
- krb5_stdcc_get_flags
+ krb5_stdcc_get_flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
#endif
};
diff --git a/src/lib/krb5/ccache/ccbase.c b/src/lib/krb5/ccache/ccbase.c
index 431e43bc93..044f48e488 100644
--- a/src/lib/krb5/ccache/ccbase.c
+++ b/src/lib/krb5/ccache/ccbase.c
@@ -37,6 +37,12 @@ struct krb5_cc_typelist {
const krb5_cc_ops *ops;
struct krb5_cc_typelist *next;
};
+
+struct krb5_cc_typecursor {
+ struct krb5_cc_typelist *tptr;
+};
+/* typedef krb5_cc_typecursor in k5-int.h */
+
extern const krb5_cc_ops krb5_mcc_ops;
#ifdef USE_KEYRING_CCACHE
extern const krb5_cc_ops krb5_krcc_ops;
@@ -213,3 +219,69 @@ krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
free(pfx);
return KRB5_CC_UNKNOWN_TYPE;
}
+
+/*
+ * cc_typecursor
+ *
+ * Note: to avoid copying the typelist at cursor creation time, among
+ * other things, we assume that the only additions ever occur to the
+ * typelist.
+ */
+krb5_error_code
+krb5int_cc_typecursor_new(krb5_context context, krb5_cc_typecursor *t)
+{
+ krb5_error_code err = 0;
+ krb5_cc_typecursor n = NULL;
+
+ *t = NULL;
+ n = malloc(sizeof(*n));
+ if (n == NULL)
+ return ENOMEM;
+
+ err = k5_mutex_lock(&cc_typelist_lock);
+ if (err)
+ goto errout;
+ n->tptr = cc_typehead;
+ err = k5_mutex_unlock(&cc_typelist_lock);
+ if (err)
+ goto errout;
+
+ *t = n;
+errout:
+ if (err)
+ free(n);
+ return err;
+}
+
+krb5_error_code
+krb5int_cc_typecursor_next(
+ krb5_context context,
+ krb5_cc_typecursor t,
+ const krb5_cc_ops **ops)
+{
+ krb5_error_code err = 0;
+
+ *ops = NULL;
+ if (t->tptr == NULL)
+ return 0;
+
+ err = k5_mutex_lock(&cc_typelist_lock);
+ if (err)
+ goto errout;
+ *ops = t->tptr->ops;
+ t->tptr = t->tptr->next;
+ err = k5_mutex_unlock(&cc_typelist_lock);
+ if (err)
+ goto errout;
+
+errout:
+ return err;
+}
+
+krb5_error_code
+krb5int_cc_typecursor_free(krb5_context context, krb5_cc_typecursor *t)
+{
+ free(*t);
+ *t = NULL;
+ return 0;
+}
diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c
new file mode 100644
index 0000000000..9a57d52230
--- /dev/null
+++ b/src/lib/krb5/ccache/cccursor.c
@@ -0,0 +1,330 @@
+/*
+ * lib/krb5/ccache/cccursor.c
+ *
+ * Copyright 2006 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * cursor for sequential traversal of ccaches
+ */
+
+#include "k5-int.h"
+
+#include <assert.h>
+
+#define CCCURSOR_CONTEXT 1
+#define CCCURSOR_ENV 2
+#define CCCURSOR_OS 3
+#define CCCURSOR_PERTYPE 4
+
+#define NFULLNAMES 3
+
+/* Prefix and residual parts of a full ccache name. */
+struct cc_fullname {
+ char *pfx;
+ char *res;
+};
+
+struct krb5_cccol_cursor {
+ int pos;
+ krb5_cc_typecursor typecursor;
+ const krb5_cc_ops *ops;
+ krb5_cc_ptcursor ptcursor;
+ int cur_fullname;
+ struct cc_fullname fullnames[NFULLNAMES]; /* previously seen ccaches */
+};
+/* typedef of krb5_cccol_cursor is in krb5.h */
+
+static int cccol_already(krb5_context, krb5_cccol_cursor, krb5_ccache *);
+
+static int cccol_cmpname(const char *, const char *, struct cc_fullname *);
+
+static krb5_error_code
+cccol_do_resolve(krb5_context, krb5_cccol_cursor, const char *, krb5_ccache *);
+
+static krb5_error_code
+cccol_pertype_next(krb5_context, krb5_cccol_cursor, krb5_ccache *);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_cursor_new(
+ krb5_context context,
+ krb5_cccol_cursor *cursor)
+{
+ krb5_error_code ret = 0;
+ krb5_cccol_cursor n = NULL;
+ int i;
+
+ *cursor = NULL;
+ n = malloc(sizeof(*n));
+ if (n == NULL)
+ return ENOMEM;
+
+ n->pos = CCCURSOR_CONTEXT;
+ n->typecursor = NULL;
+ n->ptcursor = NULL;
+ n->ops = NULL;
+
+ for (i = 0; i < NFULLNAMES; i++) {
+ n->fullnames[i].pfx = n->fullnames[i].res = NULL;
+ }
+ n->cur_fullname = 0;
+ ret = krb5int_cc_typecursor_new(context, &n->typecursor);
+ if (ret)
+ goto errout;
+
+ do {
+ /* Find first backend with ptcursor functionality. */
+ ret = krb5int_cc_typecursor_next(context, n->typecursor, &n->ops);
+ if (ret || n->ops == NULL)
+ goto errout;
+ } while (n->ops->ptcursor_new == NULL);
+
+ ret = n->ops->ptcursor_new(context, &n->ptcursor);
+ if (ret)
+ goto errout;
+
+errout:
+ if (ret) {
+ krb5_cccol_cursor_free(context, &n);
+ }
+ *cursor = n;
+ return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_cursor_next(
+ krb5_context context,
+ krb5_cccol_cursor cursor,
+ krb5_ccache *ccache)
+{
+ krb5_error_code ret = 0;
+ char *name;
+ krb5_os_context os_ctx = NULL;
+
+ *ccache = NULL;
+ os_ctx = context->os_context;
+
+ switch (cursor->pos) {
+ case CCCURSOR_CONTEXT:
+ name = os_ctx->default_ccname;
+ if (name != NULL) {
+ cursor->pos = CCCURSOR_ENV;
+ ret = cccol_do_resolve(context, cursor, name, ccache);
+ if (ret)
+ goto errout;
+ if (*ccache != NULL)
+ break;
+ }
+ /* fall through */
+ case CCCURSOR_ENV:
+ name = getenv(KRB5_ENV_CCNAME);
+ if (name != NULL) {
+ cursor->pos = CCCURSOR_OS;
+ ret = cccol_do_resolve(context, cursor, name, ccache);
+ if (ret)
+ goto errout;
+ if (*ccache != NULL)
+ break;
+ }
+ /* fall through */
+ case CCCURSOR_OS:
+ ret = krb5int_cc_os_default_name(context, &name);
+ if (ret) goto errout;
+ if (name != NULL) {
+ cursor->pos = CCCURSOR_PERTYPE;
+ ret = cccol_do_resolve(context, cursor, name, ccache);
+ free(name);
+ if (ret)
+ goto errout;
+ if (*ccache != NULL)
+ break;
+ }
+ /* fall through */
+ case CCCURSOR_PERTYPE:
+ cursor->pos = CCCURSOR_PERTYPE;
+ do {
+ ret = cccol_pertype_next(context, cursor, ccache);
+ if (ret)
+ goto errout;
+ } while (cccol_already(context, cursor, ccache));
+ break;
+ }
+errout:
+ return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_cursor_free(
+ krb5_context context,
+ krb5_cccol_cursor *cursor)
+{
+ krb5_cccol_cursor c = *cursor;
+ int i;
+
+ if (c == NULL)
+ return 0;
+
+ for (i = 0; i < NFULLNAMES; i++) {
+ if (c->fullnames[i].pfx != NULL)
+ free(c->fullnames[i].pfx);
+ if (c->fullnames[i].res != NULL)
+ free(c->fullnames[i].res);
+ }
+ if (c->ptcursor != NULL)
+ c->ops->ptcursor_free(context, &c->ptcursor);
+ if (c->typecursor != NULL)
+ krb5int_cc_typecursor_free(context, &c->typecursor);
+ free(c);
+
+ *cursor = NULL;
+ return 0;
+}
+
+/*
+ * Determine if a ccache from a per-type cursor was already one of the
+ * higher-priority defaults.
+ */
+static int
+cccol_already(
+ krb5_context context,
+ krb5_cccol_cursor c,
+ krb5_ccache *ccache)
+{
+ const char *name = NULL, *prefix = NULL;
+ int i;
+
+ if (*ccache == NULL)
+ return 0;
+ name = krb5_cc_get_name(context, *ccache);
+ if (name == NULL)
+ return 0;
+ prefix = krb5_cc_get_type(context, *ccache);
+
+ assert(c->cur_fullname < NFULLNAMES);
+ for (i = 0; i < c->cur_fullname; i++) {
+ if (cccol_cmpname(prefix, name, &c->fullnames[i])) {
+ krb5_cc_close(context, *ccache);
+ *ccache = NULL;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Compare {prefix, name} against a cc_fullname.
+ */
+static int
+cccol_cmpname(
+ const char *prefix,
+ const char *name,
+ struct cc_fullname *fullname)
+{
+ if (fullname->pfx == NULL || fullname->res == NULL)
+ return 0;
+ if (strcmp(prefix, fullname->pfx))
+ return 0;
+ if (strcmp(name, fullname->res))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Resolve one of the high-precedence ccaches, and cache its full name
+ * {prefix, residual} for exclusion when doing per-type ccache
+ * iteration. Also check to see if we've already seen the ccache
+ * name we're given.
+ */
+static krb5_error_code
+cccol_do_resolve(
+ krb5_context context,
+ krb5_cccol_cursor cursor,
+ const char *name,
+ krb5_ccache *ccache)
+{
+ krb5_error_code ret = 0;
+ struct cc_fullname *fullname;
+
+ assert(cursor->cur_fullname < NFULLNAMES);
+ ret = krb5_cc_resolve(context, name, ccache);
+ if (ret)
+ return ret;
+
+ if (cccol_already(context, cursor, ccache))
+ return 0;
+
+ fullname = &cursor->fullnames[cursor->cur_fullname];
+ fullname->pfx = strdup(krb5_cc_get_type(context, *ccache));
+ fullname->res = strdup(krb5_cc_get_name(context, *ccache));
+ cursor->cur_fullname++;
+ return ret;
+}
+
+/*
+ * Find next ccache in current backend, iterating through backends if
+ * ccache list of the current backend is exhausted.
+ */
+static krb5_error_code
+cccol_pertype_next(
+ krb5_context context,
+ krb5_cccol_cursor cursor,
+ krb5_ccache *ccache)
+{
+ krb5_error_code ret = 0;
+
+ *ccache = NULL;
+
+ /* Are we out of backends? */
+ if (cursor->ops == NULL)
+ return 0;
+ /*
+ * Loop in case there are multiple backends with empty ccache
+ * lists.
+ */
+ while (*ccache == NULL) {
+ ret = cursor->ops->ptcursor_next(context, cursor->ptcursor, ccache);
+ if (ret)
+ goto errout;
+ if (*ccache != NULL)
+ return 0;
+
+ ret = cursor->ops->ptcursor_free(context, &cursor->ptcursor);
+ if (ret)
+ goto errout;
+
+ do {
+ /* Find first backend with ptcursor functionality. */
+ ret = krb5int_cc_typecursor_next(context, cursor->typecursor,
+ &cursor->ops);
+ if (ret)
+ goto errout;
+ if (cursor->ops == NULL)
+ return 0;
+ } while (cursor->ops->ptcursor_new == NULL);
+
+ ret = cursor->ops->ptcursor_new(context, &cursor->ptcursor);
+ if (ret)
+ goto errout;
+ }
+errout:
+ return ret;
+}
diff --git a/src/lib/krb5/ccache/t_cccursor.c b/src/lib/krb5/ccache/t_cccursor.c
new file mode 100644
index 0000000000..8939c6a60a
--- /dev/null
+++ b/src/lib/krb5/ccache/t_cccursor.c
@@ -0,0 +1,234 @@
+/*
+ * lib/krb5/ccache/t_cccursor.c
+ *
+ * Copyright 2006 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "autoconf.h"
+#include "krb5.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct crlist {
+ char *ccname;
+ char *pname;
+};
+
+struct crlist crlist[] = {
+ { "foo", NULL },
+ { "MEMORY:env", "env" },
+ { "MEMORY:0", "foo0" },
+ { "MEMORY:1", "foo1" },
+ { "MEMORY:2", "foo2" },
+};
+#define NCRLIST (sizeof(crlist)/sizeof(struct crlist))
+
+struct chklist {
+ char *pfx;
+ char *res;
+};
+
+struct chklist chklist0[] = {
+ { NULL, NULL },
+ { NULL, NULL },
+ { "MEMORY", "2" },
+ { "MEMORY", "1" },
+ { "MEMORY", "0" },
+ { "MEMORY", "env" },
+};
+#define NCHKLIST0 (sizeof(chklist0)/sizeof(struct chklist))
+
+struct chklist chklist1[] = {
+ { "MEMORY", "env" },
+ { NULL, NULL },
+ { "MEMORY", "2" },
+ { "MEMORY", "1" },
+ { "MEMORY", "0" },
+};
+#define NCHKLIST1 (sizeof(chklist1)/sizeof(struct chklist))
+
+struct chklist chklist2[] = {
+ { "MEMORY", "env" },
+ { NULL, NULL },
+ { "MEMORY", "2" },
+ { "MEMORY", "1" },
+ { "MEMORY", "0" },
+};
+#define NCHKLIST2 (sizeof(chklist2)/sizeof(struct chklist))
+
+krb5_error_code
+cr_cache(krb5_context, const char *, const char *);
+
+krb5_error_code
+do_chk(krb5_context, struct chklist *, int nmax, int *);
+
+int
+do_chk_one(const char *, const char *, struct chklist *);
+
+krb5_error_code
+cr_cache(krb5_context context, const char *ccname, const char *pname)
+{
+ krb5_error_code ret;
+ krb5_principal princ = NULL;
+ krb5_ccache ccache = NULL;
+
+ ret = krb5_cc_resolve(context, ccname, &ccache);
+ if (ret)
+ goto errout;
+ if (pname != NULL) {
+ ret = krb5_parse_name(context, pname, &princ);
+ if (ret)
+ return ret;
+ ret = krb5_cc_initialize(context, ccache, princ);
+ if (ret)
+ goto errout;
+ printf("created cache %s with principal %s\n", ccname, pname);
+ } else
+ printf("created cache %s (uninitialized)\n");
+errout:
+ if (princ != NULL)
+ krb5_free_principal(context, princ);
+ if (ccache != NULL)
+ krb5_cc_close(context, ccache);
+ return ret;
+}
+
+int
+do_chk_one(const char *prefix, const char *name, struct chklist *chk)
+{
+
+ if (chk->pfx == NULL)
+ return 0;
+ if (strcmp(chk->pfx, prefix) || strcmp(chk->res, name)) {
+ fprintf(stderr, "MATCH FAILED: expected %s:%s\n",
+ chk->pfx, chk->res);
+ return 1;
+ }
+ return 0;
+}
+
+krb5_error_code
+do_chk(
+ krb5_context context,
+ struct chklist *chklist,
+ int nmax,
+ int *good)
+{
+ krb5_error_code ret = 0;
+ krb5_cccol_cursor cursor = NULL;
+ krb5_ccache ccache;
+ const char *prefix, *name;
+ int i;
+
+ ret = krb5_cccol_cursor_new(context, &cursor);
+ if (ret) goto errout;
+
+ i = 0;
+ printf(">>>\n");
+ for (i = 0; ; i++) {
+ ret = krb5_cccol_cursor_next(context, cursor, &ccache);
+ if (ret) goto errout;
+ if (ccache == NULL) {
+ printf("<<< end of list\n");
+ break;
+ }
+ prefix = krb5_cc_get_type(context, ccache);
+ name = krb5_cc_get_name(context, ccache);
+ printf("cursor: %s:%s\n", prefix, name);
+
+ if (i < nmax) {
+ if (!do_chk_one(prefix, name, &chklist[i])) {
+ *good = 0;
+ }
+ }
+ ret = krb5_cc_close(context, ccache);
+ if (ret) goto errout;
+ }
+
+ if (i != nmax) {
+ fprintf(stderr, "total ccaches %d != expected ccaches %d\n", i, nmax);
+ *good = 0;
+ }
+
+errout:
+ if (cursor != NULL)
+ krb5_cccol_cursor_free(context, &cursor);
+ return ret;
+}
+
+int
+main(int argc, char *argv[])
+{
+ krb5_error_code ret = 0;
+ krb5_context context;
+ int i, good = 1;
+
+ ret = krb5_init_context(&context);
+ if (ret) exit(1);
+
+ for (i = 0; i < NCRLIST; i++) {
+ ret = cr_cache(context, crlist[i].ccname, crlist[i].pname);
+ if (ret) goto errout;
+ }
+
+#ifdef HAVE_SETENV
+ setenv("KRB5CCNAME", "foo", 1);
+#else
+ putenv("KRB5CCNAME=foo");
+#endif
+ printf("KRB5CCNAME=foo\n");
+ ret = do_chk(context, chklist0, NCHKLIST0, &good);
+ if (ret)
+ goto errout;
+
+#ifdef HAVE_SETENV
+ setenv("KRB5CCNAME", "MEMORY:env", 1);
+#else
+ putenv("KRB5CCNAME=MEMORY:env");
+#endif
+ printf("KRB5CCNAME=MEMORY:env\n");
+ ret = do_chk(context, chklist1, NCHKLIST1, &good);
+ if (ret)
+ goto errout;
+
+ ret = krb5_cc_set_default_name(context, "MEMORY:env");
+ if (ret)
+ goto errout;
+
+ printf("KRB5CCNAME=MEMORY:env, ccdefname=MEMORY:env\n");
+ ret = do_chk(context, chklist2, NCHKLIST2, &good);
+ if (ret)
+ goto errout;
+
+errout:
+ if (ret) {
+ com_err("main", ret, "");
+ exit(1);
+ } else {
+ exit(!good);
+ }
+}
diff --git a/src/lib/krb5/os/ccdefname.c b/src/lib/krb5/os/ccdefname.c
index f9ddecce4a..4a9d184cd7 100644
--- a/src/lib/krb5/os/ccdefname.c
+++ b/src/lib/krb5/os/ccdefname.c
@@ -297,3 +297,22 @@ krb5_cc_default_name(krb5_context context)
return err ? NULL : os_ctx->default_ccname;
}
+
+/*
+ * caller must free name
+ */
+krb5_error_code
+krb5int_cc_os_default_name(krb5_context context, char **name)
+{
+ krb5_error_code retval = 0;
+ char *tmpname = NULL;
+
+ *name = NULL;
+ tmpname = malloc(BUFSIZ);
+ if (tmpname == NULL)
+ return ENOMEM;
+
+ retval = get_from_os(tmpname, BUFSIZ);
+ *name = tmpname;
+ return retval;
+}