No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / mcache.c
blobaff2845f44a615f71eae10c5ffb912faddb03c9f
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("$Heimdal: mcache.c 22107 2007-12-03 17:22:51Z lha $"
37 "$NetBSD$");
39 typedef struct krb5_mcache {
40 char *name;
41 unsigned int refcnt;
42 int dead;
43 krb5_principal primary_principal;
44 struct link {
45 krb5_creds cred;
46 struct link *next;
47 } *creds;
48 struct krb5_mcache *next;
49 } krb5_mcache;
51 static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
52 static struct krb5_mcache *mcc_head;
54 #define MCACHE(X) ((krb5_mcache *)(X)->data.data)
56 #define MISDEAD(X) ((X)->dead)
58 static const char*
59 mcc_get_name(krb5_context context,
60 krb5_ccache id)
62 return MCACHE(id)->name;
65 static krb5_mcache *
66 mcc_alloc(const char *name)
68 krb5_mcache *m, *m_c;
70 ALLOC(m, 1);
71 if(m == NULL)
72 return NULL;
73 if(name == NULL)
74 asprintf(&m->name, "%p", m);
75 else
76 m->name = strdup(name);
77 if(m->name == NULL) {
78 free(m);
79 return NULL;
81 /* check for dups first */
82 HEIMDAL_MUTEX_lock(&mcc_mutex);
83 for (m_c = mcc_head; m_c != NULL; m_c = m_c->next)
84 if (strcmp(m->name, m_c->name) == 0)
85 break;
86 if (m_c) {
87 free(m->name);
88 free(m);
89 HEIMDAL_MUTEX_unlock(&mcc_mutex);
90 return NULL;
93 m->dead = 0;
94 m->refcnt = 1;
95 m->primary_principal = NULL;
96 m->creds = NULL;
97 m->next = mcc_head;
98 mcc_head = m;
99 HEIMDAL_MUTEX_unlock(&mcc_mutex);
100 return m;
103 static krb5_error_code
104 mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
106 krb5_mcache *m;
108 HEIMDAL_MUTEX_lock(&mcc_mutex);
109 for (m = mcc_head; m != NULL; m = m->next)
110 if (strcmp(m->name, res) == 0)
111 break;
112 HEIMDAL_MUTEX_unlock(&mcc_mutex);
114 if (m != NULL) {
115 m->refcnt++;
116 (*id)->data.data = m;
117 (*id)->data.length = sizeof(*m);
118 return 0;
121 m = mcc_alloc(res);
122 if (m == NULL) {
123 krb5_set_error_string (context, "malloc: out of memory");
124 return KRB5_CC_NOMEM;
127 (*id)->data.data = m;
128 (*id)->data.length = sizeof(*m);
130 return 0;
134 static krb5_error_code
135 mcc_gen_new(krb5_context context, krb5_ccache *id)
137 krb5_mcache *m;
139 m = mcc_alloc(NULL);
141 if (m == NULL) {
142 krb5_set_error_string (context, "malloc: out of memory");
143 return KRB5_CC_NOMEM;
146 (*id)->data.data = m;
147 (*id)->data.length = sizeof(*m);
149 return 0;
152 static krb5_error_code
153 mcc_initialize(krb5_context context,
154 krb5_ccache id,
155 krb5_principal primary_principal)
157 krb5_mcache *m = MCACHE(id);
158 m->dead = 0;
159 return krb5_copy_principal (context,
160 primary_principal,
161 &m->primary_principal);
164 static int
165 mcc_close_internal(krb5_mcache *m)
167 if (--m->refcnt != 0)
168 return 0;
170 if (MISDEAD(m)) {
171 free (m->name);
172 return 1;
174 return 0;
177 static krb5_error_code
178 mcc_close(krb5_context context,
179 krb5_ccache id)
181 if (mcc_close_internal(MCACHE(id)))
182 krb5_data_free(&id->data);
183 return 0;
186 static krb5_error_code
187 mcc_destroy(krb5_context context,
188 krb5_ccache id)
190 krb5_mcache **n, *m = MCACHE(id);
191 struct link *l;
193 if (m->refcnt == 0)
194 krb5_abortx(context, "mcc_destroy: refcnt already 0");
196 if (!MISDEAD(m)) {
197 /* if this is an active mcache, remove it from the linked
198 list, and free all data */
199 HEIMDAL_MUTEX_lock(&mcc_mutex);
200 for(n = &mcc_head; n && *n; n = &(*n)->next) {
201 if(m == *n) {
202 *n = m->next;
203 break;
206 HEIMDAL_MUTEX_unlock(&mcc_mutex);
207 if (m->primary_principal != NULL) {
208 krb5_free_principal (context, m->primary_principal);
209 m->primary_principal = NULL;
211 m->dead = 1;
213 l = m->creds;
214 while (l != NULL) {
215 struct link *old;
217 krb5_free_cred_contents (context, &l->cred);
218 old = l;
219 l = l->next;
220 free (old);
222 m->creds = NULL;
224 return 0;
227 static krb5_error_code
228 mcc_store_cred(krb5_context context,
229 krb5_ccache id,
230 krb5_creds *creds)
232 krb5_mcache *m = MCACHE(id);
233 krb5_error_code ret;
234 struct link *l;
236 if (MISDEAD(m))
237 return ENOENT;
239 l = malloc (sizeof(*l));
240 if (l == NULL) {
241 krb5_set_error_string (context, "malloc: out of memory");
242 return KRB5_CC_NOMEM;
244 l->next = m->creds;
245 m->creds = l;
246 memset (&l->cred, 0, sizeof(l->cred));
247 ret = krb5_copy_creds_contents (context, creds, &l->cred);
248 if (ret) {
249 m->creds = l->next;
250 free (l);
251 return ret;
253 return 0;
256 static krb5_error_code
257 mcc_get_principal(krb5_context context,
258 krb5_ccache id,
259 krb5_principal *principal)
261 krb5_mcache *m = MCACHE(id);
263 if (MISDEAD(m) || m->primary_principal == NULL)
264 return ENOENT;
265 return krb5_copy_principal (context,
266 m->primary_principal,
267 principal);
270 static krb5_error_code
271 mcc_get_first (krb5_context context,
272 krb5_ccache id,
273 krb5_cc_cursor *cursor)
275 krb5_mcache *m = MCACHE(id);
277 if (MISDEAD(m))
278 return ENOENT;
280 *cursor = m->creds;
281 return 0;
284 static krb5_error_code
285 mcc_get_next (krb5_context context,
286 krb5_ccache id,
287 krb5_cc_cursor *cursor,
288 krb5_creds *creds)
290 krb5_mcache *m = MCACHE(id);
291 struct link *l;
293 if (MISDEAD(m))
294 return ENOENT;
296 l = *cursor;
297 if (l != NULL) {
298 *cursor = l->next;
299 return krb5_copy_creds_contents (context,
300 &l->cred,
301 creds);
302 } else
303 return KRB5_CC_END;
306 static krb5_error_code
307 mcc_end_get (krb5_context context,
308 krb5_ccache id,
309 krb5_cc_cursor *cursor)
311 return 0;
314 static krb5_error_code
315 mcc_remove_cred(krb5_context context,
316 krb5_ccache id,
317 krb5_flags which,
318 krb5_creds *mcreds)
320 krb5_mcache *m = MCACHE(id);
321 struct link **q, *p;
322 for(q = &m->creds, p = *q; p; p = *q) {
323 if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
324 *q = p->next;
325 krb5_free_cred_contents(context, &p->cred);
326 free(p);
327 } else
328 q = &p->next;
330 return 0;
333 static krb5_error_code
334 mcc_set_flags(krb5_context context,
335 krb5_ccache id,
336 krb5_flags flags)
338 return 0; /* XXX */
341 struct mcache_iter {
342 krb5_mcache *cache;
345 static krb5_error_code
346 mcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
348 struct mcache_iter *iter;
350 iter = calloc(1, sizeof(*iter));
351 if (iter == NULL) {
352 krb5_set_error_string(context, "malloc - out of memory");
353 return ENOMEM;
356 HEIMDAL_MUTEX_lock(&mcc_mutex);
357 iter->cache = mcc_head;
358 if (iter->cache)
359 iter->cache->refcnt++;
360 HEIMDAL_MUTEX_unlock(&mcc_mutex);
362 *cursor = iter;
363 return 0;
366 static krb5_error_code
367 mcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
369 struct mcache_iter *iter = cursor;
370 krb5_error_code ret;
371 krb5_mcache *m;
373 if (iter->cache == NULL)
374 return KRB5_CC_END;
376 HEIMDAL_MUTEX_lock(&mcc_mutex);
377 m = iter->cache;
378 if (m->next)
379 m->next->refcnt++;
380 iter->cache = m->next;
381 HEIMDAL_MUTEX_unlock(&mcc_mutex);
383 ret = _krb5_cc_allocate(context, &krb5_mcc_ops, id);
384 if (ret)
385 return ret;
387 (*id)->data.data = m;
388 (*id)->data.length = sizeof(*m);
390 return 0;
393 static krb5_error_code
394 mcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
396 struct mcache_iter *iter = cursor;
398 if (iter->cache)
399 mcc_close_internal(iter->cache);
400 iter->cache = NULL;
401 free(iter);
402 return 0;
405 static krb5_error_code
406 mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
408 krb5_mcache *mfrom = MCACHE(from), *mto = MCACHE(to);
409 struct link *creds;
410 krb5_principal principal;
411 krb5_mcache **n;
413 HEIMDAL_MUTEX_lock(&mcc_mutex);
415 /* drop the from cache from the linked list to avoid lookups */
416 for(n = &mcc_head; n && *n; n = &(*n)->next) {
417 if(mfrom == *n) {
418 *n = mfrom->next;
419 break;
423 /* swap creds */
424 creds = mto->creds;
425 mto->creds = mfrom->creds;
426 mfrom->creds = creds;
427 /* swap principal */
428 principal = mto->primary_principal;
429 mto->primary_principal = mfrom->primary_principal;
430 mfrom->primary_principal = principal;
432 HEIMDAL_MUTEX_unlock(&mcc_mutex);
433 mcc_destroy(context, from);
435 return 0;
438 static krb5_error_code
439 mcc_default_name(krb5_context context, char **str)
441 *str = strdup("MEMORY:");
442 if (*str == NULL) {
443 krb5_set_error_string(context, "out of memory");
444 return ENOMEM;
446 return 0;
451 * Variable containing the MEMORY based credential cache implemention.
453 * @ingroup krb5_ccache
456 const krb5_cc_ops krb5_mcc_ops = {
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