diff --git a/lib/krb5/acache.c b/lib/krb5/acache.c index 3a44ee9e4..b404bb2e2 100644 --- a/lib/krb5/acache.c +++ b/lib/krb5/acache.c @@ -1003,6 +1003,28 @@ acc_set_default(krb5_context context, krb5_ccache id) return 0; } +static krb5_error_code +acc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + krb5_acc *a = ACACHE(id); + cc_int32 error; + cc_time_t t; + + if (a->ccache == NULL) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("No API credential found", "")); + return KRB5_CC_NOTFOUND; + } + + error = (*a->ccache->func->get_change_time)(a->ccache, &t); + if (error) + return translate_cc_error(context, error); + + *mtime = t; + + return 0; +} + /** * Variable containing the API based credential cache implemention. * @@ -1032,5 +1054,6 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = { acc_end_cache_get, acc_move, acc_get_default_name, - acc_set_default + acc_set_default, + acc_lastchange }; diff --git a/lib/krb5/cache.c b/lib/krb5/cache.c index 3f9ddbb5b..4c0035c47 100644 --- a/lib/krb5/cache.c +++ b/lib/krb5/cache.c @@ -1418,3 +1418,24 @@ krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor) return 0; } +/** + * Return the last time the credential cache was modified. + * + * @param context A Kerberos 5 context + * @param id The credential cache to probe + * @param mtime the last modification time, set to 0 on error. + + * @return Return 0 or and error. See krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_last_change_time(krb5_context context, + krb5_ccache id, + krb5_timestamp *mtime) +{ + *mtime = 0; + return (*id->ops->lastchange)(context, id, mtime); +} diff --git a/lib/krb5/fcache.c b/lib/krb5/fcache.c index e495f4c46..cb1adde5d 100644 --- a/lib/krb5/fcache.c +++ b/lib/krb5/fcache.c @@ -928,6 +928,27 @@ fcc_default_name(krb5_context context, char **str) str); } +static krb5_error_code +fcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + krb5_error_code ret; + struct stat sb; + int fd; + + ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY | O_CLOEXEC, 0); + if(ret) + return ret; + ret = fstat(fd, &sb); + close(fd); + if (ret) { + ret = errno; + krb5_set_error_message(context, ret, N_("Failed to stat cache file", "")); + return ret; + } + *mtime = sb.st_mtime; + return 0; +} + /** * Variable containing the FILE based credential cache implemention. * @@ -956,5 +977,6 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_fcc_ops = { fcc_get_cache_next, fcc_end_cache_get, fcc_move, - fcc_default_name + fcc_default_name, + fcc_lastchange }; diff --git a/lib/krb5/kcm.c b/lib/krb5/kcm.c index 35011da23..8a8f1efc1 100644 --- a/lib/krb5/kcm.c +++ b/lib/krb5/kcm.c @@ -872,6 +872,13 @@ kcm_default_name(krb5_context context, char **str) str); } +static krb5_error_code +kcm_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + *mtime = time(NULL); + return 0; +} + /** * Variable containing the KCM based credential cache implemention. * @@ -900,7 +907,9 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = { NULL, NULL, kcm_move, - kcm_default_name + kcm_default_name, + NULL, + kcm_lastchange }; krb5_boolean diff --git a/lib/krb5/mcache.c b/lib/krb5/mcache.c index 94c1a3a7d..752608069 100644 --- a/lib/krb5/mcache.c +++ b/lib/krb5/mcache.c @@ -45,6 +45,7 @@ typedef struct krb5_mcache { struct link *next; } *creds; struct krb5_mcache *next; + time_t mtime; } krb5_mcache; static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER; @@ -93,6 +94,7 @@ mcc_alloc(const char *name) m->refcnt = 1; m->primary_principal = NULL; m->creds = NULL; + m->mtime = time(NULL); m->next = mcc_head; mcc_head = m; HEIMDAL_MUTEX_unlock(&mcc_mutex); @@ -157,6 +159,7 @@ mcc_initialize(krb5_context context, { krb5_mcache *m = MCACHE(id); m->dead = 0; + m->mtime = time(NULL); return krb5_copy_principal (context, primary_principal, &m->primary_principal); @@ -252,6 +255,7 @@ mcc_store_cred(krb5_context context, free (l); return ret; } + m->mtime = time(NULL); return 0; } @@ -326,6 +330,7 @@ mcc_remove_cred(krb5_context context, *q = p->next; krb5_free_cred_contents(context, &p->cred); free(p); + m->mtime = time(NULL); } else q = &p->next; } @@ -432,6 +437,8 @@ mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) mto->primary_principal = mfrom->primary_principal; mfrom->primary_principal = principal; + mto->mtime = mfrom->mtime = time(NULL); + HEIMDAL_MUTEX_unlock(&mcc_mutex); mcc_destroy(context, from); @@ -450,6 +457,13 @@ mcc_default_name(krb5_context context, char **str) return 0; } +static krb5_error_code +mcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + *mtime = MCACHE(id)->mtime; + return 0; +} + /** * Variable containing the MEMORY based credential cache implemention. @@ -479,5 +493,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = { mcc_get_cache_next, mcc_end_cache_get, mcc_move, - mcc_default_name + mcc_default_name, + NULL, + mcc_lastchange };