cursor for iterating over ccaches
authorTom Yu <tlyu@mit.edu>
Thu, 5 Oct 2006 22:58:41 +0000 (22:58 +0000)
committerTom Yu <tlyu@mit.edu>
Thu, 5 Oct 2006 22:58:41 +0000 (22:58 +0000)
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
src/include/krb5/krb5.hin
src/lib/krb5/ccache/Makefile.in
src/lib/krb5/ccache/cc_file.c
src/lib/krb5/ccache/cc_memory.c
src/lib/krb5/ccache/cc_mslsa.c
src/lib/krb5/ccache/ccapi/stdcc.c
src/lib/krb5/ccache/ccbase.c
src/lib/krb5/ccache/cccursor.c [new file with mode: 0644]
src/lib/krb5/ccache/t_cccursor.c [new file with mode: 0644]
src/lib/krb5/os/ccdefname.c

index 53b2acbf2b3b01e61ab8fc273b5d9a7bdc619152..8455fe47d87e73b0ddb0133615e1ebcaab66f46a 100644 (file)
@@ -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;
index 32b714adb1b7269cf597066a154da90c51fcec86..354ff12b116277d36b9cb9e260ff0c66c35026c9 100644 (file)
@@ -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"
  */
index 7d611f839207f213551d301ab1dd3af441e3cc1e..f2c137e5eac1a7c753bd0f73c7c8f5c8639718e4 100644 (file)
@@ -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 
index 8c35acd45cef0edaa00da510408e336403571a32..5b11a0e01be76ba855318fd389e63fe7ce5b44ee 100644 (file)
@@ -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,
 };
index 9b5ee9f3887fdfc07c438454b121ca00bf59ed72..88cd6fbbfa75edbf07af1f14c367118fca35d5d5 100644 (file)
@@ -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,
 };
index 4bb6d752bf35bebf61b1af6acf996591a11fe265..381484ca501a413833cc5994261d3dcdfd37aeb7 100644 (file)
@@ -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 */
index b4354c7a240107b4fa9686ffee1c6718ca702a0d..c9133efcd540de3af8bb9a1cedaae8ac2ab2a722 100644 (file)
@@ -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
 };
 
index 431e43bc93ef11263655517b5c1699fc7ea1d08a..044f48e488d564b85448197aa606c48d842b24e8 100644 (file)
@@ -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 (file)
index 0000000..9a57d52
--- /dev/null
@@ -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 (file)
index 0000000..8939c6a
--- /dev/null
@@ -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);
+    }
+}
index f9ddecce4af23813d516156b653d83cf04e41309..4a9d184cd7ec5a0ab00570bf77d0913dcf5d0307 100644 (file)
@@ -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;
+}