From 6e83d0bd31721ac86003530dd2450221dd05d0c2 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Mon, 22 Sep 2008 17:03:51 +0000 Subject: [PATCH] Merge 1.7 work on auxiliary ccache functions necessary for KIM. Adds krb5_cc_lock/unlock, krb5_cccol_lock/unlock, krb5_cc_last_change_time, krb5_cccol_last_change_time, krb5_cc_move, and adds pertype cursor support to some cache types 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 | 36 ++- src/include/krb5/krb5.hin | 25 ++ src/lib/krb5/ccache/cc-int.h | 20 +- src/lib/krb5/ccache/cc_file.c | 397 ++++++++++++++++++++++-------- src/lib/krb5/ccache/cc_keyring.c | 138 +++++++++-- src/lib/krb5/ccache/cc_memory.c | 150 ++++++++--- src/lib/krb5/ccache/ccapi/stdcc.c | 90 ++++++- src/lib/krb5/ccache/ccapi/stdcc.h | 20 ++ src/lib/krb5/ccache/ccbase.c | 276 ++++++++++++++++++++- src/lib/krb5/ccache/cccursor.c | 36 +++ src/lib/krb5/ccache/ccfns.c | 20 ++ 11 files changed, 1026 insertions(+), 182 deletions(-) diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 545bd983a..111b12159 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -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; diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index 403bb9f66..82e52ab52 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -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, diff --git a/src/lib/krb5/ccache/cc-int.h b/src/lib/krb5/ccache/cc-int.h index e533f4667..4c0db959d 100644 --- a/src/lib/krb5/ccache/cc-int.h +++ b/src/lib/krb5/ccache/cc-int.h @@ -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__ */ diff --git a/src/lib/krb5/ccache/cc_file.c b/src/lib/krb5/ccache/cc_file.c index a24ff4502..22c01b8b7 100644 --- a/src/lib/krb5/ccache/cc_file.c +++ b/src/lib/krb5/ccache/cc_file.c @@ -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, }; diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c index 2d8864af3..f2624ecca 100644 --- a/src/lib/krb5/ccache/cc_keyring.c +++ b/src/lib/krb5/ccache/cc_keyring.c @@ -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 */ diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c index dc0fd3422..4a3b67c80 100644 --- a/src/lib/krb5/ccache/cc_memory.c +++ b/src/lib/krb5/ccache/cc_memory.c @@ -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, }; diff --git a/src/lib/krb5/ccache/ccapi/stdcc.c b/src/lib/krb5/ccache/ccapi/stdcc.c index 83d6176cc..a5e171e24 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc.c +++ b/src/lib/krb5/ccache/ccapi/stdcc.c @@ -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, diff --git a/src/lib/krb5/ccache/ccapi/stdcc.h b/src/lib/krb5/ccache/ccapi/stdcc.h index dcd8b6b6c..e9ec085eb 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc.h +++ b/src/lib/krb5/ccache/ccapi/stdcc.h @@ -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 diff --git a/src/lib/krb5/ccache/ccbase.c b/src/lib/krb5/ccache/ccbase.c index e8bd9cec6..f54486f7d 100644 --- a/src/lib/krb5/ccache/ccbase.c +++ b/src/lib/krb5/ccache/ccbase.c @@ -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; +} diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c index 31b4737cf..5a062d443 100644 --- a/src/lib/krb5/ccache/cccursor.c +++ b/src/lib/krb5/ccache/cccursor.c @@ -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. diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c index 15bc87df6..853d6c90b 100644 --- a/src/lib/krb5/ccache/ccfns.c +++ b/src/lib/krb5/ccache/ccfns.c @@ -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); +} + -- 2.26.2