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
/* Iterator over file caches. */
struct krb5_fcc_ptcursor_data {
- struct fcc_set *cur;
+ krb5_boolean first;
};
/* An off_t can be arbitrarily complex */
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
{
if (*cursor == NULL)
return 0;
- if ((*cursor)->data != NULL)
- free((*cursor)->data);
+ free((*cursor)->data);
free(*cursor);
*cursor = NULL;
return 0;
#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;
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
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)
* 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)
--- /dev/null
+#!/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.')
/* -*- 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;
}