xref: /freebsd/crypto/heimdal/lib/krb5/mcache.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6*ae771770SStanislav Sedov  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7*ae771770SStanislav Sedov  *
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 
36b528cefcSMark Murray #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;
48*ae771770SStanislav Sedov     time_t mtime;
49*ae771770SStanislav Sedov     krb5_deltat kdc_offset;
50b528cefcSMark Murray } krb5_mcache;
51b528cefcSMark Murray 
52c19800e8SDoug Rabson static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
535e9cd1aeSAssar Westerlund static struct krb5_mcache *mcc_head;
545e9cd1aeSAssar Westerlund 
555e9cd1aeSAssar Westerlund #define	MCACHE(X)	((krb5_mcache *)(X)->data.data)
565e9cd1aeSAssar Westerlund 
571c43270aSJacques Vidrine #define MISDEAD(X)	((X)->dead)
585e9cd1aeSAssar Westerlund 
59*ae771770SStanislav Sedov static const char* KRB5_CALLCONV
mcc_get_name(krb5_context context,krb5_ccache id)60b528cefcSMark Murray mcc_get_name(krb5_context context,
61b528cefcSMark Murray 	     krb5_ccache id)
62b528cefcSMark Murray {
635e9cd1aeSAssar Westerlund     return MCACHE(id)->name;
645e9cd1aeSAssar Westerlund }
655e9cd1aeSAssar Westerlund 
66*ae771770SStanislav Sedov static krb5_mcache * KRB5_CALLCONV
mcc_alloc(const char * name)675e9cd1aeSAssar Westerlund mcc_alloc(const char *name)
685e9cd1aeSAssar Westerlund {
69c19800e8SDoug Rabson     krb5_mcache *m, *m_c;
70*ae771770SStanislav Sedov     int ret = 0;
71adb0ddaeSAssar Westerlund 
725e9cd1aeSAssar Westerlund     ALLOC(m, 1);
735e9cd1aeSAssar Westerlund     if(m == NULL)
745e9cd1aeSAssar Westerlund 	return NULL;
755e9cd1aeSAssar Westerlund     if(name == NULL)
76*ae771770SStanislav Sedov 	ret = asprintf(&m->name, "%p", m);
775e9cd1aeSAssar Westerlund     else
785e9cd1aeSAssar Westerlund 	m->name = strdup(name);
79*ae771770SStanislav Sedov     if(ret < 0 || m->name == NULL) {
805e9cd1aeSAssar Westerlund 	free(m);
815e9cd1aeSAssar Westerlund 	return NULL;
825e9cd1aeSAssar Westerlund     }
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);
92c19800e8SDoug Rabson 	return NULL;
93c19800e8SDoug Rabson     }
94c19800e8SDoug Rabson 
951c43270aSJacques Vidrine     m->dead = 0;
965e9cd1aeSAssar Westerlund     m->refcnt = 1;
975e9cd1aeSAssar Westerlund     m->primary_principal = NULL;
985e9cd1aeSAssar Westerlund     m->creds = NULL;
99*ae771770SStanislav Sedov     m->mtime = time(NULL);
100*ae771770SStanislav Sedov     m->kdc_offset = 0;
1015e9cd1aeSAssar Westerlund     m->next = mcc_head;
1025e9cd1aeSAssar Westerlund     mcc_head = m;
103c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&mcc_mutex);
1045e9cd1aeSAssar Westerlund     return m;
105b528cefcSMark Murray }
106b528cefcSMark Murray 
107*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_resolve(krb5_context context,krb5_ccache * id,const char * res)108b528cefcSMark Murray mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
109b528cefcSMark Murray {
1105e9cd1aeSAssar Westerlund     krb5_mcache *m;
1115e9cd1aeSAssar Westerlund 
112c19800e8SDoug Rabson     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;
116c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&mcc_mutex);
1175e9cd1aeSAssar Westerlund 
1185e9cd1aeSAssar Westerlund     if (m != NULL) {
1195e9cd1aeSAssar Westerlund 	m->refcnt++;
1205e9cd1aeSAssar Westerlund 	(*id)->data.data = m;
1215e9cd1aeSAssar Westerlund 	(*id)->data.length = sizeof(*m);
1225e9cd1aeSAssar Westerlund 	return 0;
123b528cefcSMark Murray     }
124b528cefcSMark Murray 
1255e9cd1aeSAssar Westerlund     m = mcc_alloc(res);
126adb0ddaeSAssar Westerlund     if (m == NULL) {
127*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_CC_NOMEM,
128*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
1295e9cd1aeSAssar Westerlund 	return KRB5_CC_NOMEM;
130adb0ddaeSAssar Westerlund     }
1315e9cd1aeSAssar Westerlund 
1325e9cd1aeSAssar Westerlund     (*id)->data.data = m;
1335e9cd1aeSAssar Westerlund     (*id)->data.length = sizeof(*m);
1345e9cd1aeSAssar Westerlund 
1355e9cd1aeSAssar Westerlund     return 0;
1365e9cd1aeSAssar Westerlund }
1375e9cd1aeSAssar Westerlund 
1385e9cd1aeSAssar Westerlund 
139*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_gen_new(krb5_context context,krb5_ccache * id)140b528cefcSMark Murray mcc_gen_new(krb5_context context, krb5_ccache *id)
141b528cefcSMark Murray {
142b528cefcSMark Murray     krb5_mcache *m;
143b528cefcSMark Murray 
1445e9cd1aeSAssar Westerlund     m = mcc_alloc(NULL);
1455e9cd1aeSAssar Westerlund 
146adb0ddaeSAssar Westerlund     if (m == NULL) {
147*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_CC_NOMEM,
148*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
149b528cefcSMark Murray 	return KRB5_CC_NOMEM;
150adb0ddaeSAssar Westerlund     }
1515e9cd1aeSAssar Westerlund 
152b528cefcSMark Murray     (*id)->data.data = m;
153b528cefcSMark Murray     (*id)->data.length = sizeof(*m);
1545e9cd1aeSAssar Westerlund 
155b528cefcSMark Murray     return 0;
156b528cefcSMark Murray }
157b528cefcSMark Murray 
158*ae771770SStanislav Sedov 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,
160b528cefcSMark Murray 	       krb5_ccache id,
161b528cefcSMark Murray 	       krb5_principal primary_principal)
162b528cefcSMark Murray {
1631c43270aSJacques Vidrine     krb5_mcache *m = MCACHE(id);
1641c43270aSJacques Vidrine     m->dead = 0;
165*ae771770SStanislav Sedov     m->mtime = time(NULL);
1665e9cd1aeSAssar Westerlund     return krb5_copy_principal (context,
167b528cefcSMark Murray 				primary_principal,
1681c43270aSJacques Vidrine 				&m->primary_principal);
169b528cefcSMark Murray }
170b528cefcSMark Murray 
171c19800e8SDoug Rabson static int
mcc_close_internal(krb5_mcache * m)172c19800e8SDoug Rabson mcc_close_internal(krb5_mcache *m)
173b528cefcSMark Murray {
1745e9cd1aeSAssar Westerlund     if (--m->refcnt != 0)
1755e9cd1aeSAssar Westerlund 	return 0;
1765e9cd1aeSAssar Westerlund 
1775e9cd1aeSAssar Westerlund     if (MISDEAD(m)) {
1785e9cd1aeSAssar Westerlund 	free (m->name);
179c19800e8SDoug Rabson 	return 1;
180c19800e8SDoug Rabson     }
181c19800e8SDoug Rabson     return 0;
1825e9cd1aeSAssar Westerlund }
1835e9cd1aeSAssar Westerlund 
184*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_close(krb5_context context,krb5_ccache id)185c19800e8SDoug Rabson mcc_close(krb5_context context,
186c19800e8SDoug Rabson 	  krb5_ccache id)
187c19800e8SDoug Rabson {
188c19800e8SDoug Rabson     if (mcc_close_internal(MCACHE(id)))
189c19800e8SDoug Rabson 	krb5_data_free(&id->data);
1905e9cd1aeSAssar Westerlund     return 0;
1915e9cd1aeSAssar Westerlund }
1925e9cd1aeSAssar Westerlund 
193*ae771770SStanislav Sedov 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);
198b528cefcSMark Murray     struct link *l;
199b528cefcSMark Murray 
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
2055e9cd1aeSAssar Westerlund            list, and free all data */
206c19800e8SDoug Rabson 	HEIMDAL_MUTEX_lock(&mcc_mutex);
2075e9cd1aeSAssar Westerlund 	for(n = &mcc_head; n && *n; n = &(*n)->next) {
2085e9cd1aeSAssar Westerlund 	    if(m == *n) {
2095e9cd1aeSAssar Westerlund 		*n = m->next;
2105e9cd1aeSAssar Westerlund 		break;
2115e9cd1aeSAssar Westerlund 	    }
2125e9cd1aeSAssar Westerlund 	}
213c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&mcc_mutex);
2141c43270aSJacques Vidrine 	if (m->primary_principal != NULL) {
215b528cefcSMark Murray 	    krb5_free_principal (context, m->primary_principal);
2165e9cd1aeSAssar Westerlund 	    m->primary_principal = NULL;
2171c43270aSJacques Vidrine 	}
2181c43270aSJacques Vidrine 	m->dead = 1;
2195e9cd1aeSAssar Westerlund 
220b528cefcSMark Murray 	l = m->creds;
221b528cefcSMark Murray 	while (l != NULL) {
222b528cefcSMark Murray 	    struct link *old;
223b528cefcSMark Murray 
224c19800e8SDoug Rabson 	    krb5_free_cred_contents (context, &l->cred);
225b528cefcSMark Murray 	    old = l;
226b528cefcSMark Murray 	    l = l->next;
227b528cefcSMark Murray 	    free (old);
228b528cefcSMark Murray 	}
2295e9cd1aeSAssar Westerlund 	m->creds = NULL;
230b528cefcSMark Murray     }
231b528cefcSMark Murray     return 0;
232b528cefcSMark Murray }
233b528cefcSMark Murray 
234*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_store_cred(krb5_context context,krb5_ccache id,krb5_creds * creds)235b528cefcSMark Murray mcc_store_cred(krb5_context context,
236b528cefcSMark Murray 	       krb5_ccache id,
237b528cefcSMark Murray 	       krb5_creds *creds)
238b528cefcSMark Murray {
2395e9cd1aeSAssar Westerlund     krb5_mcache *m = MCACHE(id);
240b528cefcSMark Murray     krb5_error_code ret;
241b528cefcSMark Murray     struct link *l;
242b528cefcSMark Murray 
2435e9cd1aeSAssar Westerlund     if (MISDEAD(m))
2445e9cd1aeSAssar Westerlund 	return ENOENT;
2455e9cd1aeSAssar Westerlund 
246b528cefcSMark Murray     l = malloc (sizeof(*l));
247adb0ddaeSAssar Westerlund     if (l == NULL) {
248*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_CC_NOMEM,
249*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
250b528cefcSMark Murray 	return KRB5_CC_NOMEM;
251adb0ddaeSAssar Westerlund     }
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;
260b528cefcSMark Murray     }
261*ae771770SStanislav Sedov     m->mtime = time(NULL);
262b528cefcSMark Murray     return 0;
263b528cefcSMark Murray }
264b528cefcSMark Murray 
265*ae771770SStanislav Sedov 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 {
2705e9cd1aeSAssar Westerlund     krb5_mcache *m = MCACHE(id);
2715e9cd1aeSAssar Westerlund 
2721c43270aSJacques Vidrine     if (MISDEAD(m) || m->primary_principal == NULL)
2735e9cd1aeSAssar Westerlund 	return ENOENT;
274b528cefcSMark Murray     return krb5_copy_principal (context,
275b528cefcSMark Murray 				m->primary_principal,
276b528cefcSMark Murray 				principal);
277b528cefcSMark Murray }
278b528cefcSMark Murray 
279*ae771770SStanislav Sedov 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 {
2845e9cd1aeSAssar Westerlund     krb5_mcache *m = MCACHE(id);
2855e9cd1aeSAssar Westerlund 
2865e9cd1aeSAssar Westerlund     if (MISDEAD(m))
2875e9cd1aeSAssar Westerlund 	return ENOENT;
2885e9cd1aeSAssar Westerlund 
289b528cefcSMark Murray     *cursor = m->creds;
290b528cefcSMark Murray     return 0;
291b528cefcSMark Murray }
292b528cefcSMark Murray 
293*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_get_next(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)294b528cefcSMark Murray mcc_get_next (krb5_context context,
295b528cefcSMark Murray 	      krb5_ccache id,
296b528cefcSMark Murray 	      krb5_cc_cursor *cursor,
297b528cefcSMark Murray 	      krb5_creds *creds)
298b528cefcSMark Murray {
2995e9cd1aeSAssar Westerlund     krb5_mcache *m = MCACHE(id);
300b528cefcSMark Murray     struct link *l;
301b528cefcSMark Murray 
3025e9cd1aeSAssar Westerlund     if (MISDEAD(m))
3035e9cd1aeSAssar Westerlund 	return ENOENT;
3045e9cd1aeSAssar Westerlund 
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 
315*ae771770SStanislav Sedov 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,
317b528cefcSMark Murray 	     krb5_ccache id,
318b528cefcSMark Murray 	     krb5_cc_cursor *cursor)
319b528cefcSMark Murray {
320b528cefcSMark Murray     return 0;
321b528cefcSMark Murray }
322b528cefcSMark Murray 
323*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_remove_cred(krb5_context context,krb5_ccache id,krb5_flags which,krb5_creds * mcreds)324b528cefcSMark Murray mcc_remove_cred(krb5_context context,
325b528cefcSMark Murray 		 krb5_ccache id,
326b528cefcSMark Murray 		 krb5_flags which,
3275e9cd1aeSAssar Westerlund 		 krb5_creds *mcreds)
328b528cefcSMark Murray {
3295e9cd1aeSAssar Westerlund     krb5_mcache *m = MCACHE(id);
3305e9cd1aeSAssar Westerlund     struct link **q, *p;
3315e9cd1aeSAssar Westerlund     for(q = &m->creds, p = *q; p; p = *q) {
3325e9cd1aeSAssar Westerlund 	if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
3335e9cd1aeSAssar Westerlund 	    *q = p->next;
334c19800e8SDoug Rabson 	    krb5_free_cred_contents(context, &p->cred);
3355e9cd1aeSAssar Westerlund 	    free(p);
336*ae771770SStanislav Sedov 	    m->mtime = time(NULL);
3375e9cd1aeSAssar Westerlund 	} else
3385e9cd1aeSAssar Westerlund 	    q = &p->next;
3395e9cd1aeSAssar Westerlund     }
3405e9cd1aeSAssar Westerlund     return 0;
341b528cefcSMark Murray }
342b528cefcSMark Murray 
343*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)344b528cefcSMark Murray mcc_set_flags(krb5_context context,
345b528cefcSMark Murray 	      krb5_ccache id,
346b528cefcSMark Murray 	      krb5_flags flags)
347b528cefcSMark Murray {
348b528cefcSMark Murray     return 0; /* XXX */
349b528cefcSMark Murray }
350b528cefcSMark Murray 
351c19800e8SDoug Rabson struct mcache_iter {
352c19800e8SDoug Rabson     krb5_mcache *cache;
353c19800e8SDoug Rabson };
354c19800e8SDoug Rabson 
355*ae771770SStanislav Sedov 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) {
362*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
363*ae771770SStanislav Sedov 			       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 
377*ae771770SStanislav Sedov 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 
404*ae771770SStanislav Sedov 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 
416*ae771770SStanislav Sedov 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 
443*ae771770SStanislav Sedov     mto->mtime = mfrom->mtime = time(NULL);
444*ae771770SStanislav Sedov 
445c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&mcc_mutex);
446c19800e8SDoug Rabson     mcc_destroy(context, from);
447c19800e8SDoug Rabson 
448c19800e8SDoug Rabson     return 0;
449c19800e8SDoug Rabson }
450c19800e8SDoug Rabson 
451*ae771770SStanislav Sedov 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:");
455c19800e8SDoug Rabson     if (*str == NULL) {
456*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
457*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
458c19800e8SDoug Rabson 	return ENOMEM;
459c19800e8SDoug Rabson     }
460c19800e8SDoug Rabson     return 0;
461c19800e8SDoug Rabson }
462c19800e8SDoug Rabson 
463*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_lastchange(krb5_context context,krb5_ccache id,krb5_timestamp * mtime)464*ae771770SStanislav Sedov mcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
465*ae771770SStanislav Sedov {
466*ae771770SStanislav Sedov     *mtime = MCACHE(id)->mtime;
467*ae771770SStanislav Sedov     return 0;
468*ae771770SStanislav Sedov }
469*ae771770SStanislav Sedov 
470*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_set_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat kdc_offset)471*ae771770SStanislav Sedov mcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
472*ae771770SStanislav Sedov {
473*ae771770SStanislav Sedov     krb5_mcache *m = MCACHE(id);
474*ae771770SStanislav Sedov     m->kdc_offset = kdc_offset;
475*ae771770SStanislav Sedov     return 0;
476*ae771770SStanislav Sedov }
477*ae771770SStanislav Sedov 
478*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
mcc_get_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat * kdc_offset)479*ae771770SStanislav Sedov mcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
480*ae771770SStanislav Sedov {
481*ae771770SStanislav Sedov     krb5_mcache *m = MCACHE(id);
482*ae771770SStanislav Sedov     *kdc_offset = m->kdc_offset;
483*ae771770SStanislav Sedov     return 0;
484*ae771770SStanislav Sedov }
485*ae771770SStanislav Sedov 
486c19800e8SDoug Rabson 
487c19800e8SDoug Rabson /**
488c19800e8SDoug Rabson  * Variable containing the MEMORY based credential cache implemention.
489c19800e8SDoug Rabson  *
490c19800e8SDoug Rabson  * @ingroup krb5_ccache
491c19800e8SDoug Rabson  */
492c19800e8SDoug Rabson 
493*ae771770SStanislav Sedov KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = {
494*ae771770SStanislav Sedov     KRB5_CC_OPS_VERSION,
495b528cefcSMark Murray     "MEMORY",
496b528cefcSMark Murray     mcc_get_name,
497b528cefcSMark Murray     mcc_resolve,
498b528cefcSMark Murray     mcc_gen_new,
499b528cefcSMark Murray     mcc_initialize,
500b528cefcSMark Murray     mcc_destroy,
501b528cefcSMark Murray     mcc_close,
502b528cefcSMark Murray     mcc_store_cred,
503b528cefcSMark Murray     NULL, /* mcc_retrieve */
504b528cefcSMark Murray     mcc_get_principal,
505b528cefcSMark Murray     mcc_get_first,
506b528cefcSMark Murray     mcc_get_next,
507b528cefcSMark Murray     mcc_end_get,
508b528cefcSMark Murray     mcc_remove_cred,
509c19800e8SDoug Rabson     mcc_set_flags,
510c19800e8SDoug Rabson     NULL,
511c19800e8SDoug Rabson     mcc_get_cache_first,
512c19800e8SDoug Rabson     mcc_get_cache_next,
513c19800e8SDoug Rabson     mcc_end_cache_get,
514c19800e8SDoug Rabson     mcc_move,
515*ae771770SStanislav Sedov     mcc_default_name,
516*ae771770SStanislav Sedov     NULL,
517*ae771770SStanislav Sedov     mcc_lastchange,
518*ae771770SStanislav Sedov     mcc_set_kdc_offset,
519*ae771770SStanislav Sedov     mcc_get_kdc_offset
520b528cefcSMark Murray };
521