Remove unneeded cccol behaviors
authorGreg Hudson <ghudson@mit.edu>
Mon, 5 Sep 2011 16:26:43 +0000 (16:26 +0000)
committerGreg Hudson <ghudson@mit.edu>
Mon, 5 Sep 2011 16:26:43 +0000 (16:26 +0000)
Do not yield any default caches in the top level cccol implementation.
In the FILE type, yield the default cache if it exists and is of type
FILE, instead of yielding the set of open file caches.

ticket: 6955

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25156 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/ccache/Makefile.in
src/lib/krb5/ccache/cc_file.c
src/lib/krb5/ccache/cccursor.c
src/lib/krb5/ccache/t_cccol.py [new file with mode: 0644]
src/lib/krb5/ccache/t_cccursor.c

index eaf0e00d43e3f076c1412fe2c76d907965f82a08..00aaae7d6afd0b24b643cb34dc462b2bfd09c810 100644 (file)
@@ -101,11 +101,12 @@ 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 t_cccursor
+check-unix:: t_cc
        KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\
        $(RUN_SETUP) $(VALGRIND) ./t_cc
-       KRB5_CONFIG=$(srcdir)/../krb/t_krb5.conf ; export KRB5_CONFIG ;\
-       $(RUN_SETUP) $(VALGRIND) ./t_cccursor
+
+check-pytests:: t_cccursor
+       $(RUNPYTEST) $(srcdir)/t_cccol.py $(PYTESTFLAGS)
 
 clean-unix::
        $(RM) t_cc t_cc.o t_cccursor t_cccursor.o
index 4599309322f0111e976b4c7fc6c99017db0e1050..39f81d8b4eacfdb694d21841a4681ff0778e5595 100644 (file)
@@ -324,7 +324,7 @@ static struct fcc_set *fccs = NULL;
 
 /* Iterator over file caches.  */
 struct krb5_fcc_ptcursor_data {
-    struct fcc_set *cur;
+    krb5_boolean first;
 };
 
 /* An off_t can be arbitrarily complex */
@@ -2332,71 +2332,53 @@ krb5_fcc_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor)
     if (n == NULL)
         return ENOMEM;
     n->ops = &krb5_fcc_ops;
-    cdata = malloc(sizeof(struct krb5_fcc_ptcursor_data));
+    cdata = malloc(sizeof(*cdata));
     if (cdata == NULL) {
-        ret = ENOMEM;
-        goto errout;
+        free(n);
+        return ENOMEM;
     }
+    cdata->first = TRUE;
     n->data = cdata;
-    ret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
-    if (ret)
-        goto errout;
-    cdata->cur = fccs;
-    ret = k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
-    if (ret)
-        goto errout;
-
-errout:
-    if (ret) {
-        krb5_fcc_ptcursor_free(context, &n);
-    }
     *cursor = n;
     return ret;
 }
 
 static krb5_error_code KRB5_CALLCONV
-krb5_fcc_ptcursor_next(krb5_context context,
-                       krb5_cc_ptcursor cursor,
-                       krb5_ccache *ccache)
+krb5_fcc_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor,
+                       krb5_ccache *cache_out)
 {
-    krb5_error_code ret = 0;
-    struct krb5_fcc_ptcursor_data *cdata = NULL;
-    krb5_ccache n;
-
-    *ccache = NULL;
-    n = malloc(sizeof(*n));
-    if (n == NULL)
-        return ENOMEM;
-
-    cdata = cursor->data;
+    krb5_error_code ret;
+    struct krb5_fcc_ptcursor_data *cdata = cursor->data;
+    const char *defname, *residual;
+    krb5_ccache cache;
+    struct stat sb;
 
-    ret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
-    if (ret)
-        goto errout;
+    *cache_out = NULL;
+    if (!cdata->first)
+        return 0;
+    cdata->first = FALSE;
 
-    if (cdata->cur == NULL) {
-        k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
-        free(n);
-        n = NULL;
-        goto errout;
-    }
+    defname = krb5_cc_default_name(context);
+    if (!defname)
+        return 0;
 
-    n->ops = &krb5_fcc_ops;
-    n->data = cdata->cur->data;
-    cdata->cur->refcount++;
+    /* Check if the default has type FILE or no type; find the residual. */
+    if (strncmp(defname, "FILE:", 5) == 0)
+        residual = defname + 5;
+    else if (strchr(defname + 2, ':') == NULL)  /* Skip drive prefix if any. */
+        residual = defname;
+    else
+        return 0;
 
-    cdata->cur = cdata->cur->next;
+    /* Don't yield a nonexistent default file cache. */
+    if (stat(residual, &sb) != 0)
+        return 0;
 
-    ret = k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+    ret = krb5_cc_resolve(context, defname, &cache);
     if (ret)
-        goto errout;
-errout:
-    if (ret && n != NULL) {
-        free(n);
-        n = NULL;
-    }
-    *ccache = n;
-    return ret;
+        return ret;
+    *cache_out = cache;
+    return 0;
 }
 
 static krb5_error_code KRB5_CALLCONV
