aboutsummaryrefslogtreecommitdiff
path: root/lib/krb5/mcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/krb5/mcache.c')
-rw-r--r--lib/krb5/mcache.c195
1 files changed, 137 insertions, 58 deletions
diff --git a/lib/krb5/mcache.c b/lib/krb5/mcache.c
index e4b90c17e7b2..474cb3a2bd2e 100644
--- a/lib/krb5/mcache.c
+++ b/lib/krb5/mcache.c
@@ -47,6 +47,7 @@ typedef struct krb5_mcache {
struct krb5_mcache *next;
time_t mtime;
krb5_deltat kdc_offset;
+ HEIMDAL_MUTEX mutex;
} krb5_mcache;
static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
@@ -99,6 +100,7 @@ mcc_alloc(const char *name)
m->mtime = time(NULL);
m->kdc_offset = 0;
m->next = mcc_head;
+ HEIMDAL_MUTEX_init(&(m->mutex));
mcc_head = m;
HEIMDAL_MUTEX_unlock(&mcc_mutex);
return m;
@@ -116,10 +118,12 @@ mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
HEIMDAL_MUTEX_unlock(&mcc_mutex);
if (m != NULL) {
- m->refcnt++;
- (*id)->data.data = m;
- (*id)->data.length = sizeof(*m);
- return 0;
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+ m->refcnt++;
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
+ (*id)->data.data = m;
+ (*id)->data.length = sizeof(*m);
+ return 0;
}
m = mcc_alloc(res);
@@ -155,29 +159,73 @@ mcc_gen_new(krb5_context context, krb5_ccache *id)
return 0;
}
+static void KRB5_CALLCONV
+mcc_destroy_internal(krb5_context context,
+ krb5_mcache *m)
+{
+ struct link *l;
+
+ if (m->primary_principal != NULL) {
+ krb5_free_principal (context, m->primary_principal);
+ m->primary_principal = NULL;
+ }
+ m->dead = 1;
+
+ l = m->creds;
+ while (l != NULL) {
+ struct link *old;
+
+ krb5_free_cred_contents (context, &l->cred);
+ old = l;
+ l = l->next;
+ free (old);
+ }
+
+ m->creds = NULL;
+ return;
+}
+
static krb5_error_code KRB5_CALLCONV
mcc_initialize(krb5_context context,
krb5_ccache id,
krb5_principal primary_principal)
{
krb5_mcache *m = MCACHE(id);
+ krb5_error_code ret = 0;
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+ heim_assert(m->refcnt != 0, "resurection released mcache");
+ /*
+ * It's important to destroy any existing
+ * creds here, that matches the baheviour
+ * of all other backends and also the
+ * MEMORY: backend in MIT.
+ */
+ mcc_destroy_internal(context, m);
m->dead = 0;
+ m->kdc_offset = 0;
m->mtime = time(NULL);
- return krb5_copy_principal (context,
- primary_principal,
- &m->primary_principal);
+ ret = krb5_copy_principal (context,
+ primary_principal,
+ &m->primary_principal);
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
+ return ret;
}
static int
mcc_close_internal(krb5_mcache *m)
{
- if (--m->refcnt != 0)
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+ heim_assert(m->refcnt != 0, "closed dead cache mcache");
+ if (--m->refcnt != 0) {
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
-
+ }
if (MISDEAD(m)) {
free (m->name);
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 1;
}
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}
@@ -185,8 +233,12 @@ static krb5_error_code KRB5_CALLCONV
mcc_close(krb5_context context,
krb5_ccache id)
{
- if (mcc_close_internal(MCACHE(id)))
+ krb5_mcache *m = MCACHE(id);
+
+ if (mcc_close_internal(MCACHE(id))) {
+ HEIMDAL_MUTEX_destroy(&(m->mutex));
krb5_data_free(&id->data);
+ }
return 0;
}
@@ -195,10 +247,13 @@ mcc_destroy(krb5_context context,
krb5_ccache id)
{
krb5_mcache **n, *m = MCACHE(id);
- struct link *l;
+ HEIMDAL_MUTEX_lock(&(m->mutex));
if (m->refcnt == 0)
- krb5_abortx(context, "mcc_destroy: refcnt already 0");
+ {
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
+ krb5_abortx(context, "mcc_destroy: refcnt already 0");
+ }
if (!MISDEAD(m)) {
/* if this is an active mcache, remove it from the linked
@@ -211,23 +266,9 @@ mcc_destroy(krb5_context context,
}
}
HEIMDAL_MUTEX_unlock(&mcc_mutex);
- if (m->primary_principal != NULL) {
- krb5_free_principal (context, m->primary_principal);
- m->primary_principal = NULL;
- }
- m->dead = 1;
-
- l = m->creds;
- while (l != NULL) {
- struct link *old;
-
- krb5_free_cred_contents (context, &l->cred);
- old = l;
- l = l->next;
- free (old);
- }
- m->creds = NULL;
+ mcc_destroy_internal(context, m);
}
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}
@@ -240,25 +281,32 @@ mcc_store_cred(krb5_context context,
krb5_error_code ret;
struct link *l;
+ HEIMDAL_MUTEX_lock(&(m->mutex));
if (MISDEAD(m))
- return ENOENT;
+ {
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
+ return ENOENT;
+ }
l = malloc (sizeof(*l));
if (l == NULL) {
- krb5_set_error_message(context, KRB5_CC_NOMEM,
- N_("malloc: out of memory", ""));
- return KRB5_CC_NOMEM;
+ krb5_set_error_message(context, KRB5_CC_NOMEM,
+ N_("malloc: out of memory", ""));
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
+ return KRB5_CC_NOMEM;
}
l->next = m->creds;
m->creds = l;
memset (&l->cred, 0, sizeof(l->cred));
ret = krb5_copy_creds_contents (context, creds, &l->cred);
if (ret) {
- m->creds = l->next;
- free (l);
- return ret;
+ m->creds = l->next;
+ free (l);
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
+ return ret;
}
m->mtime = time(NULL);
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}
@@ -268,25 +316,35 @@ mcc_get_principal(krb5_context context,
krb5_principal *principal)
{
krb5_mcache *m = MCACHE(id);
+ krb5_error_code ret = 0;
- if (MISDEAD(m) || m->primary_principal == NULL)
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+ if (MISDEAD(m) || m->primary_principal == NULL) {
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return ENOENT;
- return krb5_copy_principal (context,
- m->primary_principal,
- principal);
+ }
+ ret = krb5_copy_principal (context,
+ m->primary_principal,
+ principal);
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
+ return ret;
}
static krb5_error_code KRB5_CALLCONV
mcc_get_first (krb5_context context,
- krb5_ccache id,
- krb5_cc_cursor *cursor)
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
{
krb5_mcache *m = MCACHE(id);
- if (MISDEAD(m))
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+ if (MISDEAD(m)) {
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return ENOENT;
-
+ }
*cursor = m->creds;
+
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}
@@ -299,8 +357,12 @@ mcc_get_next (krb5_context context,
krb5_mcache *m = MCACHE(id);
struct link *l;
- if (MISDEAD(m))
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+ if (MISDEAD(m)) {
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return ENOENT;
+ }
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
l = *cursor;
if (l != NULL) {
@@ -328,6 +390,9 @@ mcc_remove_cred(krb5_context context,
{
krb5_mcache *m = MCACHE(id);
struct link **q, *p;
+
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+
for(q = &m->creds, p = *q; p; p = *q) {
if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
*q = p->next;
@@ -337,6 +402,7 @@ mcc_remove_cred(krb5_context context,
} else
q = &p->next;
}
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}
@@ -358,16 +424,16 @@ mcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
struct mcache_iter *iter;
iter = calloc(1, sizeof(*iter));
- if (iter == NULL) {
- krb5_set_error_message(context, ENOMEM,
- N_("malloc: out of memory", ""));
- return ENOMEM;
- }
+ if (iter == NULL)
+ return krb5_enomem(context);
HEIMDAL_MUTEX_lock(&mcc_mutex);
iter->cache = mcc_head;
- if (iter->cache)
+ if (iter->cache) {
+ HEIMDAL_MUTEX_lock(&(iter->cache->mutex));
iter->cache->refcnt++;
+ HEIMDAL_MUTEX_unlock(&(iter->cache->mutex));
+ }
HEIMDAL_MUTEX_unlock(&mcc_mutex);
*cursor = iter;
@@ -387,7 +453,12 @@ mcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
HEIMDAL_MUTEX_lock(&mcc_mutex);
m = iter->cache;
if (m->next)
- m->next->refcnt++;
+ {
+ HEIMDAL_MUTEX_lock(&(m->next->mutex));
+ m->next->refcnt++;
+ HEIMDAL_MUTEX_unlock(&(m->next->mutex));
+ }
+
iter->cache = m->next;
HEIMDAL_MUTEX_unlock(&mcc_mutex);
@@ -407,7 +478,7 @@ mcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
struct mcache_iter *iter = cursor;
if (iter->cache)
- mcc_close_internal(iter->cache);
+ mcc_close_internal(iter->cache);
iter->cache = NULL;
free(iter);
return 0;
@@ -431,6 +502,8 @@ mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
}
}
+ HEIMDAL_MUTEX_lock(&(mfrom->mutex));
+ HEIMDAL_MUTEX_lock(&(mto->mutex));
/* swap creds */
creds = mto->creds;
mto->creds = mfrom->creds;
@@ -442,6 +515,8 @@ mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
mto->mtime = mfrom->mtime = time(NULL);
+ HEIMDAL_MUTEX_unlock(&(mfrom->mutex));
+ HEIMDAL_MUTEX_unlock(&(mto->mutex));
HEIMDAL_MUTEX_unlock(&mcc_mutex);
mcc_destroy(context, from);
@@ -452,18 +527,18 @@ static krb5_error_code KRB5_CALLCONV
mcc_default_name(krb5_context context, char **str)
{
*str = strdup("MEMORY:");
- if (*str == NULL) {
- krb5_set_error_message(context, ENOMEM,
- N_("malloc: out of memory", ""));
- return ENOMEM;
- }
+ if (*str == NULL)
+ return krb5_enomem(context);
return 0;
}
static krb5_error_code KRB5_CALLCONV
mcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
{
- *mtime = MCACHE(id)->mtime;
+ krb5_mcache *m = MCACHE(id);
+ HEIMDAL_MUTEX_lock(&(m->mutex));
+ *mtime = m->mtime;
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}
@@ -471,7 +546,9 @@ static krb5_error_code KRB5_CALLCONV
mcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
{
krb5_mcache *m = MCACHE(id);
+ HEIMDAL_MUTEX_lock(&(m->mutex));
m->kdc_offset = kdc_offset;
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}
@@ -479,7 +556,9 @@ static krb5_error_code KRB5_CALLCONV
mcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
{
krb5_mcache *m = MCACHE(id);
+ HEIMDAL_MUTEX_lock(&(m->mutex));
*kdc_offset = m->kdc_offset;
+ HEIMDAL_MUTEX_unlock(&(m->mutex));
return 0;
}