Merge 1.7 work on auxiliary ccache functions necessary for KIM. Adds krb5_cc_lock...
authorJustin Anderson <jander@mit.edu>
Mon, 22 Sep 2008 17:03:51 +0000 (17:03 +0000)
committerJustin Anderson <jander@mit.edu>
Mon, 22 Sep 2008 17:03:51 +0000 (17:03 +0000)
Locking functions work the same as the CCAPI cc_ccache_lock / cc_context_lock functions, though not as read/write locks.

ticket: 6124
status: open

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

src/include/k5-int.h
src/include/krb5/krb5.hin
src/lib/krb5/ccache/cc-int.h
src/lib/krb5/ccache/cc_file.c
src/lib/krb5/ccache/cc_keyring.c
src/lib/krb5/ccache/cc_memory.c
src/lib/krb5/ccache/ccapi/stdcc.c
src/lib/krb5/ccache/ccapi/stdcc.h
src/lib/krb5/ccache/ccbase.c
src/lib/krb5/ccache/cccursor.c
src/lib/krb5/ccache/ccfns.c

index 545bd983aec23468f6b91b60c740833f4dae97d4..111b12159d494b1b99bd9fe6240730a1fa7fd97a 100644 (file)
@@ -2027,11 +2027,14 @@ struct _krb5_cc_ops {
                                                   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 *move)(krb5_context, krb5_ccache, 
+                                               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 *);
+    krb5_error_code (KRB5_CALLCONV *lock)(krb5_context, krb5_ccache);
+    krb5_error_code (KRB5_CALLCONV *unlock)(krb5_context, krb5_ccache);
 };
 
 extern const krb5_cc_ops *krb5_cc_dfl_ops;
@@ -2039,6 +2042,37 @@ extern const krb5_cc_ops *krb5_cc_dfl_ops;
 krb5_error_code
 krb5int_cc_os_default_name(krb5_context context, char **name);
 