@@ -2405,8 +2387,7 @@ krb5_fcc_ptcursor_free(krb5_context context,
 {
     if (*cursor == NULL)
         return 0;
-    if ((*cursor)->data != NULL)
-        free((*cursor)->data);
+    free((*cursor)->data);
     free(*cursor);
     *cursor = NULL;
     return 0;
index 7bb074938535e2e5901c05175e7908e6385f263d..2efaa322c76753d3b3156fef45cecab8a33a64ca 100644 (file)
 
 #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;
@@ -113,62 +81,44 @@ errout:
 krb5_error_code KRB5_CALLCONV
 krb5_cccol_cursor_next(krb5_context context,
                        krb5_cccol_cursor cursor,
-                       krb5_ccache *ccache)
+                       krb5_ccache *ccache_out)
 {
     krb5_error_code ret = 0;
-    char *name;
-    krb5_os_context os_ctx = NULL;
+    krb5_ccache ccache;
 
-    *ccache = NULL;
-    os_ctx = &context->os_context;
+    *ccache_out = NULL;
 
-    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;
+    /* Are we out of backends? */
+    if (cursor->ops == NULL)
+        return 0;
+
+    while (1) {
+        ret = cursor->ops->ptcursor_next(context, cursor->ptcursor, &ccache);
+        if (ret)
+            return ret;
+        if (ccache != NULL) {
+            *ccache_out = ccache;
+            return 0;
         }
-        /* fall through */
-    case CCCURSOR_PERTYPE:
-        cursor->pos = CCCURSOR_PERTYPE;
+
+        ret = cursor->ops->ptcursor_free(context, &cursor->ptcursor);
+        if (ret)
+            return ret;
+
         do {
-            ret = cccol_pertype_next(context, cursor, ccache);
+            /* Find next type with ptcursor functionality. */
+            ret = krb5int_cc_typecursor_next(context, cursor->typecursor,
+                                             &cursor->ops);
             if (ret)
-                goto errout;
-        } while (cccol_already(context, cursor, ccache));
-        break;
+                return ret;
+            if (cursor->ops == NULL)
+                return 0;
+        } while (cursor->ops->ptcursor_new == NULL);
+
+        ret = cursor->ops->ptcursor_new(context, &cursor->ptcursor);
+        if (ret)
+            return ret;
     }
-errout:
-    return ret;
 }
 
 krb5_error_code KRB5_CALLCONV
