From 0899feef5ea10df79ded4e215d8f5cfcf75e9451 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Thu, 5 Oct 2006 22:58:41 +0000 Subject: [PATCH] cursor for iterating over ccaches Some ccache back ends need per-type cursors implemented. * src/include/k5-int.h: Declare krb5_cc_ptcursor. Update krb5_cc_ops vector to include functions for ptcursor and some not-yet-implemented functionality. * src/include/krb5/krb5.hin: Prototype krb5_cccol_cursor_new, krb5_cccol_cursor_next, krb5_cccol_cursor_free. * src/lib/krb5/ccache/Makefile.in: Compile cccursor.c. Build t_cccursor. * src/lib/krb5/ccache/cccursor.c: Implementation of cursor for iterating over ccaches. * src/lib/krb5/ccache/ccbase.c: Add typecursor functionality for iteration over registered ccache types. * src/lib/krb5/ccache/cc_memory.c: Implmement per-type ccache cursor functionality. * src/lib/krb5/ccache/cc_mslsa.c: * src/lib/krb5/ccache/cc_file.c: * src/lib/krb5/ccache/ccapi/stdcc.c: Add place-holder ops vector entries. * src/lib/krb5/ccache/t_cccursor.c: New test of ccache cursor functionality. * src/lib/krb5/os/ccdefname.c (krb5int_cc_os_default_name): New function to return the OS-specific default ccache name. ticket: new status: open git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18651 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/k5-int.h | 44 ++++ src/include/krb5/krb5.hin | 19 ++ src/lib/krb5/ccache/Makefile.in | 7 + src/lib/krb5/ccache/cc_file.c | 6 + src/lib/krb5/ccache/cc_memory.c | 109 ++++++++++ src/lib/krb5/ccache/cc_mslsa.c | 8 +- src/lib/krb5/ccache/ccapi/stdcc.c | 16 +- src/lib/krb5/ccache/ccbase.c | 72 +++++++ src/lib/krb5/ccache/cccursor.c | 330 ++++++++++++++++++++++++++++++ src/lib/krb5/ccache/t_cccursor.c | 234 +++++++++++++++++++++ src/lib/krb5/os/ccdefname.c | 19 ++ 11 files changed, 861 insertions(+), 3 deletions(-) create mode 100644 src/lib/krb5/ccache/cccursor.c create mode 100644 src/lib/krb5/ccache/t_cccursor.c diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 53b2acbf2..8455fe47d 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 32b714adb..354ff12b1 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 7d611f839..f2c137e5e 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 8c35acd45..5b11a0e01 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 9b5ee9f38..88cd6fbbf 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 4bb6d752b..381484ca5 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 b4354c7a2..c9133efcd 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 431e43bc9..044f48e48 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 000000000..9a57d5223 --- /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 + +#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 000000000..8939c6a60 --- /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 +#include +#include +#include + +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 f9ddecce4..4a9d184cd 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; +} -- 2.26.2