+/* reentrant mutex used by krb5_cc_* functions */
+typedef struct _k5_cc_mutex {
+    k5_mutex_t lock;
+    krb5_context owner;
+    krb5_int32 refcount;
+} k5_cc_mutex;
+
+#define K5_CC_MUTEX_PARTIAL_INITIALIZER \
+       { K5_MUTEX_PARTIAL_INITIALIZER, NULL, 0 }
+
+krb5_error_code
+k5_cc_mutex_init(k5_cc_mutex *m);
+
+krb5_error_code
+k5_cc_mutex_finish_init(k5_cc_mutex *m);
+
+#define k5_cc_mutex_destroy(M) \
+k5_mutex_destroy(&(M)->lock);
+
+void
+k5_cc_mutex_assert_locked(krb5_context context, k5_cc_mutex *m);
+
+void
+k5_cc_mutex_assert_unlocked(krb5_context context, k5_cc_mutex *m);
+
+krb5_error_code
+k5_cc_mutex_lock(krb5_context context, k5_cc_mutex *m);
+
+krb5_error_code
+k5_cc_mutex_unlock(krb5_context context, k5_cc_mutex *m);
+
 typedef struct _krb5_donot_replay {
     krb5_magic magic;
     krb5_ui_4 hash;
index 403bb9f6669260debb339235331ac105293ae080..82e52ab523d8ef167f811bad197fefaf3a46a87e 100644 (file)
@@ -1296,6 +1296,22 @@ 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_cc_move (krb5_context context, krb5_ccache src, krb5_ccache dst);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_last_change_time (
+    krb5_context context, 
+    krb5_ccache ccache, 
+    krb5_timestamp *change_time);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_lock (krb5_context context, krb5_ccache ccache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_unlock (krb5_context context, krb5_ccache ccache);
+
+
 krb5_error_code KRB5_CALLCONV
 krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor);
 
@@ -1308,6 +1324,15 @@ krb5_cccol_cursor_next(
 krb5_error_code KRB5_CALLCONV
 krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor);
 
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_last_change_time(krb5_context context, krb5_timestamp *change_time);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_lock(krb5_context context);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_unlock(krb5_context context);
+
 krb5_error_code KRB5_CALLCONV
 krb5_cc_new_unique(
     krb5_context context,
index e533f4667674838e973003348e0dbe8a4e1d2409..4c0db959d759fd1ed87514feccf44cc1f96a8c6e 100644 (file)
@@ -65,8 +65,22 @@ krb5int_cc_typecursor_free(
     krb5_cc_typecursor *cursor);
 
 
-extern k5_mutex_t krb5int_mcc_mutex;
-extern k5_mutex_t krb5int_krcc_mutex;
-extern k5_mutex_t krb5int_cc_file_mutex;
+extern k5_cc_mutex krb5int_mcc_mutex;
+extern k5_cc_mutex krb5int_krcc_mutex;
+extern k5_cc_mutex krb5int_cc_file_mutex;
+
+#ifdef USE_CCAPI_V3
+extern krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_lock
+(krb5_context context); 
+
+extern krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_unlock
+(krb5_context context);
+#endif
+
+krb5_error_code
+k5_cc_mutex_force_unlock(k5_cc_mutex *m);
+
+krb5_error_code
+k5_cccol_force_unlock(void);
 
 #endif /* __KRB5_CCACHE_H__ */
index a24ff4502f7db5533feccb7269d515bfe2c4546e..22c01b8b705a312fc5ed7903e8da81a1dba88fa3 100644 (file)
@@ -166,6 +166,25 @@ static krb5_error_code krb5_fcc_skip_principal
 static krb5_error_code KRB5_CALLCONV krb5_fcc_set_flags
         (krb5_context, krb5_ccache id, krb5_flags flags);
 
+static krb5_error_code KRB5_CALLCONV krb5_fcc_ptcursor_new
+        (krb5_context context, krb5_cc_ptcursor *cursor);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_ptcursor_next
+        (krb5_context context, krb5_cc_ptcursor cursor, krb5_ccache *ccache);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_ptcursor_free
+        (krb5_context context, krb5_cc_ptcursor *cursor);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_last_change_time
+        (krb5_context context, krb5_ccache id, krb5_timestamp *change_time);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_lock
+        (krb5_context context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_unlock
+        (krb5_context context, krb5_ccache id);
+
+
 extern const krb5_cc_ops krb5_cc_file_ops;
 
 krb5_error_code krb5_change_cache (void);
@@ -205,6 +224,9 @@ static krb5_error_code krb5_fcc_close_file
         (krb5_context, struct _krb5_fcc_data *data);
 static krb5_error_code krb5_fcc_open_file
         (krb5_context, krb5_ccache, int);
+static krb5_error_code krb5_fcc_data_last_change_time
+        (krb5_context context, struct _krb5_fcc_data *data, 
+        krb5_timestamp *change_time);
 
 
 #define KRB5_OK 0
@@ -261,7 +283,7 @@ typedef struct _krb5_fcc_data {
     /* Lock this one before reading or modifying the data stored here
        that can be changed.  (Filename is fixed after
        initialization.)  */
-    k5_mutex_t lock;
+    k5_cc_mutex lock;
     int file;
     krb5_flags flags;
     int mode;                          /* needed for locking code */
@@ -301,9 +323,14 @@ struct fcc_set {
     unsigned int refcount;
 };
 
-k5_mutex_t krb5int_cc_file_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+k5_cc_mutex krb5int_cc_file_mutex = K5_CC_MUTEX_PARTIAL_INITIALIZER;
 static struct fcc_set *fccs = NULL;
 
+/* Iterator over file caches.  */
+struct krb5_fcc_ptcursor_data {
+    struct fcc_set *cur;
+};
+
 /* An off_t can be arbitrarily complex */
 typedef struct _krb5_fcc_cursor {
     off_t pos;
@@ -311,12 +338,12 @@ typedef struct _krb5_fcc_cursor {
 
 #define MAYBE_OPEN(CONTEXT, ID, MODE)                                  \
 {                                                                      \
-    k5_assert_locked(&((krb5_fcc_data *)(ID)->data)->lock);            \
+    k5_cc_mutex_assert_locked(CONTEXT, &((krb5_fcc_data *)(ID)->data)->lock);          \
     if (OPENCLOSE (ID)) {                                              \
        krb5_error_code maybe_open_ret;                                 \
        maybe_open_ret = krb5_fcc_open_file (CONTEXT,ID,MODE);          \
        if (maybe_open_ret) {                                           \
-           k5_mutex_unlock(&((krb5_fcc_data *)(ID)->data)->lock);      \
+           k5_cc_mutex_unlock(CONTEXT, &((krb5_fcc_data *)(ID)->data)->lock);  \
            return maybe_open_ret;                                      \
        }                                                               \
     }                                                                  \
@@ -356,7 +383,7 @@ krb5_fcc_read(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned i
 #if 0
      int ret;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      ret = read(((krb5_fcc_data *) id->data)->file, (char *) buf, len);
      if (ret == -1)
@@ -368,7 +395,7 @@ krb5_fcc_read(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned i
 #else
      krb5_fcc_data *data = (krb5_fcc_data *) id->data;
 
-     k5_assert_locked(&data->lock);
+     k5_cc_mutex_assert_locked(context, &data->lock);
 
      while (len > 0) {
         int nread, e;
@@ -441,7 +468,7 @@ krb5_fcc_read_principal(krb5_context context, krb5_ccache id, krb5_principal *pr
     krb5_int32 length, type;
     int i;
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     *princ = NULL;
 
@@ -517,7 +544,7 @@ krb5_fcc_read_addrs(krb5_context context, krb5_ccache id, krb5_address ***addrs)
      size_t msize;
      int i;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      *addrs = 0;
 
@@ -565,7 +592,7 @@ krb5_fcc_read_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *keyb
      krb5_ui_2 ui2;
      krb5_int32 int32;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      keyblock->magic = KV5M_KEYBLOCK;
      keyblock->contents = 0;
@@ -613,7 +640,7 @@ krb5_fcc_read_data(krb5_context context, krb5_ccache id, krb5_data *data)
      krb5_error_code kret;
      krb5_int32 len;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      data->magic = KV5M_DATA;
      data->data = 0;
@@ -655,7 +682,7 @@ krb5_fcc_read_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
      krb5_ui_2 ui2;
      krb5_int32 int32;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      addr->magic = KV5M_ADDRESS;
      addr->contents = 0;
@@ -701,7 +728,7 @@ krb5_fcc_read_int32(krb5_context context, krb5_ccache id, krb5_int32 *i)
     unsigned char buf[4];
     krb5_int32 val;
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     if ((data->version == KRB5_FCC_FVNO_1) ||
        (data->version == KRB5_FCC_FVNO_2)) 
@@ -726,7 +753,7 @@ krb5_fcc_read_ui_2(krb5_context context, krb5_ccache id, krb5_ui_2 *i)
     krb5_error_code retval;
     unsigned char buf[2];
     
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     if ((data->version == KRB5_FCC_FVNO_1) ||
        (data->version == KRB5_FCC_FVNO_2))
@@ -743,7 +770,7 @@ krb5_fcc_read_ui_2(krb5_context context, krb5_ccache id, krb5_ui_2 *i)
 static krb5_error_code
 krb5_fcc_read_octet(krb5_context context, krb5_ccache id, krb5_octet *i)
 {
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
     return krb5_fcc_read(context, id, (krb5_pointer) i, 1);
 }    
 
@@ -755,7 +782,7 @@ krb5_fcc_read_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
     krb5_error_code retval;
     krb5_int32 i;
     
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     if ((data->version == KRB5_FCC_FVNO_1) ||
        (data->version == KRB5_FCC_FVNO_2))
@@ -790,7 +817,7 @@ krb5_fcc_read_authdata(krb5_context context, krb5_ccache id, krb5_authdata ***a)
      size_t msize;
      int i;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      *a = 0;
 
@@ -840,7 +867,7 @@ krb5_fcc_read_authdatum(krb5_context context, krb5_ccache id, krb5_authdata *a)
     krb5_int32 int32;
     krb5_ui_2 ui2;
     
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     a->magic = KV5M_AUTHDATA;
     a->contents = NULL;
@@ -896,7 +923,7 @@ krb5_fcc_write(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned
 {
      int ret;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
      invalidate_cache((krb5_fcc_data *) id->data);
 
      ret = write(((krb5_fcc_data *)id->data)->file, (char *) buf, len);
@@ -930,7 +957,7 @@ krb5_fcc_store_principal(krb5_context context, krb5_ccache id, krb5_principal pr
     krb5_error_code ret;
     krb5_int32 i, length, tmp, type;
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     type = krb5_princ_type(context, princ);
     tmp = length = krb5_princ_size(context, princ);
@@ -968,7 +995,7 @@ krb5_fcc_store_addrs(krb5_context context, krb5_ccache id, krb5_address **addrs)
      krb5_address **temp;
      krb5_int32 i, length = 0;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      /* Count the number of components */
      if (addrs) {
@@ -993,7 +1020,7 @@ krb5_fcc_store_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *key
      krb5_fcc_data *data = (krb5_fcc_data *)id->data;
      krb5_error_code ret;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      ret = krb5_fcc_store_ui_2(context, id, keyblock->enctype);
      CHECK(ret);
@@ -1011,7 +1038,7 @@ krb5_fcc_store_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
 {
      krb5_error_code ret;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      ret = krb5_fcc_store_ui_2(context, id, addr->addrtype);
      CHECK(ret);
@@ -1026,7 +1053,7 @@ krb5_fcc_store_data(krb5_context context, krb5_ccache id, krb5_data *data)
 {
      krb5_error_code ret;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      ret = krb5_fcc_store_ui_4(context, id, data->length);
      CHECK(ret);
@@ -1045,7 +1072,7 @@ krb5_fcc_store_ui_4(krb5_context context, krb5_ccache id, krb5_ui_4 i)
     krb5_fcc_data *data = (krb5_fcc_data *)id->data;
     unsigned char buf[4];
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     if ((data->version == KRB5_FCC_FVNO_1) ||
        (data->version == KRB5_FCC_FVNO_2)) 
@@ -1069,7 +1096,7 @@ krb5_fcc_store_ui_2(krb5_context context, krb5_ccache id, krb5_int32 i)
     krb5_ui_2 ibuf;
     unsigned char buf[2];
     
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     if ((data->version == KRB5_FCC_FVNO_1) ||
        (data->version == KRB5_FCC_FVNO_2)) {
@@ -1088,7 +1115,7 @@ krb5_fcc_store_octet(krb5_context context, krb5_ccache id, krb5_int32 i)
 {
     krb5_octet ibuf;
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     ibuf = (krb5_octet) i;
     return krb5_fcc_write(context, id, (char *) &ibuf, 1);
@@ -1100,7 +1127,7 @@ krb5_fcc_store_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
     krb5_fcc_data *data = (krb5_fcc_data *)id->data;
     krb5_error_code retval;
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     if ((data->version == KRB5_FCC_FVNO_1) ||
        (data->version == KRB5_FCC_FVNO_2))
@@ -1125,7 +1152,7 @@ krb5_fcc_store_authdata(krb5_context context, krb5_ccache id, krb5_authdata **a)
     krb5_authdata **temp;
     krb5_int32 i, length=0;
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     if (a != NULL) {
        for (temp=a; *temp; temp++)
@@ -1146,7 +1173,7 @@ krb5_fcc_store_authdatum (krb5_context context, krb5_ccache id, krb5_authdata *a
 {
     krb5_error_code ret;
 
-    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
     ret = krb5_fcc_store_ui_2(context, id, a->ad_type);
     CHECK(ret);
@@ -1162,7 +1189,7 @@ krb5_fcc_close_file (krb5_context context, krb5_fcc_data *data)
      int ret;
      krb5_error_code retval;
 
-     k5_assert_locked(&data->lock);
+     k5_cc_mutex_assert_locked(context, &data->lock);
 
      if (data->file == NO_FILE)
         return KRB5_FCC_INTERNAL;
@@ -1201,7 +1228,7 @@ krb5_fcc_open_file (krb5_context context, krb5_ccache id, int mode)
     int lock_flag;
     krb5_error_code retval = 0;
 
-    k5_assert_locked(&data->lock);
+    k5_cc_mutex_assert_locked(context, &data->lock);
     invalidate_cache(data);
 
     if (data->file != NO_FILE) {
@@ -1384,7 +1411,7 @@ krb5_fcc_skip_header(krb5_context context, krb5_ccache id)
      krb5_error_code kret;
      krb5_ui_2 fcc_flen;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      fcc_lseek(data, (off_t) sizeof(krb5_ui_2), SEEK_SET);
      if (data->version == KRB5_FCC_FVNO_4) {
@@ -1402,7 +1429,7 @@ krb5_fcc_skip_principal(krb5_context context, krb5_ccache id)
      krb5_error_code kret;
      krb5_principal princ;
 
-     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
 
      kret = krb5_fcc_read_principal(context, id, &princ);
      if (kret != KRB5_OK)
@@ -1431,7 +1458,7 @@ krb5_fcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
      krb5_error_code kret = 0;
      int reti = 0;
 
-     kret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+     kret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
      if (kret)
         return kret;
 
@@ -1447,7 +1474,7 @@ krb5_fcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
          if (reti == -1) {
              kret = krb5_fcc_interpret(context, errno);
              MAYBE_CLOSE(context, id, kret);
-            k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+            k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
              return kret;
          }
      }
@@ -1455,7 +1482,7 @@ krb5_fcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
      kret = krb5_fcc_store_principal(context, id, princ);
 
      MAYBE_CLOSE(context, id, kret);
-     k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
      krb5_change_cache ();
      return kret;
 }
@@ -1469,7 +1496,7 @@ static krb5_error_code dereference(krb5_context context, krb5_fcc_data *data)
     krb5_error_code kerr;
     struct fcc_set **fccsp;
 
-    kerr = k5_mutex_lock(&krb5int_cc_file_mutex);
+    kerr = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
     if (kerr)
        return kerr;
     for (fccsp = &fccs; *fccsp != NULL; fccsp = &(*fccsp)->next)
@@ -1484,21 +1511,21 @@ static krb5_error_code dereference(krb5_context context, krb5_fcc_data *data)
        temp = *fccsp;
        *fccsp = (*fccsp)->next;
        free(temp);
-       k5_mutex_unlock(&krb5int_cc_file_mutex);
-       k5_mutex_assert_unlocked(&data->lock);
+       k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+       k5_cc_mutex_assert_unlocked(context, &data->lock);
        free(data->filename);
        zap(data->buf, sizeof(data->buf));
        if (data->file >= 0) {
-           kerr = k5_mutex_lock(&data->lock);
+           kerr = k5_cc_mutex_lock(context, &data->lock);
            if (kerr)
                return kerr;
            krb5_fcc_close_file(context, data);
-           k5_mutex_unlock(&data->lock);
+           k5_cc_mutex_unlock(context, &data->lock);
        }
-       k5_mutex_destroy(&data->lock);
+       k5_cc_mutex_destroy(&data->lock);
        free(data);
     } else
-       k5_mutex_unlock(&krb5int_cc_file_mutex);
+       k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
     return 0;
 }
 
@@ -1537,7 +1564,7 @@ krb5_fcc_destroy(krb5_context context, krb5_ccache id)
      unsigned int wlen;
      char zeros[BUFSIZ];
 
-     kret = k5_mutex_lock(&data->lock);
+     kret = k5_cc_mutex_lock(context, &data->lock);
      if (kret)
         return kret;
 
@@ -1647,7 +1674,7 @@ krb5_fcc_destroy(krb5_context context, krb5_ccache id)
 #endif /* MSDOS_FILESYSTEM */
 
   cleanup:
-     k5_mutex_unlock(&data->lock);
+     k5_cc_mutex_unlock(context, &data->lock);
      dereference(context, data);
      krb5_xfree(id);
 
@@ -1684,7 +1711,7 @@ krb5_fcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
      krb5_fcc_data *data;
      struct fcc_set *setptr;
 
-     kret = k5_mutex_lock(&krb5int_cc_file_mutex);
+     kret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
      if (kret)
         return kret;
      for (setptr = fccs; setptr; setptr = setptr->next) {
@@ -1696,35 +1723,35 @@ krb5_fcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
         assert(setptr->refcount != 0);
         setptr->refcount++;
         assert(setptr->refcount != 0);
-        kret = k5_mutex_lock(&data->lock);
+        kret = k5_cc_mutex_lock(context, &data->lock);
         if (kret) {
-            k5_mutex_unlock(&krb5int_cc_file_mutex);
+            k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
             return kret;
         }
-        k5_mutex_unlock(&krb5int_cc_file_mutex);
+        k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
      } else {
         data = malloc(sizeof(krb5_fcc_data));
         if (data == NULL) {
-            k5_mutex_unlock(&krb5int_cc_file_mutex);
+            k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
             return KRB5_CC_NOMEM;
         }
         data->filename = strdup(residual);
         if (data->filename == NULL) {
-            k5_mutex_unlock(&krb5int_cc_file_mutex);
+            k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
             free(data);
             return KRB5_CC_NOMEM;
         }
-        kret = k5_mutex_init(&data->lock);
+        kret = k5_cc_mutex_init(&data->lock);
         if (kret) {
-            k5_mutex_unlock(&krb5int_cc_file_mutex);
+            k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
             free(data->filename);
             free(data);
             return kret;
         }
-        kret = k5_mutex_lock(&data->lock);
+        kret = k5_cc_mutex_lock(context, &data->lock);
         if (kret) {
-            k5_mutex_unlock(&krb5int_cc_file_mutex);
-            k5_mutex_destroy(&data->lock);
+            k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+            k5_cc_mutex_destroy(&data->lock);
             free(data->filename);
             free(data);
             return kret;
@@ -1736,9 +1763,9 @@ krb5_fcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
         data->valid_bytes = 0;
         setptr = malloc(sizeof(struct fcc_set));
         if (setptr == NULL) {
-            k5_mutex_unlock(&krb5int_cc_file_mutex);
-            k5_mutex_unlock(&data->lock);
-            k5_mutex_destroy(&data->lock);
+            k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+            k5_cc_mutex_unlock(context, &data->lock);
+            k5_cc_mutex_destroy(&data->lock);
             free(data->filename);
             free(data);
             return KRB5_CC_NOMEM;
@@ -1747,11 +1774,11 @@ krb5_fcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
         setptr->data = data;
         setptr->next = fccs;
         fccs = setptr;
-        k5_mutex_unlock(&krb5int_cc_file_mutex);
+        k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
      }
 
-     k5_mutex_assert_locked(&data->lock);
-     k5_mutex_unlock(&data->lock);
+     k5_cc_mutex_assert_locked(context, &data->lock);
+     k5_cc_mutex_unlock(context, &data->lock);
      lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
      if (lid == NULL) {
         dereference(context, data);
@@ -1789,20 +1816,20 @@ krb5_fcc_start_seq_get(krb5_context context, krb5_ccache id,
      krb5_error_code kret = KRB5_OK;
      krb5_fcc_data *data = (krb5_fcc_data *)id->data;
 
-     kret = k5_mutex_lock(&data->lock);
+     kret = k5_cc_mutex_lock(context, &data->lock);
      if (kret)
         return kret;
 
      fcursor = (krb5_fcc_cursor *) malloc(sizeof(krb5_fcc_cursor));
      if (fcursor == NULL) {
-        k5_mutex_unlock(&data->lock);
+        k5_cc_mutex_unlock(context, &data->lock);
         return KRB5_CC_NOMEM;
      }
      if (OPENCLOSE(id)) {
           kret = krb5_fcc_open_file(context, id, FCC_OPEN_RDONLY);
           if (kret) {
               krb5_xfree(fcursor);
-             k5_mutex_unlock(&data->lock);
+             k5_cc_mutex_unlock(context, &data->lock);
               return kret;
           }
      }
@@ -1824,7 +1851,7 @@ krb5_fcc_start_seq_get(krb5_context context, krb5_ccache id,
 
 done:
      MAYBE_CLOSE(context, id, kret);
-     k5_mutex_unlock(&data->lock);
+     k5_cc_mutex_unlock(context, &data->lock);
      return kret;
 }
 
@@ -1860,7 +1887,7 @@ krb5_fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
      krb5_octet octet;
      krb5_fcc_data *d = (krb5_fcc_data *) id->data;
 
-     kret = k5_mutex_lock(&d->lock);
+     kret = k5_cc_mutex_lock(context, &d->lock);
      if (kret)
         return kret;
 
@@ -1872,7 +1899,7 @@ krb5_fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
      if (kret) {
         kret = krb5_fcc_interpret(context, errno);
         MAYBE_CLOSE(context, id, kret);
-        k5_mutex_unlock(&d->lock);
+        k5_cc_mutex_unlock(context, &d->lock);
         return kret;
      }
 
@@ -1903,7 +1930,7 @@ krb5_fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
 
 lose:
      MAYBE_CLOSE (context, id, kret);
-     k5_mutex_unlock(&d->lock);
+     k5_cc_mutex_unlock(context, &d->lock);
      if (kret != KRB5_OK)
         krb5_free_cred_contents(context, creds);
      return kret;
@@ -1966,7 +1993,7 @@ krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
      struct fcc_set *setptr;
      
      /* Set master lock */
-     kret = k5_mutex_lock(&krb5int_cc_file_mutex);
+     kret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
      if (kret)
         return kret;
 
@@ -1974,7 +2001,7 @@ krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
      (void) strcat(scratch, "XXXXXX");
      ret = mkstemp(scratch);
      if (ret == -1) {
-         k5_mutex_unlock(&krb5int_cc_file_mutex);
+         k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
         return krb5_fcc_interpret(context, errno);
      }
      set_cloexec_fd(ret);
@@ -1982,34 +2009,34 @@ krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
      /* Allocate memory */
      data = (krb5_pointer) malloc(sizeof(krb5_fcc_data));
      if (data == NULL) {
+         k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
          close(ret);
          unlink(scratch);
-         k5_mutex_unlock(&krb5int_cc_file_mutex);
          return KRB5_CC_NOMEM;
      }
 
      data->filename = strdup(scratch);
      if (data->filename == NULL) {
-          k5_mutex_unlock(&krb5int_cc_file_mutex);
+         k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
          free(data);
          close(ret);
          unlink(scratch);
          return KRB5_CC_NOMEM;
      }
 
-     kret = k5_mutex_init(&data->lock);
+     kret = k5_cc_mutex_init(&data->lock);
      if (kret) {
-       k5_mutex_unlock(&krb5int_cc_file_mutex);
+       k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
        free(data->filename);
        free(data);
        close(ret);
        unlink(scratch);
        return kret;
      }
-     kret = k5_mutex_lock(&data->lock);
+     kret = k5_cc_mutex_lock(context, &data->lock);
      if (kret) {
-       k5_mutex_unlock(&krb5int_cc_file_mutex);
-       k5_mutex_destroy(&data->lock);
+       k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+       k5_cc_mutex_destroy(&data->lock);
        free(data->filename);
        free(data);
        close(ret);
@@ -2064,9 +2091,9 @@ krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
 
      setptr = malloc(sizeof(struct fcc_set));
      if (setptr == NULL) {
-       k5_mutex_unlock(&krb5int_cc_file_mutex);
-       k5_mutex_unlock(&data->lock);
-       k5_mutex_destroy(&data->lock);
+       k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+       k5_cc_mutex_unlock(context, &data->lock);
+       k5_cc_mutex_destroy(&data->lock);
        free(data->filename);
        free(data);
        (void) close(ret);
@@ -2077,10 +2104,10 @@ krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
      setptr->data = data;
      setptr->next = fccs;
      fccs = setptr;
-     k5_mutex_unlock(&krb5int_cc_file_mutex);
+     k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
 
-     k5_mutex_assert_locked(&data->lock);
-     k5_mutex_unlock(&data->lock);
+     k5_cc_mutex_assert_locked(context, &data->lock);
+     k5_cc_mutex_unlock(context, &data->lock);
      lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
      if (lid == NULL) {
         dereference(context, data);
@@ -2102,8 +2129,8 @@ krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
      return KRB5_OK;
 
 err_out:
-     k5_mutex_unlock(&krb5int_cc_file_mutex);
-     k5_mutex_destroy(&data->lock);
+     k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+     k5_cc_mutex_destroy(&data->lock);
      free(data->filename);
      free(data);
      return kret;
@@ -2140,7 +2167,7 @@ krb5_fcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *pri
 {
      krb5_error_code kret = KRB5_OK;
 
-     kret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+     kret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
      if (kret)
         return kret;
 
@@ -2153,7 +2180,7 @@ krb5_fcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *pri
 
 done:
      MAYBE_CLOSE(context, id, kret);
-     k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
      return kret;
 }
 
@@ -2183,7 +2210,7 @@ krb5_fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
 #define TCHECK(ret) if (ret != KRB5_OK) goto lose;
      krb5_error_code ret;
 
-     ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+     ret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
      if (ret)
         return ret;
 
@@ -2194,7 +2221,7 @@ krb5_fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
      ret = fcc_lseek((krb5_fcc_data *) id->data, (off_t) 0, SEEK_END);
      if (ret < 0) {
           MAYBE_CLOSE_IGNORE(context, id);
-         k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+         k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
          return krb5_fcc_interpret(context, errno);
      }
 
@@ -2221,7 +2248,7 @@ krb5_fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
 
 lose:
      MAYBE_CLOSE(context, id, ret);
-     k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+     k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
      krb5_change_cache ();
      return ret;
 #undef TCHECK
@@ -2256,7 +2283,7 @@ krb5_fcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
 {
     krb5_error_code ret = KRB5_OK;
 
-    ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+    ret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
     if (ret)
        return ret;
 
@@ -2274,7 +2301,7 @@ krb5_fcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
     }
 
     ((krb5_fcc_data *) id->data)->flags = flags;
-    k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
     return ret;
 }
 
@@ -2294,14 +2321,172 @@ krb5_fcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags *flags)
 {
     krb5_error_code ret = KRB5_OK;
 
-    ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+    ret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
     if (ret)
        return ret;
     *flags = ((krb5_fcc_data *) id->data)->flags;
-    k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+    k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
     return ret;
 }
 
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor)
+{
+    krb5_error_code ret = 0;
+    krb5_cc_ptcursor n = NULL;
+    struct krb5_fcc_ptcursor_data *cdata = NULL;
+    
+    *cursor = NULL;
+    
+    n = malloc(sizeof(*n));
+    if (n == NULL)
+        return ENOMEM;
+    n->ops = &krb5_fcc_ops;
+    cdata = malloc(sizeof(struct krb5_fcc_ptcursor_data));
+    if (cdata == NULL) {
+        ret = ENOMEM;
+        goto errout;
+    }
+    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_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;
+
+    ret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
+    if (ret)
+        goto errout;
+    
+    if (cdata->cur == NULL) {
+        k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+        free(n);
+        n = NULL;
+        goto errout;
+    }
+        
+    n->ops = &krb5_fcc_ops;
+    n->data = cdata->cur->data;
+    cdata->cur->refcount++;
+    
+    cdata->cur = cdata->cur->next;
+    
+    ret = k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+    if (ret)
+        goto errout;
+errout:
+        if (ret && n != NULL) {
+            free(n);
+            n = NULL;
+        }
+    *ccache = n;
+    return ret;
+}
+
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_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;
+}
+
+/*
+ * Modifies:
+ * change_time
+ * 
+ * Effects:
+ * Returns the timestamp of id's file modification date.
+ * If an error occurs, change_time is set to 0.
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_last_change_time(krb5_context context, krb5_ccache id,
+            krb5_timestamp *change_time)
+{
+    krb5_error_code kret = KRB5_OK;
+    krb5_fcc_data *data = (krb5_fcc_data *) id->data;
+
+    kret = krb5_fcc_data_last_change_time(context, data, change_time);
+
+    return kret;
+}
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_lock(krb5_context context,
+            krb5_ccache id)
+{
+    krb5_error_code ret = 0;
+    krb5_fcc_data *data = (krb5_fcc_data *) id->data;
+    ret = k5_cc_mutex_lock(context, &data->lock);
+    return ret;
+}
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_unlock(krb5_context context,
+            krb5_ccache id)
+{
+    krb5_error_code ret = 0;
+    krb5_fcc_data *data = (krb5_fcc_data *) id->data;
+    ret = k5_cc_mutex_unlock(context, &data->lock);
+    return ret;
+}
+
+static krb5_error_code
+krb5_fcc_data_last_change_time(krb5_context context, krb5_fcc_data *data,
+            krb5_timestamp *change_time)
+{
+    krb5_error_code kret = KRB5_OK;
+    register int ret;
+
+    struct stat buf;
+
+    *change_time = 0;
+
+    kret = k5_cc_mutex_lock(context, &data->lock);
+    if (kret) {
+        return kret;
+    }
+
+    ret = stat(data->filename, &buf);
+    if (ret == -1) {
+        kret = krb5_fcc_interpret(context, errno);
+    } else {
+        *change_time = (krb5_timestamp) buf.st_mtime;
+    }
+
+    k5_cc_mutex_unlock(context, &data->lock);
+
+    return kret;
+}
 
 static krb5_error_code
 krb5_fcc_interpret(krb5_context context, int errnum)
@@ -2374,6 +2559,14 @@ const krb5_cc_ops krb5_fcc_ops = {
      krb5_fcc_remove_cred,
      krb5_fcc_set_flags,
      krb5_fcc_get_flags,
+     krb5_fcc_ptcursor_new,
+     krb5_fcc_ptcursor_next,
+     krb5_fcc_ptcursor_free,
+     NULL, /* move */
+     krb5_fcc_last_change_time,
+     NULL, /* wasdefault */
+     krb5_fcc_lock,
+     krb5_fcc_unlock,
 };
 
 #if defined(_WIN32)
@@ -2435,10 +2628,12 @@ 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,
+     krb5_fcc_ptcursor_new,
+     krb5_fcc_ptcursor_next,
+     krb5_fcc_ptcursor_free,
+     NULL, /* move */
+     krb5_fcc_last_change_time,
+     NULL, /* wasdefault */
+     krb5_fcc_lock,
+     krb5_fcc_unlock,
 };
index 2d8864af3ea4d5e83b1a4551929ba1f60bc4d9b9..f2624ecca473395b72ea9b75f0a9ab21b4292351 100644 (file)
@@ -177,12 +177,13 @@ typedef struct _krb5_krcc_cursor
 typedef struct _krb5_krcc_data
 {
     char   *name;              /* Name for this credentials cache */
-    k5_mutex_t lock;           /* synchronization */
+    k5_cc_mutex lock;          /* synchronization */
     key_serial_t parent_id;    /* parent keyring of this ccache keyring */
     key_serial_t ring_id;      /* keyring representing ccache */
     key_serial_t princ_id;     /* key holding principal info */
     int     numkeys;           /* # of keys in this ring
                                 * (does NOT include principal info) */
+    krb5_timestamp changetime;
 } krb5_krcc_data;
 
 /* Passed internally to assure we don't go past the bounds of our buffer */
@@ -193,7 +194,7 @@ typedef struct _krb5_krcc_buffer_cursor
 } krb5_krcc_bc;
 
 /* Global mutex */
-k5_mutex_t krb5int_krcc_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+k5_cc_mutex krb5int_krcc_mutex = K5_CC_MUTEX_PARTIAL_INITIALIZER;
 
 /*
  * Internal functions (exported via the krb5_krcc_ops)
@@ -249,6 +250,15 @@ static krb5_error_code KRB5_CALLCONV krb5_krcc_set_flags
 static krb5_error_code KRB5_CALLCONV krb5_krcc_get_flags
     (krb5_context context, krb5_ccache id, krb5_flags * flags);
 
+static krb5_error_code KRB5_CALLCONV krb5_krcc_last_change_time
+    (krb5_context, krb5_ccache, krb5_timestamp *);
+
+static krb5_error_code KRB5_CALLCONV krb5_krcc_lock
+    (krb5_context context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_krcc_unlock
+    (krb5_context context, krb5_ccache id);
+
 /*
  * Internal utility functions
  */
@@ -339,6 +349,8 @@ static krb5_error_code krb5_krcc_unparse_ui_4
     (krb5_context, krb5_ccache id, krb5_ui_4 i, krb5_krcc_bc * bc);
 static krb5_error_code krb5_krcc_unparse_ui_2
     (krb5_context, krb5_ccache id, krb5_int32 i, krb5_krcc_bc * bc);
+static void krb5_krcc_update_change_time
+    (krb5_krcc_data *);
 
 /* Note the following is a stub function for Linux */
 extern krb5_error_code krb5_change_cache(void);
@@ -381,7 +393,7 @@ krb5_krcc_initialize(krb5_context context, krb5_ccache id,
 
     DEBUG_PRINT(("krb5_krcc_initialize: entered\n"));
 
-    kret = k5_mutex_lock(&((krb5_krcc_data *) id->data)->lock);
+    kret = k5_cc_mutex_lock(context, &((krb5_krcc_data *) id->data)->lock);
     if (kret)
        return kret;
 
@@ -394,7 +406,7 @@ krb5_krcc_initialize(krb5_context context, krb5_ccache id,
        krb5_change_cache();
 
 out:
-    k5_mutex_unlock(&((krb5_krcc_data *) id->data)->lock);
+    k5_cc_mutex_unlock(context, &((krb5_krcc_data *) id->data)->lock);
     return kret;
 }
 
@@ -416,7 +428,7 @@ krb5_krcc_close(krb5_context context, krb5_ccache id)
     d = (krb5_krcc_data *) id->data;
 
     krb5_xfree(d->name);
-    k5_mutex_destroy(&d->lock);
+    k5_cc_mutex_destroy(&d->lock);
     krb5_xfree(d);
 
     krb5_xfree(id);
@@ -445,7 +457,7 @@ krb5_krcc_clearcache(krb5_context context, krb5_ccache id)
     krb5_krcc_data *d;
     int     res;
 
-    k5_assert_locked(&((krb5_krcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_krcc_data *) id->data)->lock);
 
     d = (krb5_krcc_data *) id->data;
 
@@ -458,6 +470,7 @@ krb5_krcc_clearcache(krb5_context context, krb5_ccache id)
     }
     d->numkeys = 0;
     d->princ_id = 0;
+    krb5_krcc_update_change_time(d);
 
     return KRB5_OK;
 }
@@ -480,7 +493,7 @@ krb5_krcc_destroy(krb5_context context, krb5_ccache id)
 
     d = (krb5_krcc_data *) id->data;
 
-    kret = k5_mutex_lock(&d->lock);
+    kret = k5_cc_mutex_lock(context, &d->lock);
     if (kret)
        return kret;
 
@@ -494,8 +507,8 @@ krb5_krcc_destroy(krb5_context context, krb5_ccache id)
        goto cleanup;
     }
 cleanup:
-    k5_mutex_unlock(&d->lock);
-    k5_mutex_destroy(&d->lock);
+    k5_cc_mutex_unlock(context, &d->lock);
+    k5_cc_mutex_destroy(&d->lock);
     krb5_xfree(d);
     krb5_xfree(id);
 
@@ -649,7 +662,7 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id,
     DEBUG_PRINT(("krb5_krcc_start_seq_get: entered\n"));
 
     d = id->data;
-    kret = k5_mutex_lock(&d->lock);
+    kret = k5_cc_mutex_lock(context, &d->lock);
     if (kret)
        return kret;
 
@@ -664,7 +677,7 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id,
 
     krcursor = (krb5_krcc_cursor) malloc(size);
     if (krcursor == NULL) {
-       k5_mutex_unlock(&d->lock);
+       k5_cc_mutex_unlock(context, &d->lock);
        return KRB5_CC_NOMEM;
     }
 
@@ -675,7 +688,7 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id,
        DEBUG_PRINT(("Read %d bytes from keyring, numkeys %d: %s\n",
                     res, d->numkeys, strerror(errno)));
        free(krcursor);
-       k5_mutex_unlock(&d->lock);
+       k5_cc_mutex_unlock(context, &d->lock);
        return KRB5_CC_IO;
     }
 
@@ -683,7 +696,7 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id,
     krcursor->currkey = 0;
     krcursor->princ_id = d->princ_id;
 
-    k5_mutex_unlock(&d->lock);
+    k5_cc_mutex_unlock(context, &d->lock);
     *cursor = (krb5_cc_cursor) krcursor;
     return KRB5_OK;
 }
@@ -796,7 +809,7 @@ krb5_krcc_new_data(const char *name, key_serial_t ring,
     if (d == NULL)
        return KRB5_CC_NOMEM;
 
-    kret = k5_mutex_init(&d->lock);
+    kret = k5_cc_mutex_init(&d->lock);
     if (kret) {
        krb5_xfree(d);
        return kret;
@@ -804,7 +817,7 @@ krb5_krcc_new_data(const char *name, key_serial_t ring,
 
     d->name = strdup(name);
     if (d->name == NULL) {
-       k5_mutex_destroy(&d->lock);
+       k5_cc_mutex_destroy(&d->lock);
        krb5_xfree(d);
        return KRB5_CC_NOMEM;
     }
@@ -812,6 +825,8 @@ krb5_krcc_new_data(const char *name, key_serial_t ring,
     d->ring_id = ring;
     d->parent_id = parent_ring;
     d->numkeys = 0;
+    d->changetime = 0;
+    krb5_krcc_update_change_time(d);
 
     *datapp = d;
     return 0;
@@ -848,7 +863,7 @@ krb5_krcc_generate_new(krb5_context context, krb5_ccache * id)
 
     lid->ops = &krb5_krcc_ops;
 
-    kret = k5_mutex_lock(&krb5int_krcc_mutex);
+    kret = k5_cc_mutex_lock(context, &krb5int_krcc_mutex);
     if (kret) {
        free(lid);
        return kret;
@@ -876,7 +891,7 @@ krb5_krcc_generate_new(krb5_context context, krb5_ccache * id)
     while (1) {
        kret = krb5int_random_string(context, uniquename, sizeof(uniquename));
         if (kret) {
-            k5_mutex_unlock(&krb5int_krcc_mutex);
+            k5_cc_mutex_unlock(context, &krb5int_krcc_mutex);
             free(lid);
             return kret;
        }
@@ -892,7 +907,7 @@ krb5_krcc_generate_new(krb5_context context, krb5_ccache * id)
                kret = errno;
                DEBUG_PRINT(("krb5_krcc_generate_new: '%s' trying to "
                             "create '%s'\n", strerror(errno), uniquename));
-               k5_mutex_unlock(&krb5int_krcc_mutex);
+               k5_cc_mutex_unlock(context, &krb5int_krcc_mutex);
                return kret;
            }
            break;
@@ -900,7 +915,7 @@ krb5_krcc_generate_new(krb5_context context, krb5_ccache * id)
     }
            
     kret = krb5_krcc_new_data(uniquename, key, ring_id, &d);
-    k5_mutex_unlock(&krb5int_krcc_mutex);
+    k5_cc_mutex_unlock(context, &krb5int_krcc_mutex);
     if (kret) {
        krb5_xfree(lid);
        return kret;
@@ -1014,7 +1029,7 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds)
 
     DEBUG_PRINT(("krb5_krcc_store: entered\n"));
 
-    kret = k5_mutex_lock(&d->lock);
+    kret = k5_cc_mutex_lock(context, &d->lock);
     if (kret)
        return kret;
 
@@ -1042,6 +1057,7 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds)
     } else {
        d->numkeys++;
        kret = KRB5_OK;
+       krb5_krcc_update_change_time(d);
     }
 
   errout:
@@ -1050,10 +1066,47 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds)
     if (payload)
        free(payload);
 
-    k5_mutex_unlock(&d->lock);
+    k5_cc_mutex_unlock(context, &d->lock);
     return kret;
 }
 
+static krb5_error_code KRB5_CALLCONV 
+krb5_krcc_last_change_time(krb5_context context, krb5_ccache id, 
+                          krb5_timestamp *change_time)
+{
+    krb5_error_code ret = 0;
+    krb5_krcc_data *data = (krb5_krcc_data *) id->data;
+    
+    *change_time = 0;
+    
+    ret = k5_cc_mutex_lock(context, &data->lock);
+    if (!ret) {
+        *change_time = data->changetime;
+        k5_cc_mutex_unlock(context, &data->lock);
+    }
+
+    return ret;
+}
+
+static krb5_error_code KRB5_CALLCONV 
+krb5_krcc_lock(krb5_context context, krb5_ccache id)
+{
+    krb5_error_code ret = 0;
+    krb5_krcc_data *data = (krb5_krcc_data *) id->data;
+    ret = k5_cc_mutex_lock(context, &data->lock);
+    return ret;
+}
+
+static krb5_error_code KRB5_CALLCONV 
+krb5_krcc_unlock(krb5_context context, krb5_ccache id)
+{
+    krb5_error_code ret = 0;
+    krb5_krcc_data *data = (krb5_krcc_data *) id->data;
+    ret = k5_cc_mutex_unlock(context, &data->lock);
+    return ret;
+}
+
+
 static  krb5_error_code
 krb5_krcc_save_principal(krb5_context context, krb5_ccache id,
                         krb5_principal princ)
@@ -1065,7 +1118,7 @@ krb5_krcc_save_principal(krb5_context context, krb5_ccache id,
     unsigned int payloadsize;
     krb5_krcc_bc bc;
 
-    k5_assert_locked(&((krb5_krcc_data *) id->data)->lock);
+    k5_cc_mutex_assert_locked(context, &((krb5_krcc_data *) id->data)->lock);
 
     d = (krb5_krcc_data *) id->data;
 
@@ -1102,6 +1155,7 @@ krb5_krcc_save_principal(krb5_context context, krb5_ccache id,
     } else {
        d->princ_id = newkey;
        kret = KRB5_OK;
+       krb5_krcc_update_change_time(d);
     }
 
   errout:
@@ -1119,7 +1173,7 @@ krb5_krcc_retrieve_principal(krb5_context context, krb5_ccache id,
     int     psize;
     krb5_krcc_bc bc;
 
-    kret = k5_mutex_lock(&d->lock);
+    kret = k5_cc_mutex_lock(context, &d->lock);
     if (kret)
        return kret;
 
@@ -1143,7 +1197,7 @@ krb5_krcc_retrieve_principal(krb5_context context, krb5_ccache id,
   errout:
     if (payload)
        free(payload);
-    k5_mutex_unlock(&d->lock);
+    k5_cc_mutex_unlock(context, &d->lock);
     return kret;
 }
 
@@ -1972,6 +2026,22 @@ krb5_krcc_unparse_cred(krb5_context context, krb5_ccache id,
     return kret;
 }
 
+/*
+ * Utility routine: called by krb5_krcc_* functions to keep 
+ * result of krb5_krcc_last_change_time up to date.
+ * Value monotonically increases -- based on but not guaranteed to be actual 
+ * system time.
+ */
+
+static void
+krb5_krcc_update_change_time(krb5_krcc_data *d)
+{
+       krb5_timestamp now_time = time(NULL);
+       d->changetime = (d->changetime >= now_time) ? 
+       d->changetime + 1 : now_time;
+}
+
+
 /*
  * ccache implementation storing credentials in the Linux keyring facility
  * The default is to put them at the session keyring level.
@@ -1995,7 +2065,15 @@ const krb5_cc_ops krb5_krcc_ops = {
     krb5_krcc_end_seq_get,
     krb5_krcc_remove_cred,
     krb5_krcc_set_flags,
-    krb5_krcc_get_flags                /* added after 1.4 release */
+    krb5_krcc_get_flags,       /* added after 1.4 release */
+    NULL,
+    NULL,
+    NULL,
+    NULL, /* move */
+    krb5_krcc_last_change_time, /* lastchange */
+    NULL, /* wasdefault */
+    krb5_krcc_lock,
+    krb5_krcc_unlock,
 };
 
 #else /* !USE_KEYRING_CCACHE */
@@ -2020,6 +2098,14 @@ const krb5_cc_ops krb5_krcc_ops = {
     NULL,
     NULL,
     NULL,
-    NULL                       /* added after 1.4 release */
+    NULL,                      /* added after 1.4 release */
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
 };
 #endif /* USE_KEYRING_CCACHE */
index dc0fd3422000d0ef146ec90af450e3a55801e6c2..4a3b67c80a5e4a71ff58ced662e3aa9b6d6f898a 100644 (file)
@@ -75,18 +75,24 @@ 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_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_next
+       (krb5_context, krb5_cc_ptcursor, krb5_ccache *);
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_ptcursor_free
+       (krb5_context, krb5_cc_ptcursor *);
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_last_change_time
+       (krb5_context, krb5_ccache, krb5_timestamp *);
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_lock
+       (krb5_context context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_unlock
+       (krb5_context context, krb5_ccache id);
 
-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);
@@ -102,9 +108,10 @@ typedef struct _krb5_mcc_link {
 /* Per-cache data header.  */
 typedef struct _krb5_mcc_data {
     char *name;
-    k5_mutex_t lock;
+    k5_cc_mutex lock;
     krb5_principal prin;
     krb5_mcc_cursor link;
+    krb5_timestamp changetime;
 } krb5_mcc_data;
 
 /* List of memory caches.  */
@@ -118,9 +125,11 @@ struct krb5_mcc_ptcursor_data {
     struct krb5_mcc_list_node *cur;
 };
 
-k5_mutex_t krb5int_mcc_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+k5_cc_mutex krb5int_mcc_mutex = K5_CC_MUTEX_PARTIAL_INITIALIZER;
 static krb5_mcc_list_node *mcc_head = 0;
 
+static void update_mcc_change_time(krb5_mcc_data *);
+
 /*
  * Modifies:
  * id
@@ -142,15 +151,18 @@ krb5_mcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
     krb5_mcc_data *d;
 
     d = (krb5_mcc_data *)id->data;
-    ret = k5_mutex_lock(&d->lock);
+    ret = k5_cc_mutex_lock(context, &d->lock);
     if (ret)
         return ret;
 
     krb5_mcc_free(context, id);
+       
+    d = (krb5_mcc_data *)id->data;
     ret = krb5_copy_principal(context, princ,
-                             &((krb5_mcc_data *)id->data)->prin);
+                             &d->prin);
+    update_mcc_change_time(d);
 
-    k5_mutex_unlock(&d->lock);
+    k5_cc_mutex_unlock(context, &d->lock);
     if (ret == KRB5_OK)
         krb5_change_cache();
     return ret;
@@ -202,7 +214,7 @@ krb5_mcc_destroy(krb5_context context, krb5_ccache id)
     krb5_mcc_data *d;
     krb5_error_code err;
 
-    err = k5_mutex_lock(&krb5int_mcc_mutex);
+    err = k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
     if (err)
        return err;
 
@@ -215,16 +227,16 @@ krb5_mcc_destroy(krb5_context context, krb5_ccache id)
            break;
        }
     }
-    k5_mutex_unlock(&krb5int_mcc_mutex);
+    k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
 
-    err = k5_mutex_lock(&d->lock);
+    err = k5_cc_mutex_lock(context, &d->lock);
     if (err)
         return err;
 
     krb5_mcc_free(context, id);
     krb5_xfree(d->name);
-    k5_mutex_unlock(&d->lock);
-    k5_mutex_destroy(&d->lock);
+    k5_cc_mutex_unlock(context, &d->lock);
+    k5_cc_mutex_destroy(&d->lock);
     krb5_xfree(d); 
     krb5_xfree(id);
 
@@ -261,7 +273,7 @@ krb5_mcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
     krb5_error_code err;
     krb5_mcc_data *d;
 
-    err = k5_mutex_lock(&krb5int_mcc_mutex);
+    err = k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
     if (err)
        return err;
     for (ptr = mcc_head; ptr; ptr=ptr->next)
@@ -272,11 +284,11 @@ krb5_mcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
     else {
        err = new_mcc_data(residual, &d);
        if (err) {
-           k5_mutex_unlock(&krb5int_mcc_mutex);
+           k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
            return err;
        }
     }
-    k5_mutex_unlock(&krb5int_mcc_mutex);
+    k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
 
     lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
     if (lid == NULL)
@@ -310,11 +322,11 @@ krb5_mcc_start_seq_get(krb5_context context, krb5_ccache id,
      krb5_mcc_data *d;
 
      d = id->data;
-     err = k5_mutex_lock(&d->lock);
+     err = k5_cc_mutex_lock(context, &d->lock);
      if (err)
         return err;
      mcursor = d->link;
-     k5_mutex_unlock(&d->lock);
+     k5_cc_mutex_unlock(context, &d->lock);
      *cursor = (krb5_cc_cursor) mcursor;
      return KRB5_OK;
 }
@@ -396,8 +408,8 @@ new_mcc_data (const char *name, krb5_mcc_data **dataptr)
     d = malloc(sizeof(krb5_mcc_data));
     if (d == NULL)
        return KRB5_CC_NOMEM;
-
-    err = k5_mutex_init(&d->lock);
+        
+    err = k5_cc_mutex_init(&d->lock);
     if (err) {
        krb5_xfree(d);
        return err;
@@ -405,12 +417,14 @@ new_mcc_data (const char *name, krb5_mcc_data **dataptr)
 
     d->name = malloc(strlen(name) + 1);
     if (d->name == NULL) {
-       k5_mutex_destroy(&d->lock);
+       k5_cc_mutex_destroy(&d->lock);
        krb5_xfree(d);
        return KRB5_CC_NOMEM;
     }
     d->link = NULL;
     d->prin = NULL;
+    d->changetime = 0;
+    update_mcc_change_time(d);
 
     /* Set up the filename */
     strcpy(d->name, name);
@@ -418,7 +432,7 @@ new_mcc_data (const char *name, krb5_mcc_data **dataptr)
     n = malloc(sizeof(krb5_mcc_list_node));
     if (n == NULL) {
        free(d->name);
-       k5_mutex_destroy(&d->lock);
+       k5_cc_mutex_destroy(&d->lock);
        free(d);
        return KRB5_CC_NOMEM;
     }
@@ -461,7 +475,7 @@ krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
 
     lid->ops = &krb5_mcc_ops;
     
-    err = k5_mutex_lock(&krb5int_mcc_mutex);
+    err = k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
     if (err) {
        free(lid);
        return err;
@@ -473,7 +487,7 @@ krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
 
         err = krb5int_random_string (context, uniquename, sizeof (uniquename));
         if (err) {
-           k5_mutex_unlock(&krb5int_mcc_mutex);
+           k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
            free(lid);
            return err;
         }
@@ -488,7 +502,7 @@ krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
     
     err = new_mcc_data(uniquename, &d);
 
-    k5_mutex_unlock(&krb5int_mcc_mutex);
+    k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
     if (err) {
        krb5_xfree(lid);
        return err;
@@ -636,12 +650,13 @@ krb5_mcc_store(krb5_context ctx, krb5_ccache id, krb5_creds *creds)
        free(new_node);
        return err;
     }
-    err = k5_mutex_lock(&mptr->lock);
+    err = k5_cc_mutex_lock(ctx, &mptr->lock);
     if (err)
        return err;
     new_node->next = mptr->link;
     mptr->link = new_node;
-    k5_mutex_unlock(&mptr->lock);
+    update_mcc_change_time(mptr);
+    k5_cc_mutex_unlock(ctx, &mptr->lock);
     return 0;
 }
 
@@ -666,11 +681,11 @@ krb5_mcc_ptcursor_new(
        goto errout;
     }
     n->data = cdata;
-    ret = k5_mutex_lock(&krb5int_mcc_mutex);
+    ret = k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
     if (ret)
        goto errout;
     cdata->cur = mcc_head;
-    ret = k5_mutex_unlock(&krb5int_mcc_mutex);
+    ret = k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
     if (ret)
        goto errout;
 
@@ -702,11 +717,11 @@ krb5_mcc_ptcursor_next(
 
     (*ccache)->ops = &krb5_mcc_ops;
     (*ccache)->data = cdata->cur->cache;
-    ret = k5_mutex_lock(&krb5int_mcc_mutex);
+    ret = k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
     if (ret)
        goto errout;
     cdata->cur = cdata->cur->next;
-    ret = k5_mutex_unlock(&krb5int_mcc_mutex);
+    ret = k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
     if (ret)
        goto errout;
 errout:
@@ -731,6 +746,57 @@ krb5_mcc_ptcursor_free(
     return 0;
 }
 
+static krb5_error_code KRB5_CALLCONV 
+krb5_mcc_last_change_time(
+    krb5_context context,
+    krb5_ccache id, 
+    krb5_timestamp *change_time)
+{
+    krb5_error_code ret = 0;
+    krb5_mcc_data *data = (krb5_mcc_data *) id->data;
+    
+    *change_time = 0;
+    
+    ret = k5_cc_mutex_lock(context, &data->lock);
+    if (!ret) {
+        *change_time = data->changetime;
+        k5_cc_mutex_unlock(context, &data->lock);
+    }
+
+    return ret;
+}
+
+/*
+ Utility routine: called by krb5_mcc_* functions to keep 
+ result of krb5_mcc_last_change_time up to date
+ */
+
+static void
+update_mcc_change_time(krb5_mcc_data *d)
+{
+    krb5_timestamp now_time = time(NULL);
+    d->changetime = (d->changetime >= now_time) ? 
+       d->changetime + 1 : now_time;
+}
+
+static krb5_error_code KRB5_CALLCONV 
+krb5_mcc_lock(krb5_context context, krb5_ccache id)
+{
+    krb5_error_code ret = 0;
+    krb5_mcc_data *data = (krb5_mcc_data *) id->data;
+    ret = k5_cc_mutex_lock(context, &data->lock);
+    return ret;
+}
+
+static krb5_error_code KRB5_CALLCONV 
+krb5_mcc_unlock(krb5_context context, krb5_ccache id)
+{
+    krb5_error_code ret = 0;
+    krb5_mcc_data *data = (krb5_mcc_data *) id->data;
+    ret = k5_cc_mutex_unlock(context, &data->lock);
+    return ret;
+}
+
 const krb5_cc_ops krb5_mcc_ops = {
      0,
      "MEMORY",
@@ -752,7 +818,9 @@ const krb5_cc_ops krb5_mcc_ops = {
      krb5_mcc_ptcursor_new,
      krb5_mcc_ptcursor_next,
      krb5_mcc_ptcursor_free,
-     NULL,
-     NULL,
-     NULL,
+     NULL, /* move */
+     krb5_mcc_last_change_time,
+     NULL, /* wasdefault */
+     krb5_mcc_lock,
+     krb5_mcc_unlock,
 };
index 83d6176cc240e5ea78be257ace1f16235640f7dc..a5e171e2422153b537e67a668b71eea91df2384d 100644 (file)
@@ -90,9 +90,11 @@ krb5_cc_ops krb5_cc_stdcc_ops = {
       krb5_stdccv3_ptcursor_new,
       krb5_stdccv3_ptcursor_next,
       krb5_stdccv3_ptcursor_free,
-      NULL,
-      NULL,
-      NULL,
+      NULL, /* move */
+      krb5_stdccv3_last_change_time, /* lastchange */
+      NULL, /* wasdefault */
+      krb5_stdccv3_lock,
+      krb5_stdccv3_unlock,
 #else
       krb5_stdcc_get_name,
       krb5_stdcc_resolve,
@@ -908,7 +910,6 @@ krb5_stdccv3_ptcursor_next(
        cc_string_t ccstring = NULL;
        char *name = NULL;
        
-       // TODO set proper errors, check context param
        if (!cursor || !cursor->data) {
                err = ccErrInvalidContext;
        }
@@ -984,6 +985,87 @@ krb5_stdccv3_ptcursor_free(
     return 0;
 }
 
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_last_change_time
+               (krb5_context context, krb5_ccache id,
+           krb5_timestamp *change_time)
+{
+    krb5_error_code err = 0;
+    stdccCacheDataPtr ccapi_data = id->data;
+    cc_time_t ccapi_change_time = 0;
+
+    *change_time = 0;
+    
+    if (!err) {
+        err = stdccv3_setup(context, ccapi_data);
+    }
+    if (!err) {
+        err = cc_ccache_get_change_time (ccapi_data->NamedCache, &ccapi_change_time);
+    }
+    if (!err) {
+        *change_time = ccapi_change_time;
+    }
+    
+    return cc_err_xlate (err);
+}
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_lock
+(krb5_context context, krb5_ccache id)
+{
+    krb5_error_code err = 0;
+    stdccCacheDataPtr ccapi_data = id->data;
+    
+    if (!err) {
+        err = stdccv3_setup(context, ccapi_data);
+    }
+    if (!err) {
+        err = cc_ccache_lock(ccapi_data->NamedCache, cc_lock_write, cc_lock_block);
+    }
+    return cc_err_xlate(err);    
+}
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_unlock
+(krb5_context context, krb5_ccache id)
+{
+    krb5_error_code err = 0;
+    stdccCacheDataPtr ccapi_data = id->data;
+    
+    if (!err) {
+        err = stdccv3_setup(context, ccapi_data);
+    }
+    if (!err) {
+        err = cc_ccache_unlock(ccapi_data->NamedCache);
+    }
+    return cc_err_xlate(err);    
+}
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_lock
+(krb5_context context)
+{
+    krb5_error_code err = 0;
+
+    if (!err && !gCntrlBlock) {
+        err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
+    }
+    if (!err) {
+        err = cc_context_lock(gCntrlBlock, cc_lock_write, cc_lock_block);
+    }
+    return cc_err_xlate(err);    
+}
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_unlock
+(krb5_context context)
+{
+    krb5_error_code err = 0;
+
+    if (!err && !gCntrlBlock) {
+        err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
+    }
+    if (!err) {
+        err = cc_context_unlock(gCntrlBlock);
+    }
+    return cc_err_xlate(err);    
+}
+
 #else /* !USE_CCAPI_V3 */
 
 static krb5_error_code stdcc_setup(krb5_context context,
index dcd8b6b6cf5a54aba226966e4059b9359a7bb686..e9ec085eb3b91c059b7bbd5456e65335910ce724 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __KRB5_STDCC_H__
+#define __KRB5_STDCC_H__
+
 #if defined(_WIN32) || defined(USE_CCAPI)
 
 #include "k5-int.h"    /* loads krb5.h */
@@ -97,6 +100,21 @@ krb5_error_code KRB5_CALLCONV krb5_stdccv3_ptcursor_next
 krb5_error_code KRB5_CALLCONV krb5_stdccv3_ptcursor_free
                (krb5_context context, krb5_cc_ptcursor *cursor);
 
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_last_change_time
+               (krb5_context context, krb5_ccache id,
+           krb5_timestamp *change_time);
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_lock 
+        (krb5_context, krb5_ccache id);
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_unlock
+        (krb5_context, krb5_ccache id);
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_lock
+        (krb5_context context); 
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_unlock
+        (krb5_context context);
 
 #else
 
@@ -154,3 +172,5 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_remove
 #endif
 
 #endif /* defined(_WIN32) || defined(USE_CCAPI) */
+
+#endif
index e8bd9cec6771f6ab9ca344934488e5fcc225bb66..f54486f7df2a5562fffe8049b20c96d90e30bdd3 100644 (file)
@@ -83,6 +83,9 @@ static struct krb5_cc_typelist cc_krcc_entry = { &krb5_krcc_ops, NEXT };
 static struct krb5_cc_typelist *cc_typehead = INITIAL_TYPEHEAD;
 static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
 
+/* mutex for krb5_cccol_[un]lock */
+static k5_cc_mutex cccol_lock = K5_CC_MUTEX_PARTIAL_INITIALIZER;
+
 static krb5_error_code
 krb5int_cc_getops(krb5_context, const char *, const krb5_cc_ops **);
 
@@ -91,19 +94,22 @@ krb5int_cc_initialize(void)
 {
     int err;
 
-    err = k5_mutex_finish_init(&krb5int_mcc_mutex);
+    err = k5_cc_mutex_finish_init(&cccol_lock);
+    if (err)
+       return err;
+    err = k5_cc_mutex_finish_init(&krb5int_mcc_mutex);
     if (err)
        return err;
     err = k5_mutex_finish_init(&cc_typelist_lock);
     if (err)
        return err;
 #ifndef NO_FILE_CCACHE
-    err = k5_mutex_finish_init(&krb5int_cc_file_mutex);
+    err = k5_cc_mutex_finish_init(&krb5int_cc_file_mutex);
     if (err)
        return err;
 #endif
 #ifdef USE_KEYRING_CCACHE
-    err = k5_mutex_finish_init(&krb5int_krcc_mutex);
+    err = k5_cc_mutex_finish_init(&krb5int_krcc_mutex);
     if (err)
        return err;
 #endif
@@ -114,13 +120,15 @@ void
 krb5int_cc_finalize(void)
 {
     struct krb5_cc_typelist *t, *t_next;
+    k5_cccol_force_unlock();
+    k5_cc_mutex_destroy(&cccol_lock);
     k5_mutex_destroy(&cc_typelist_lock);
 #ifndef NO_FILE_CCACHE
-    k5_mutex_destroy(&krb5int_cc_file_mutex);
+    k5_cc_mutex_destroy(&krb5int_cc_file_mutex);
 #endif
-    k5_mutex_destroy(&krb5int_mcc_mutex);
+    k5_cc_mutex_destroy(&krb5int_mcc_mutex);
 #ifdef USE_KEYRING_CCACHE
-    k5_mutex_destroy(&krb5int_krcc_mutex);
+    k5_cc_mutex_destroy(&krb5int_krcc_mutex);
 #endif
     for (t = cc_typehead; t != INITIAL_TYPEHEAD; t = t_next) {
        t_next = t->next;
@@ -353,3 +361,259 @@ krb5int_cc_typecursor_free(krb5_context context, krb5_cc_typecursor *t)
     *t = NULL;
     return 0;
 }
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_move (krb5_context context, krb5_ccache src, krb5_ccache dst)
+{
+    krb5_error_code ret = 0;
+    krb5_principal princ = NULL;
+    
+    ret = krb5_cccol_lock(context);
+    if (ret) {
+               return ret;
+    }
+    
+    ret = krb5_cc_lock(context, src);
+    if (ret) {
+               krb5_cccol_unlock(context);
+               return ret;
+    }
+    
+    ret = krb5_cc_get_principal(context, src, &princ);
+    if (!ret) {
+               ret = krb5_cc_initialize(context, dst, princ);
+    }
+    if (!ret) {
+               ret = krb5_cc_lock(context, dst);
+    }
+    if (!ret) {
+               ret = krb5_cc_copy_creds(context, src, dst);
+               krb5_cc_unlock(context, dst);
+    }
+    
+    krb5_cc_unlock(context, src);
+    if (!ret) {
+               ret = krb5_cc_destroy(context, src);
+    }
+    krb5_cccol_unlock(context);
+    if (princ) {
+               krb5_free_principal(context, princ);
+               princ = NULL;
+    }        
+    
+    return ret;
+}
+
+krb5_error_code
+k5_cc_mutex_init(k5_cc_mutex *m)
+{
+    krb5_error_code ret = 0;
+    
+    ret = k5_mutex_init(&m->lock);
+    if (ret) return ret;
+    m->owner = NULL;
+    m->refcount = 0;
+    
+    return ret;
+}
+
+krb5_error_code
+k5_cc_mutex_finish_init(k5_cc_mutex *m)
+{
+    krb5_error_code ret = 0;
+    
+    ret = k5_mutex_finish_init(&m->lock);
+    if (ret) return ret;
+    m->owner = NULL;
+    m->refcount = 0;
+    
+    return ret;
+}
+
+void
+k5_cc_mutex_assert_locked(krb5_context context, k5_cc_mutex *m)
+{
+#ifdef DEBUG_THREADS
+    assert(m->refcount > 0);
+    assert(m->owner == context);
+#endif
+    k5_assert_locked(&m->lock);
+}
+
+void
+k5_cc_mutex_assert_unlocked(krb5_context context, k5_cc_mutex *m)
+{
+#ifdef DEBUG_THREADS
+    assert(m->refcount == 0);
+    assert(m->owner == NULL);
+#endif
+    k5_assert_unlocked(&m->lock);    
+}
+
+krb5_error_code
+k5_cc_mutex_lock(krb5_context context, k5_cc_mutex *m)
+{
+    krb5_error_code ret = 0;
+    
+    // not locked or already locked by another context
+    if (m->owner != context) {
+       // acquire lock, blocking until available
+       ret = k5_mutex_lock(&m->lock);
+       m->owner = context;
+       m->refcount = 1;
+    }
+    // already locked by this context, just increase refcount
+    else {
+       m->refcount++;
+    }
+    return ret;    
+}
+
+krb5_error_code
+k5_cc_mutex_unlock(krb5_context context, k5_cc_mutex *m)
+{
+    krb5_error_code ret = 0;
+    
+    /* verify owner and sanity check refcount */
+    if ((m->owner != context) || (m->refcount < 1)) {
+       return ret;
+    }
+    /* decrement & unlock when count reaches zero */
+    m->refcount--;
+    if (m->refcount == 0) {
+       m->owner = NULL;
+       k5_mutex_unlock(&m->lock);
+    }
+    return ret;
+}
+
+/* necessary to make reentrant locks play nice with krb5int_cc_finalize */
+krb5_error_code
+k5_cc_mutex_force_unlock(k5_cc_mutex *m)
+{
+    krb5_error_code ret = 0;
+    
+    m->refcount = 0;
+    m->owner = NULL;
+    if (m->refcount > 0) {
+       k5_mutex_unlock(&m->lock);
+    }
+    return ret;    
+}
+
+/*
+ * holds on to all pertype global locks as well as typelist lock
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_lock(krb5_context context)
+{
+    krb5_error_code ret = 0;
+    
+    ret = k5_cc_mutex_lock(context, &cccol_lock);
+    if (ret) {
+       return ret;
+    }    
+    ret = k5_mutex_lock(&cc_typelist_lock);
+    if (ret) {
+       k5_cc_mutex_unlock(context, &cccol_lock);
+       return ret;
+    }
+    ret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
+    if (ret) {
+       k5_mutex_unlock(&cc_typelist_lock);
+       k5_cc_mutex_unlock(context, &cccol_lock);
+       return ret;
+    }
+    ret = k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
+    if (ret) {
+       k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+       k5_mutex_unlock(&cc_typelist_lock);
+       k5_cc_mutex_unlock(context, &cccol_lock);
+       return ret;
+    }
+#ifdef USE_CCAPI_V3
+    ret = krb5_stdccv3_context_lock(context);
+#endif
+#ifdef USE_KEYRING_CCACHE
+    ret = k5_cc_mutex_lock(context, &krb5int_krcc_mutex);
+#endif
+    if (ret) {
+       k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
+       k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+       k5_mutex_unlock(&cc_typelist_lock);
+       k5_cc_mutex_unlock(context, &cccol_lock);
+       return ret;
+    }
+    k5_mutex_unlock(&cc_typelist_lock);
+    return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_unlock(krb5_context context)
+{
+    krb5_error_code ret = 0;
+    
+    /* sanity check */
+    k5_cc_mutex_assert_locked(context, &cccol_lock);
+    
+    ret = k5_mutex_lock(&cc_typelist_lock);
+    if (ret) {
+       k5_cc_mutex_unlock(context, &cccol_lock);
+       return ret;
+    }    
+
+    // unlock each type in the opposite order
+#ifdef USE_KEYRING_CCACHE
+    k5_cc_mutex_assert_locked(context, &krb5int_krcc_mutex);
+    k5_cc_mutex_unlock(context, &krb5int_krcc_mutex);
+#endif
+#ifdef USE_CCAPI_V3
+    krb5_stdccv3_context_unlock(context);
+#endif
+    k5_cc_mutex_assert_locked(context, &krb5int_mcc_mutex);
+    k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
+    k5_cc_mutex_assert_locked(context, &krb5int_cc_file_mutex);
+    k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
+    k5_mutex_assert_locked(&cc_typelist_lock);
+
+    k5_mutex_unlock(&cc_typelist_lock);
+    k5_cc_mutex_unlock(context, &cccol_lock);
+
+    return ret;
+}
+
+/* necessary to make reentrant locks play nice with krb5int_cc_finalize */
+krb5_error_code
+k5_cccol_force_unlock()
+{
+    krb5_error_code ret = 0;
+    
+    /* sanity check */
+    if ((&cccol_lock)->refcount == 0) {
+       return 0;
+    }
+    
+    ret = k5_mutex_lock(&cc_typelist_lock);
+    if (ret) {
+       (&cccol_lock)->refcount = 0;
+       (&cccol_lock)->owner = NULL;
+       k5_mutex_unlock(&(&cccol_lock)->lock);
+       return ret;
+    }    
+    
+    // unlock each type in the opposite order
+#ifdef USE_KEYRING_CCACHE
+    k5_cc_mutex_force_unlock(&krb5int_krcc_mutex);
+#endif
+#ifdef USE_CCAPI_V3
+    krb5_stdccv3_context_unlock(NULL);
+#endif
+    k5_cc_mutex_force_unlock(&krb5int_mcc_mutex);
+    k5_cc_mutex_force_unlock(&krb5int_cc_file_mutex);
+    
+    k5_mutex_unlock(&cc_typelist_lock);
+    k5_cc_mutex_force_unlock(&cccol_lock);
+    
+    return ret;
+}
index 31b4737cf6105914edf28c2309087b28c8706bb3..5a062d4433f5ea8587c62e1f6a1593f8d71741b5 100644 (file)
@@ -198,6 +198,42 @@ krb5_cccol_cursor_free(
     return 0;
 }
 
+krb5_error_code KRB5_CALLCONV
+krb5_cccol_last_change_time(
+    krb5_context context, 
+    krb5_timestamp *change_time)
+{
+    krb5_error_code ret = 0;
+    krb5_cccol_cursor c = NULL;
+    krb5_ccache ccache = NULL;
+    krb5_timestamp last_time = 0;
+    krb5_timestamp max_change_time = 0;
+    
+    *change_time = 0;
+    
+    ret = krb5_cccol_cursor_new(context, &c);
+    
+    while (!ret) {
+        ret = krb5_cccol_cursor_next(context, c, &ccache);
+        if (ccache) {
+            ret = krb5_cc_last_change_time(context, ccache, &last_time);
+            if (!ret && last_time > max_change_time) {
+                max_change_time = last_time;
+            }
+            ret = 0;
+        }
+        else {
+            break;
+        }
+    }
+    *change_time = max_change_time;
+    return ret;
+}
+
+/*
+ * 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.
index 15bc87df6b76a24e519fb5fd3bc6b952011da9b6..853d6c90b8c4601d26c5af2c7caeae22dcc42e50 100644 (file)
@@ -166,3 +166,23 @@ krb5_cc_get_type (krb5_context context, krb5_ccache cache)
 {
     return cache->ops->prefix;
 }
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_last_change_time (krb5_context context, krb5_ccache ccache, 
+            krb5_timestamp *change_time)
+{
+    return ccache->ops->lastchange(context, ccache, change_time);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_lock (krb5_context context, krb5_ccache ccache)
+{
+    return ccache->ops->lock(context, ccache);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_unlock (krb5_context context, krb5_ccache ccache)
+{
+    return ccache->ops->unlock(context, ccache);
+}
+