@@ -176,17 +126,10 @@ 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)
@@ -232,133 +175,6 @@ krb5_cccol_last_change_time(krb5_context context,
  * krb5_cccol_lock and krb5_cccol_unlock are defined in ccbase.c
  */
 
-/*
- * 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;
-}
-
 krb5_error_code
 krb5_cc_cache_match(krb5_context context, krb5_principal client,
                     krb5_ccache *cache_out)
diff --git a/src/lib/krb5/ccache/t_cccol.py b/src/lib/krb5/ccache/t_cccol.py
new file mode 100644 (file)
index 0000000..d809971
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+from k5test import *
+
+realm = K5Realm(create_host=False, start_kadmind=False)
+
+realm.addprinc('alice', password('alice'))
+realm.addprinc('bob', password('bob'))
+
+ccdir = os.path.join(realm.testdir, 'cc')
+dccname = 'DIR:%s' % ccdir
+duser = 'DIR::%s/tkt1' % ccdir
+dalice = 'DIR::%s/tkt2' % ccdir
+dbob = 'DIR::%s/tkt3' % ccdir
+os.mkdir(ccdir)
+realm.kinit('user', password('user'), flags=['-c', duser])
+realm.kinit('alice', password('alice'), flags=['-c', dalice])
+realm.kinit('bob', password('bob'), flags=['-c', dbob])
+
+def cursor_test(testname, args, expected):
+    outlines = realm.run_as_client(['./t_cccursor'] + args).splitlines()
+    outlines.sort()
+    expected.sort()
+    if outlines != expected:
+        fail('Output not expected for %s\n' % testname +
+             'Expected output:\n\n' + '\n'.join(expected) + '\n\n' +
+             'Actual output:\n\n' + '\n'.join(outlines))
+
+fccname = 'FILE:%s' % realm.ccache
+cursor_test('file-default', [], [fccname])
+cursor_test('file-default2', [realm.ccache], [fccname])
+cursor_test('file-default3', [fccname], [fccname])
+
+cursor_test('dir', [dccname], [duser, dalice, dbob])
+
+mfoo = 'MEMORY:foo'
+mbar = 'MEMORY:bar'
+cursor_test('filemem', [fccname, mfoo, mbar], [fccname, mfoo, mbar])
+cursor_test('dirmem', [dccname, mfoo], [duser, dalice, dbob, mfoo])
+
+# Make sure FILE doesn't yield a nonexistent default cache.
+realm.run_as_client([kdestroy])
+cursor_test('noexist', [], [])
+
+success('Renewing credentials.')
index b708aa6f95c1efaa5f79b8d18c5d839984d27e82..a0c758603ab45626ac7407cc8e017162d2948827 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/ccache/t_cccursor.c */
+/* lib/krb5/ccache/t_cccursor.c - Simple test harness for cccol API */
 /*
- * Copyright 2006 by the Massachusetts Institute of Technology.
+ * Copyright 2011 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
  * 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
-dest_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", ccname);
-errout:
-    if (princ != NULL)
-        krb5_free_principal(context, princ);
-    if (ccache != NULL)
-        krb5_cc_close(context, ccache);
-    return ret;
-}
-
-krb5_error_code
-dest_cache(krb5_context context, const char *ccname, const char *pname)
-{
-    krb5_error_code ret;
-    krb5_ccache ccache = NULL;
+/*
+ * Displays a list of caches returned by the cccol cursor.  The first argument,
+ * if given, is set to the default cache name for the context before iterating.
+ * Any remaining argments are resolved as caches and kept open during the
+ * iteration.
+ */
 
-    ret = krb5_cc_resolve(context, ccname, &ccache);
-    if (ret)
-        goto errout;
-    if (pname != NULL) {
-        ret = krb5_cc_destroy(context, ccache);
-        if (ret)
-            return ret;
-        printf("Destroyed cache %s\n", ccname);
-    } else {
-        printf("Closed cache %s (uninitialized)\n", ccname);
-        ret = krb5_cc_close(context, ccache);
-    }
-errout:
-    return ret;
-}
+#include "k5-int.h"
 
 int
-do_chk_one(const char *prefix, const char *name, struct chklist *chk)
+main(int argc, char **argv)
 {
-
-    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;
+    krb5_context ctx;
+    krb5_cccol_cursor cursor;
+    krb5_ccache cache, hold[64];
     int i;
+    char *name;
 
-    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;
-    }
+    assert(krb5_init_context(&ctx) == 0);
+    if (argc > 1)
+        assert(krb5_cc_set_default_name(ctx, argv[1]) == 0);
 
-    if (i != nmax) {
-        fprintf(stderr, "total ccaches %d != expected ccaches %d\n", i, nmax);
-        *good = 0;
+    if (argc > 2) {
+        assert(argc < 60);
+        for (i = 2; i < argc; i++)
+            assert(krb5_cc_resolve(ctx, argv[i], &hold[i - 2]) == 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;
-    unsigned int i;
-    int 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;
-
-    for (i = 0; i < NCRLIST; i++) {
-        ret = dest_cache(context, crlist[i].ccname, crlist[i].pname);
-        if (ret) goto errout;
+    assert(krb5_cccol_cursor_new(ctx, &cursor) == 0);
+    while (1) {
+        assert(krb5_cccol_cursor_next(ctx, cursor, &cache) == 0);
+        if (cache == NULL)
+            break;
+        assert(krb5_cc_get_full_name(ctx, cache, &name) == 0);
+        printf("%s\n", name);
+        krb5_free_string(ctx, name);
+        krb5_cc_close(ctx, cache);
     }
+    assert(krb5_cccol_cursor_free(ctx, &cursor) == 0);
 
-errout:
-    krb5_free_context(context);
-    if (ret) {
-        com_err("main", ret, "");
-        exit(1);
-    } else {
-        exit(!good);
-    }
+    for (i = 2; i < argc; i++)
+        krb5_cc_close(ctx, hold[i - 2]);
+    return 0;
 }