use DES_set_key_unchecked().
[heimdal.git] / lib / krb5 / mcache.c
blob2f15fbb15f8b3d39b1b39e7251b5550d5f8bec10
1 /*
2 * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
36 RCSID("$Id$");
38 typedef struct krb5_mcache {
39 char *name;
40 unsigned int refcnt;
41 int dead;
42 krb5_principal primary_principal;
43 struct link {
44 krb5_creds cred;
45 struct link *next;
46 } *creds;
47 struct krb5_mcache *next;
48 } krb5_mcache;
50 static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
51 static struct krb5_mcache *mcc_head;
53 #define MCACHE(X) ((krb5_mcache *)(X)->data.data)
55 #define MISDEAD(X) ((X)->dead)
57 static const char*
58 mcc_get_name(krb5_context context,
59 krb5_ccache id)
61 return MCACHE(id)->name;
64 static krb5_mcache *
65 mcc_alloc(const char *name)
67 krb5_mcache *m, *m_c;
69 ALLOC(m, 1);
70 if(m == NULL)
71 return NULL;
72 if(name == NULL)
73 asprintf(&m->name, "%p", m);
74 else
75 m->name = strdup(name);
76 if(m->name == NULL) {
77 free(m);
78 return NULL;
80 /* check for dups first */
81 HEIMDAL_MUTEX_lock(&mcc_mutex);
82 for (m_c = mcc_head; m_c != NULL; m_c = m_c->next)
83 if (strcmp(m->name, m_c->name) == 0)
84 break;
85 if (m_c) {
86 free(m->name);
87 free(m);
88 HEIMDAL_MUTEX_unlock(&mcc_mutex);
89 return NULL;
92 m->dead = 0;
93 m->refcnt = 1;
94 m->primary_principal = NULL;
95 m->creds = NULL;
96 m->next = mcc_head;
97 mcc_head = m;
98 HEIMDAL_MUTEX_unlock(&mcc_mutex);
99 return m;
102 static krb5_error_code
103 mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
105 krb5_mcache *m;
107 HEIMDAL_MUTEX_lock(&mcc_mutex);
108 for (m = mcc_head; m != NULL; m = m->next)
109 if (strcmp(m->name, res) == 0)
110 break;
111 HEIMDAL_MUTEX_unlock(&mcc_mutex);
113 if (m != NULL) {
114 m->refcnt++;
115 (*id)->data.data = m;
116 (*id)->data.length = sizeof(*m);
117 return 0;
120 m = mcc_alloc(res);
121 if (m == NULL) {
122 krb5_set_error_string (context, "malloc: out of memory");
123 return KRB5_CC_NOMEM;
126 (*id)->data.data = m;
127 (*id)->data.length = sizeof(*m);
129 return 0;
133 static krb5_error_code
134 mcc_gen_new(krb5_context context, krb5_ccache *id)
136 krb5_mcache *m;
138 m = mcc_alloc(NULL);
140 if (m == NULL) {
141 krb5_set_error_string (context, "malloc: out of memory");
142 return KRB5_CC_NOMEM;
145 (*id)->data.data = m;
146 (*id)->data.length = sizeof(*m);
148 return 0;
151 static krb5_error_code
152 mcc_initialize(krb5_context context,
153 krb5_ccache id,
154 krb5_principal primary_principal)
156 krb5_mcache *m = MCACHE(id);
157 m->dead = 0;
158 return krb5_copy_principal (context,
159 primary_principal,
160 &m->primary_principal);
163 static int
164 mcc_close_internal(krb5_mcache *m)
166 if (--m->refcnt != 0)
167 return 0;
169 if (MISDEAD(m)) {
170 free (m->name);
171 return 1;
173 return 0;
176 static krb5_error_code
177 mcc_close(krb5_context context,
178 krb5_ccache id)
180 if (mcc_close_internal(MCACHE(id)))
181 krb5_data_free(&id->data);
182 return 0;
185 static krb5_error_code
186 mcc_destroy(krb5_context context,
187 krb5_ccache id)
189 krb5_mcache **n, *m = MCACHE(id);
190 struct link *l;
192 if (m->refcnt == 0)
193 krb5_abortx(context, "mcc_destroy: refcnt already 0");
195 if (!MISDEAD(m)) {
196 /* if this is an active mcache, remove it from the linked
197 list, and free all data */
198 HEIMDAL_MUTEX_lock(&mcc_mutex);
199 for(n = &mcc_head; n && *n; n = &(*n)->next) {
200 if(m == *n) {
201 *n = m->next;
202 break;
205 HEIMDAL_MUTEX_unlock(&mcc_mutex);
206 if (m->primary_principal != NULL) {
207 krb5_free_principal (context, m->primary_principal);
208 m->primary_principal = NULL;
210 m->dead = 1;
212 l = m->creds;
213 while (l != NULL) {
214 struct link *old;
216 krb5_free_cred_contents (context, &l->cred);
217 old = l;
218 l = l->next;
219 free (old);
221 m->creds = NULL;
223 return 0;
226 static krb5_error_code
227 mcc_store_cred(krb5_context context,
228 krb5_ccache id,
229 krb5_creds *creds)
231 krb5_mcache *m = MCACHE(id);
232 krb5_error_code ret;
233 struct link *l;
235 if (MISDEAD(m))
236 return ENOENT;
238 l = malloc (sizeof(*l));
239 if (l == NULL) {
240 krb5_set_error_string (context, "malloc: out of memory");
241 return KRB5_CC_NOMEM;
243 l->next = m->creds;
244 m->creds = l;
245 memset (&l->cred, 0, sizeof(l->cred));
246 ret = krb5_copy_creds_contents (context, creds, &l->cred);
247 if (ret) {
248 m->creds = l->next;
249 free (l);
250 return ret;
252 return 0;
255 static krb5_error_code
256 mcc_get_principal(krb5_context context,
257 krb5_ccache id,
258 krb5_principal *principal)
260 krb5_mcache *m = MCACHE(id);
262 if (MISDEAD(m) || m->primary_principal == NULL)
263 return ENOENT;
264 return krb5_copy_principal (context,
265 m->primary_principal,
266 principal);
269 static krb5_error_code
270 mcc_get_first (krb5_context context,
271 krb5_ccache id,
272 krb5_cc_cursor *cursor)
274 krb5_mcache *m = MCACHE(id);
276 if (MISDEAD(m))
277 return ENOENT;
279 *cursor = m->creds;
280 return 0;
283 static krb5_error_code
284 mcc_get_next (krb5_context context,
285 krb5_ccache id,
286 krb5_cc_cursor *cursor,
287 krb5_creds *creds)
289 krb5_mcache *m = MCACHE(id);
290 struct link *l;
292 if (MISDEAD(m))
293 return ENOENT;
295 l = *cursor;
296 if (l != NULL) {
297 *cursor = l->next;
298 return krb5_copy_creds_contents (context,
299 &l->cred,
300 creds);
301 } else
302 return KRB5_CC_END;
305 static krb5_error_code
306 mcc_end_get (krb5_context context,
307 krb5_ccache id,
308 krb5_cc_cursor *cursor)
310 return 0;
313 static krb5_error_code
314 mcc_remove_cred(krb5_context context,
315 krb5_ccache id,
316 krb5_flags which,
317 krb5_creds *mcreds)
319 krb5_mcache *m = MCACHE(id);
320 struct link **q, *p;
321 for(q = &m->creds, p = *q; p; p = *q) {
322 if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
323 *q = p->next;
324 krb5_free_cred_contents(context, &p->cred);
325 free(p);
326 } else
327 q = &p->next;
329 return 0;
332 static krb5_error_code
333 mcc_set_flags(krb5_context context,
334 krb5_ccache id,
335 krb5_flags flags)
337 return 0; /* XXX */
340 struct mcache_iter {
341 krb5_mcache *cache;
344 static krb5_error_code
345 mcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
347 struct mcache_iter *iter;
349 iter = calloc(1, sizeof(*iter));
350 if (iter == NULL) {
351 krb5_set_error_string(context, "malloc - out of memory");
352 return ENOMEM;
355 HEIMDAL_MUTEX_lock(&mcc_mutex);
356 iter->cache = mcc_head;
357 if (iter->cache)
358 iter->cache->refcnt++;
359 HEIMDAL_MUTEX_unlock(&mcc_mutex);
361 *cursor = iter;
362 return 0;
365 static krb5_error_code
366 mcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
368 struct mcache_iter *iter = cursor;
369 krb5_error_code ret;
370 krb5_mcache *m;
372 if (iter->cache == NULL)
373 return KRB5_CC_END;
375 HEIMDAL_MUTEX_lock(&mcc_mutex);
376 m = iter->cache;
377 if (m->next)
378 m->next->refcnt++;
379 iter->cache = m->next;
380 HEIMDAL_MUTEX_unlock(&mcc_mutex);
382 ret = _krb5_cc_allocate(context, &krb5_mcc_ops, id);
383 if (ret)
384 return ret;
386 (*id)->data.data = m;
387 (*id)->data.length = sizeof(*m);
389 return 0;
392 static krb5_error_code
393 mcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
395 struct mcache_iter *iter = cursor;
397 if (iter->cache)
398 mcc_close_internal(iter->cache);
399 iter->cache = NULL;
400 free(iter);
401 return 0;
404 static krb5_error_code
405 mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
407 krb5_mcache *mfrom = MCACHE(from), *mto = MCACHE(to);
408 struct link *creds;
409 krb5_principal principal;
410 krb5_mcache **n;
412 HEIMDAL_MUTEX_lock(&mcc_mutex);
414 /* drop the from cache from the linked list to avoid lookups */
415 for(n = &mcc_head; n && *n; n = &(*n)->next) {
416 if(mfrom == *n) {
417 *n = mfrom->next;
418 break;
422 /* swap creds */
423 creds = mto->creds;
424 mto->creds = mfrom->creds;
425 mfrom->creds = creds;
426 /* swap principal */
427 principal = mto->primary_principal;
428 mto->primary_principal = mfrom->primary_principal;
429 mfrom->primary_principal = principal;
431 HEIMDAL_MUTEX_unlock(&mcc_mutex);
432 mcc_destroy(context, from);
434 return 0;
437 static krb5_error_code
438 mcc_default_name(krb5_context context, char **str)
440 *str = strdup("MEMORY:");
441 if (*str == NULL) {
442 krb5_set_error_string(context, "out of memory");
443 return ENOMEM;
445 return 0;
450 * Variable containing the MEMORY based credential cache implemention.
452 * @ingroup krb5_ccache
455 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = {
456 KRB5_CC_OPS_VERSION,
457 "MEMORY",
458 mcc_get_name,
459 mcc_resolve,
460 mcc_gen_new,
461 mcc_initialize,
462 mcc_destroy,
463 mcc_close,
464 mcc_store_cred,
465 NULL, /* mcc_retrieve */
466 mcc_get_principal,
467 mcc_get_first,
468 mcc_get_next,
469 mcc_end_get,
470 mcc_remove_cred,
471 mcc_set_flags,
472 NULL,
473 mcc_get_cache_first,
474 mcc_get_cache_next,
475 mcc_end_cache_get,
476 mcc_move,
477 mcc_default_name