xref: /freebsd/crypto/heimdal/lib/krb5/mcache.c (revision c19800e8)
1b528cefcSMark Murray /*
21c43270aSJacques Vidrine  * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7b528cefcSMark Murray  *
8b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
9b528cefcSMark Murray  * modification, are permitted provided that the following conditions
10b528cefcSMark Murray  * are met:
11b528cefcSMark Murray  *
12b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
13b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
14b528cefcSMark Murray  *
15b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
16b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
17b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
18b528cefcSMark Murray  *
19b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
20b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
21b528cefcSMark Murray  *    without specific prior written permission.
22b528cefcSMark Murray  *
23b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b528cefcSMark Murray  * SUCH DAMAGE.
34b528cefcSMark Murray  */
35b528cefcSMark Murray 
36c19800e8SDoug Rabson #include "krb5_locl.h"
37b528cefcSMark Murray 
38b528cefcSMark Murray typedef struct krb5_mcache {
395e9cd1aeSAssar Westerlund     char *name;
405e9cd1aeSAssar Westerlund     unsigned int refcnt;
411c43270aSJacques Vidrine     int dead;
42b528cefcSMark Murray     krb5_principal primary_principal;
43b528cefcSMark Murray     struct link {
44b528cefcSMark Murray 	krb5_creds cred;
45b528cefcSMark Murray 	struct link *next;
46b528cefcSMark Murray     } *creds;
475e9cd1aeSAssar Westerlund     struct krb5_mcache *next;
48b528cefcSMark Murray     time_t mtime;
49b528cefcSMark Murray     krb5_deltat kdc_offset;
50c19800e8SDoug Rabson } krb5_mcache;
515e9cd1aeSAssar Westerlund 
525e9cd1aeSAssar Westerlund static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
535e9cd1aeSAssar Westerlund static struct krb5_mcache *mcc_head;
545e9cd1aeSAssar Westerlund 
551c43270aSJacques Vidrine #define	MCACHE(X)	((krb5_mcache *)(X)->data.data)
565e9cd1aeSAssar Westerlund 
578373020dSJacques Vidrine #define MISDEAD(X)	((X)->dead)
58b528cefcSMark Murray 
59b528cefcSMark Murray static const char* KRB5_CALLCONV
mcc_get_name(krb5_context context,krb5_ccache id)60b528cefcSMark Murray mcc_get_name(krb5_context context,
615e9cd1aeSAssar Westerlund 	     krb5_ccache id)
625e9cd1aeSAssar Westerlund {
635e9cd1aeSAssar Westerlund     return MCACHE(id)->name;
645e9cd1aeSAssar Westerlund }
655e9cd1aeSAssar Westerlund 
665e9cd1aeSAssar Westerlund static krb5_mcache * KRB5_CALLCONV
mcc_alloc(const char * name)67c19800e8SDoug Rabson mcc_alloc(const char *name)
68adb0ddaeSAssar Westerlund {
695e9cd1aeSAssar Westerlund     krb5_mcache *m, *m_c;
705e9cd1aeSAssar Westerlund     int ret = 0;
715e9cd1aeSAssar Westerlund 
725e9cd1aeSAssar Westerlund     ALLOC(m, 1);
735e9cd1aeSAssar Westerlund     if(m == NULL)
745e9cd1aeSAssar Westerlund 	return NULL;
755e9cd1aeSAssar Westerlund     if(name == NULL)
765e9cd1aeSAssar Westerlund 	ret = asprintf(&m->name, "%p", m);
775e9cd1aeSAssar Westerlund     else
785e9cd1aeSAssar Westerlund 	m->name = strdup(name);
795e9cd1aeSAssar Westerlund     if(ret < 0 || m->name == NULL) {
80c19800e8SDoug Rabson 	free(m);
81c19800e8SDoug Rabson 	return NULL;
82c19800e8SDoug Rabson     }
83c19800e8SDoug Rabson     /* check for dups first */
84c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&mcc_mutex);
85c19800e8SDoug Rabson     for (m_c = mcc_head; m_c != NULL; m_c = m_c->next)
86c19800e8SDoug Rabson 	if (strcmp(m->name, m_c->name) == 0)
87c19800e8SDoug Rabson 	    break;
88c19800e8SDoug Rabson     if (m_c) {
89c19800e8SDoug Rabson 	free(m->name);
90c19800e8SDoug Rabson 	free(m);
91c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&mcc_mutex);
921c43270aSJacques Vidrine 	return NULL;
935e9cd1aeSAssar Westerlund     }
945e9cd1aeSAssar Westerlund 
955e9cd1aeSAssar Westerlund     m->dead = 0;
965e9cd1aeSAssar Westerlund     m->refcnt = 1;
975e9cd1aeSAssar Westerlund     m->primary_principal = NULL;
98c19800e8SDoug Rabson     m->creds = NULL;
995e9cd1aeSAssar Westerlund     m->mtime = time(NULL);
100b528cefcSMark Murray     m->kdc_offset = 0;
101b528cefcSMark Murray     m->next = mcc_head;
102b528cefcSMark Murray     mcc_head = m;
103b528cefcSMark Murray     HEIMDAL_MUTEX_unlock(&mcc_mutex);
104b528cefcSMark Murray     return m;
1055e9cd1aeSAssar Westerlund }
1065e9cd1aeSAssar Westerlund 
107c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_resolve(krb5_context context,krb5_ccache * id,const char * res)1085e9cd1aeSAssar Westerlund mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
1095e9cd1aeSAssar Westerlund {
1105e9cd1aeSAssar Westerlund     krb5_mcache *m;
111c19800e8SDoug Rabson 
1125e9cd1aeSAssar Westerlund     HEIMDAL_MUTEX_lock(&mcc_mutex);
1135e9cd1aeSAssar Westerlund     for (m = mcc_head; m != NULL; m = m->next)
1145e9cd1aeSAssar Westerlund 	if (strcmp(m->name, res) == 0)
1155e9cd1aeSAssar Westerlund 	    break;
1165e9cd1aeSAssar Westerlund     HEIMDAL_MUTEX_unlock(&mcc_mutex);
1175e9cd1aeSAssar Westerlund 
118b528cefcSMark Murray     if (m != NULL) {
119b528cefcSMark Murray 	m->refcnt++;
1205e9cd1aeSAssar Westerlund 	(*id)->data.data = m;
121adb0ddaeSAssar Westerlund 	(*id)->data.length = sizeof(*m);
122adb0ddaeSAssar Westerlund 	return 0;
1235e9cd1aeSAssar Westerlund     }
124adb0ddaeSAssar Westerlund 
1255e9cd1aeSAssar Westerlund     m = mcc_alloc(res);
1265e9cd1aeSAssar Westerlund     if (m == NULL) {
1275e9cd1aeSAssar Westerlund 	krb5_set_error_message(context, KRB5_CC_NOMEM,
1285e9cd1aeSAssar Westerlund 			       N_("malloc: out of memory", ""));
1295e9cd1aeSAssar Westerlund 	return KRB5_CC_NOMEM;
1305e9cd1aeSAssar Westerlund     }
1315e9cd1aeSAssar Westerlund 
1325e9cd1aeSAssar Westerlund     (*id)->data.data = m;
133b528cefcSMark Murray     (*id)->data.length = sizeof(*m);
134b528cefcSMark Murray 
135b528cefcSMark Murray     return 0;
136b528cefcSMark Murray }
137b528cefcSMark Murray 
1385e9cd1aeSAssar Westerlund 
1395e9cd1aeSAssar Westerlund static krb5_error_code KRB5_CALLCONV
mcc_gen_new(krb5_context context,krb5_ccache * id)140adb0ddaeSAssar Westerlund mcc_gen_new(krb5_context context, krb5_ccache *id)
141adb0ddaeSAssar Westerlund {
142b528cefcSMark Murray     krb5_mcache *m;
143adb0ddaeSAssar Westerlund 
1445e9cd1aeSAssar Westerlund     m = mcc_alloc(NULL);
145b528cefcSMark Murray 
146b528cefcSMark Murray     if (m == NULL) {
1475e9cd1aeSAssar Westerlund 	krb5_set_error_message(context, KRB5_CC_NOMEM,
148b528cefcSMark Murray 			       N_("malloc: out of memory", ""));
149b528cefcSMark Murray 	return KRB5_CC_NOMEM;
150b528cefcSMark Murray     }
151b528cefcSMark Murray 
152b528cefcSMark Murray     (*id)->data.data = m;
153b528cefcSMark Murray     (*id)->data.length = sizeof(*m);
154b528cefcSMark Murray 
155b528cefcSMark Murray     return 0;
1561c43270aSJacques Vidrine }
1571c43270aSJacques Vidrine 
1585e9cd1aeSAssar Westerlund static krb5_error_code KRB5_CALLCONV
mcc_initialize(krb5_context context,krb5_ccache id,krb5_principal primary_principal)159b528cefcSMark Murray mcc_initialize(krb5_context context,
1601c43270aSJacques Vidrine 	       krb5_ccache id,
161b528cefcSMark Murray 	       krb5_principal primary_principal)
162b528cefcSMark Murray {
163c19800e8SDoug Rabson     krb5_mcache *m = MCACHE(id);
164c19800e8SDoug Rabson     m->dead = 0;
165b528cefcSMark Murray     m->mtime = time(NULL);
1665e9cd1aeSAssar Westerlund     return krb5_copy_principal (context,
1675e9cd1aeSAssar Westerlund 				primary_principal,
1685e9cd1aeSAssar Westerlund 				&m->primary_principal);
1695e9cd1aeSAssar Westerlund }
1705e9cd1aeSAssar Westerlund 
171c19800e8SDoug Rabson static int
mcc_close_internal(krb5_mcache * m)172c19800e8SDoug Rabson mcc_close_internal(krb5_mcache *m)
173c19800e8SDoug Rabson {
1745e9cd1aeSAssar Westerlund     if (--m->refcnt != 0)
1755e9cd1aeSAssar Westerlund 	return 0;
176c19800e8SDoug Rabson 
177c19800e8SDoug Rabson     if (MISDEAD(m)) {
178c19800e8SDoug Rabson 	free (m->name);
179c19800e8SDoug Rabson 	return 1;
180c19800e8SDoug Rabson     }
181c19800e8SDoug Rabson     return 0;
1825e9cd1aeSAssar Westerlund }
1835e9cd1aeSAssar Westerlund 
1845e9cd1aeSAssar Westerlund static krb5_error_code KRB5_CALLCONV
mcc_close(krb5_context context,krb5_ccache id)1855e9cd1aeSAssar Westerlund mcc_close(krb5_context context,
1865e9cd1aeSAssar Westerlund 	  krb5_ccache id)
1875e9cd1aeSAssar Westerlund {
1885e9cd1aeSAssar Westerlund     if (mcc_close_internal(MCACHE(id)))
1895e9cd1aeSAssar Westerlund 	krb5_data_free(&id->data);
190b528cefcSMark Murray     return 0;
191b528cefcSMark Murray }
1925e9cd1aeSAssar Westerlund 
1935e9cd1aeSAssar Westerlund static krb5_error_code KRB5_CALLCONV
mcc_destroy(krb5_context context,krb5_ccache id)1945e9cd1aeSAssar Westerlund mcc_destroy(krb5_context context,
1955e9cd1aeSAssar Westerlund 	    krb5_ccache id)
1965e9cd1aeSAssar Westerlund {
1975e9cd1aeSAssar Westerlund     krb5_mcache **n, *m = MCACHE(id);
198c19800e8SDoug Rabson     struct link *l;
1995e9cd1aeSAssar Westerlund 
2005e9cd1aeSAssar Westerlund     if (m->refcnt == 0)
2015e9cd1aeSAssar Westerlund 	krb5_abortx(context, "mcc_destroy: refcnt already 0");
2025e9cd1aeSAssar Westerlund 
2035e9cd1aeSAssar Westerlund     if (!MISDEAD(m)) {
2045e9cd1aeSAssar Westerlund 	/* if this is an active mcache, remove it from the linked
205c19800e8SDoug Rabson            list, and free all data */
2061c43270aSJacques Vidrine 	HEIMDAL_MUTEX_lock(&mcc_mutex);
207b528cefcSMark Murray 	for(n = &mcc_head; n && *n; n = &(*n)->next) {
2085e9cd1aeSAssar Westerlund 	    if(m == *n) {
2091c43270aSJacques Vidrine 		*n = m->next;
2101c43270aSJacques Vidrine 		break;
2115e9cd1aeSAssar Westerlund 	    }
212b528cefcSMark Murray 	}
213b528cefcSMark Murray 	HEIMDAL_MUTEX_unlock(&mcc_mutex);
214b528cefcSMark Murray 	if (m->primary_principal != NULL) {
215b528cefcSMark Murray 	    krb5_free_principal (context, m->primary_principal);
216c19800e8SDoug Rabson 	    m->primary_principal = NULL;
217b528cefcSMark Murray 	}
218b528cefcSMark Murray 	m->dead = 1;
219b528cefcSMark Murray 
220b528cefcSMark Murray 	l = m->creds;
2215e9cd1aeSAssar Westerlund 	while (l != NULL) {
222b528cefcSMark Murray 	    struct link *old;
223b528cefcSMark Murray 
224b528cefcSMark Murray 	    krb5_free_cred_contents (context, &l->cred);
225b528cefcSMark Murray 	    old = l;
226b528cefcSMark Murray 	    l = l->next;
227b528cefcSMark Murray 	    free (old);
228b528cefcSMark Murray 	}
229b528cefcSMark Murray 	m->creds = NULL;
230b528cefcSMark Murray     }
2315e9cd1aeSAssar Westerlund     return 0;
232b528cefcSMark Murray }
233b528cefcSMark Murray 
234b528cefcSMark Murray static krb5_error_code KRB5_CALLCONV
mcc_store_cred(krb5_context context,krb5_ccache id,krb5_creds * creds)2355e9cd1aeSAssar Westerlund mcc_store_cred(krb5_context context,
2365e9cd1aeSAssar Westerlund 	       krb5_ccache id,
2375e9cd1aeSAssar Westerlund 	       krb5_creds *creds)
238b528cefcSMark Murray {
239adb0ddaeSAssar Westerlund     krb5_mcache *m = MCACHE(id);
240adb0ddaeSAssar Westerlund     krb5_error_code ret;
241b528cefcSMark Murray     struct link *l;
242adb0ddaeSAssar Westerlund 
243b528cefcSMark Murray     if (MISDEAD(m))
244b528cefcSMark Murray 	return ENOENT;
245b528cefcSMark Murray 
246b528cefcSMark Murray     l = malloc (sizeof(*l));
247b528cefcSMark Murray     if (l == NULL) {
248b528cefcSMark Murray 	krb5_set_error_message(context, KRB5_CC_NOMEM,
249b528cefcSMark Murray 			       N_("malloc: out of memory", ""));
250b528cefcSMark Murray 	return KRB5_CC_NOMEM;
251b528cefcSMark Murray     }
252b528cefcSMark Murray     l->next = m->creds;
253b528cefcSMark Murray     m->creds = l;
254b528cefcSMark Murray     memset (&l->cred, 0, sizeof(l->cred));
255b528cefcSMark Murray     ret = krb5_copy_creds_contents (context, creds, &l->cred);
256b528cefcSMark Murray     if (ret) {
257b528cefcSMark Murray 	m->creds = l->next;
258b528cefcSMark Murray 	free (l);
259b528cefcSMark Murray 	return ret;
2605e9cd1aeSAssar Westerlund     }
2615e9cd1aeSAssar Westerlund     m->mtime = time(NULL);
2621c43270aSJacques Vidrine     return 0;
2635e9cd1aeSAssar Westerlund }
264b528cefcSMark Murray 
265b528cefcSMark Murray static krb5_error_code KRB5_CALLCONV
mcc_get_principal(krb5_context context,krb5_ccache id,krb5_principal * principal)266b528cefcSMark Murray mcc_get_principal(krb5_context context,
267b528cefcSMark Murray 		  krb5_ccache id,
268b528cefcSMark Murray 		  krb5_principal *principal)
269b528cefcSMark Murray {
270b528cefcSMark Murray     krb5_mcache *m = MCACHE(id);
271b528cefcSMark Murray 
272b528cefcSMark Murray     if (MISDEAD(m) || m->primary_principal == NULL)
273b528cefcSMark Murray 	return ENOENT;
2745e9cd1aeSAssar Westerlund     return krb5_copy_principal (context,
2755e9cd1aeSAssar Westerlund 				m->primary_principal,
2765e9cd1aeSAssar Westerlund 				principal);
2775e9cd1aeSAssar Westerlund }
2785e9cd1aeSAssar Westerlund 
279b528cefcSMark Murray static krb5_error_code KRB5_CALLCONV
mcc_get_first(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)280b528cefcSMark Murray mcc_get_first (krb5_context context,
281b528cefcSMark Murray 	       krb5_ccache id,
282b528cefcSMark Murray 	       krb5_cc_cursor *cursor)
283b528cefcSMark Murray {
284b528cefcSMark Murray     krb5_mcache *m = MCACHE(id);
285b528cefcSMark Murray 
286b528cefcSMark Murray     if (MISDEAD(m))
287b528cefcSMark Murray 	return ENOENT;
288b528cefcSMark Murray 
2895e9cd1aeSAssar Westerlund     *cursor = m->creds;
290b528cefcSMark Murray     return 0;
291b528cefcSMark Murray }
2925e9cd1aeSAssar Westerlund 
2935e9cd1aeSAssar Westerlund static krb5_error_code KRB5_CALLCONV
mcc_get_next(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)2945e9cd1aeSAssar Westerlund mcc_get_next (krb5_context context,
295b528cefcSMark Murray 	      krb5_ccache id,
296b528cefcSMark Murray 	      krb5_cc_cursor *cursor,
297b528cefcSMark Murray 	      krb5_creds *creds)
298b528cefcSMark Murray {
299b528cefcSMark Murray     krb5_mcache *m = MCACHE(id);
300b528cefcSMark Murray     struct link *l;
301b528cefcSMark Murray 
302b528cefcSMark Murray     if (MISDEAD(m))
303b528cefcSMark Murray 	return ENOENT;
304b528cefcSMark Murray 
305b528cefcSMark Murray     l = *cursor;
306b528cefcSMark Murray     if (l != NULL) {
307b528cefcSMark Murray 	*cursor = l->next;
308b528cefcSMark Murray 	return krb5_copy_creds_contents (context,
309b528cefcSMark Murray 					 &l->cred,
310b528cefcSMark Murray 					 creds);
311b528cefcSMark Murray     } else
312b528cefcSMark Murray 	return KRB5_CC_END;
313b528cefcSMark Murray }
314b528cefcSMark Murray 
315b528cefcSMark Murray static krb5_error_code KRB5_CALLCONV
mcc_end_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)316b528cefcSMark Murray mcc_end_get (krb5_context context,
3175e9cd1aeSAssar Westerlund 	     krb5_ccache id,
318b528cefcSMark Murray 	     krb5_cc_cursor *cursor)
3195e9cd1aeSAssar Westerlund {
3205e9cd1aeSAssar Westerlund     return 0;
3215e9cd1aeSAssar Westerlund }
3225e9cd1aeSAssar Westerlund 
3235e9cd1aeSAssar Westerlund static krb5_error_code KRB5_CALLCONV
mcc_remove_cred(krb5_context context,krb5_ccache id,krb5_flags which,krb5_creds * mcreds)324c19800e8SDoug Rabson mcc_remove_cred(krb5_context context,
3255e9cd1aeSAssar Westerlund 		 krb5_ccache id,
3265e9cd1aeSAssar Westerlund 		 krb5_flags which,
3275e9cd1aeSAssar Westerlund 		 krb5_creds *mcreds)
3285e9cd1aeSAssar Westerlund {
3295e9cd1aeSAssar Westerlund     krb5_mcache *m = MCACHE(id);
330b528cefcSMark Murray     struct link **q, *p;
331b528cefcSMark Murray     for(q = &m->creds, p = *q; p; p = *q) {
332b528cefcSMark Murray 	if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
333b528cefcSMark Murray 	    *q = p->next;
334b528cefcSMark Murray 	    krb5_free_cred_contents(context, &p->cred);
335b528cefcSMark Murray 	    free(p);
336b528cefcSMark Murray 	    m->mtime = time(NULL);
337b528cefcSMark Murray 	} else
338b528cefcSMark Murray 	    q = &p->next;
339b528cefcSMark Murray     }
340c19800e8SDoug Rabson     return 0;
341c19800e8SDoug Rabson }
342c19800e8SDoug Rabson 
343c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)344c19800e8SDoug Rabson mcc_set_flags(krb5_context context,
345c19800e8SDoug Rabson 	      krb5_ccache id,
346c19800e8SDoug Rabson 	      krb5_flags flags)
347c19800e8SDoug Rabson {
348c19800e8SDoug Rabson     return 0; /* XXX */
349c19800e8SDoug Rabson }
350c19800e8SDoug Rabson 
351c19800e8SDoug Rabson struct mcache_iter {
352c19800e8SDoug Rabson     krb5_mcache *cache;
353c19800e8SDoug Rabson };
354c19800e8SDoug Rabson 
355c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_get_cache_first(krb5_context context,krb5_cc_cursor * cursor)356c19800e8SDoug Rabson mcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
357c19800e8SDoug Rabson {
358c19800e8SDoug Rabson     struct mcache_iter *iter;
359c19800e8SDoug Rabson 
360c19800e8SDoug Rabson     iter = calloc(1, sizeof(*iter));
361c19800e8SDoug Rabson     if (iter == NULL) {
362c19800e8SDoug Rabson 	krb5_set_error_message(context, ENOMEM,
363c19800e8SDoug Rabson 			       N_("malloc: out of memory", ""));
364c19800e8SDoug Rabson 	return ENOMEM;
365c19800e8SDoug Rabson     }
366c19800e8SDoug Rabson 
367c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&mcc_mutex);
368c19800e8SDoug Rabson     iter->cache = mcc_head;
369c19800e8SDoug Rabson     if (iter->cache)
370c19800e8SDoug Rabson 	iter->cache->refcnt++;
371c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&mcc_mutex);
372c19800e8SDoug Rabson 
373c19800e8SDoug Rabson     *cursor = iter;
374c19800e8SDoug Rabson     return 0;
375c19800e8SDoug Rabson }
376c19800e8SDoug Rabson 
377c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_get_cache_next(krb5_context context,krb5_cc_cursor cursor,krb5_ccache * id)378c19800e8SDoug Rabson mcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
379c19800e8SDoug Rabson {
380c19800e8SDoug Rabson     struct mcache_iter *iter = cursor;
381c19800e8SDoug Rabson     krb5_error_code ret;
382c19800e8SDoug Rabson     krb5_mcache *m;
383c19800e8SDoug Rabson 
384c19800e8SDoug Rabson     if (iter->cache == NULL)
385c19800e8SDoug Rabson 	return KRB5_CC_END;
386c19800e8SDoug Rabson 
387c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&mcc_mutex);
388c19800e8SDoug Rabson     m = iter->cache;
389c19800e8SDoug Rabson     if (m->next)
390c19800e8SDoug Rabson 	m->next->refcnt++;
391c19800e8SDoug Rabson     iter->cache = m->next;
392c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&mcc_mutex);
393c19800e8SDoug Rabson 
394c19800e8SDoug Rabson     ret = _krb5_cc_allocate(context, &krb5_mcc_ops, id);
395c19800e8SDoug Rabson     if (ret)
396c19800e8SDoug Rabson 	return ret;
397c19800e8SDoug Rabson 
398c19800e8SDoug Rabson     (*id)->data.data = m;
399c19800e8SDoug Rabson     (*id)->data.length = sizeof(*m);
400c19800e8SDoug Rabson 
401c19800e8SDoug Rabson     return 0;
402c19800e8SDoug Rabson }
403c19800e8SDoug Rabson 
404c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_end_cache_get(krb5_context context,krb5_cc_cursor cursor)405c19800e8SDoug Rabson mcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
406c19800e8SDoug Rabson {
407c19800e8SDoug Rabson     struct mcache_iter *iter = cursor;
408c19800e8SDoug Rabson 
409c19800e8SDoug Rabson     if (iter->cache)
410c19800e8SDoug Rabson 	mcc_close_internal(iter->cache);
411c19800e8SDoug Rabson     iter->cache = NULL;
412c19800e8SDoug Rabson     free(iter);
413c19800e8SDoug Rabson     return 0;
414c19800e8SDoug Rabson }
415c19800e8SDoug Rabson 
416c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_move(krb5_context context,krb5_ccache from,krb5_ccache to)417c19800e8SDoug Rabson mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
418c19800e8SDoug Rabson {
419c19800e8SDoug Rabson     krb5_mcache *mfrom = MCACHE(from), *mto = MCACHE(to);
420c19800e8SDoug Rabson     struct link *creds;
421c19800e8SDoug Rabson     krb5_principal principal;
422c19800e8SDoug Rabson     krb5_mcache **n;
423c19800e8SDoug Rabson 
424c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&mcc_mutex);
425c19800e8SDoug Rabson 
426c19800e8SDoug Rabson     /* drop the from cache from the linked list to avoid lookups */
427c19800e8SDoug Rabson     for(n = &mcc_head; n && *n; n = &(*n)->next) {
428c19800e8SDoug Rabson 	if(mfrom == *n) {
429c19800e8SDoug Rabson 	    *n = mfrom->next;
430c19800e8SDoug Rabson 	    break;
431c19800e8SDoug Rabson 	}
432c19800e8SDoug Rabson     }
433c19800e8SDoug Rabson 
434c19800e8SDoug Rabson     /* swap creds */
435c19800e8SDoug Rabson     creds = mto->creds;
436c19800e8SDoug Rabson     mto->creds = mfrom->creds;
437c19800e8SDoug Rabson     mfrom->creds = creds;
438c19800e8SDoug Rabson     /* swap principal */
439c19800e8SDoug Rabson     principal = mto->primary_principal;
440c19800e8SDoug Rabson     mto->primary_principal = mfrom->primary_principal;
441c19800e8SDoug Rabson     mfrom->primary_principal = principal;
442c19800e8SDoug Rabson 
443c19800e8SDoug Rabson     mto->mtime = mfrom->mtime = time(NULL);
444c19800e8SDoug Rabson 
445c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&mcc_mutex);
446c19800e8SDoug Rabson     mcc_destroy(context, from);
447c19800e8SDoug Rabson 
448c19800e8SDoug Rabson     return 0;
449c19800e8SDoug Rabson }
450c19800e8SDoug Rabson 
451c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_default_name(krb5_context context,char ** str)452c19800e8SDoug Rabson mcc_default_name(krb5_context context, char **str)
453c19800e8SDoug Rabson {
454c19800e8SDoug Rabson     *str = strdup("MEMORY:");
455b528cefcSMark Murray     if (*str == NULL) {
456b528cefcSMark Murray 	krb5_set_error_message(context, ENOMEM,
457b528cefcSMark Murray 			       N_("malloc: out of memory", ""));
458b528cefcSMark Murray 	return ENOMEM;
459b528cefcSMark Murray     }
460b528cefcSMark Murray     return 0;
461b528cefcSMark Murray }
462b528cefcSMark Murray 
463b528cefcSMark Murray static krb5_error_code KRB5_CALLCONV
mcc_lastchange(krb5_context context,krb5_ccache id,krb5_timestamp * mtime)464b528cefcSMark Murray mcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
465b528cefcSMark Murray {
466b528cefcSMark Murray     *mtime = MCACHE(id)->mtime;
467b528cefcSMark Murray     return 0;
468b528cefcSMark Murray }
469b528cefcSMark Murray 
470c19800e8SDoug Rabson static krb5_error_code KRB5_CALLCONV
mcc_set_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat kdc_offset)471c19800e8SDoug Rabson mcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
472c19800e8SDoug Rabson {
473c19800e8SDoug Rabson     krb5_mcache *m = MCACHE(id);
474c19800e8SDoug Rabson     m->kdc_offset = kdc_offset;
475c19800e8SDoug Rabson     return 0;
476c19800e8SDoug Rabson }
477b528cefcSMark Murray 
478 static krb5_error_code KRB5_CALLCONV
mcc_get_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat * kdc_offset)479 mcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
480 {
481     krb5_mcache *m = MCACHE(id);
482     *kdc_offset = m->kdc_offset;
483     return 0;
484 }
485 
486 
487 /**
488  * Variable containing the MEMORY based credential cache implemention.
489  *
490  * @ingroup krb5_ccache
491  */
492 
493 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = {
494     KRB5_CC_OPS_VERSION,
495     "MEMORY",
496     mcc_get_name,
497     mcc_resolve,
498     mcc_gen_new,
499     mcc_initialize,
500     mcc_destroy,
501     mcc_close,
502     mcc_store_cred,
503     NULL, /* mcc_retrieve */
504     mcc_get_principal,
505     mcc_get_first,
506     mcc_get_next,
507     mcc_end_get,
508     mcc_remove_cred,
509     mcc_set_flags,
510     NULL,
511     mcc_get_cache_first,
512     mcc_get_cache_next,
513     mcc_end_cache_get,
514     mcc_move,
515     mcc_default_name,
516     NULL,
517     mcc_lastchange,
518     mcc_set_kdc_offset,
519     mcc_get_kdc_offset
520 };
521