/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- mcc_get_name
- mcc_alloc
- mcc_resolve
- mcc_gen_new
- mcc_initialize
- mcc_close_internal
- mcc_close
- mcc_destroy
- mcc_store_cred
- mcc_get_principal
- mcc_get_first
- mcc_get_next
- mcc_end_get
- mcc_remove_cred
- mcc_set_flags
- mcc_get_cache_first
- mcc_get_cache_next
- mcc_end_cache_get
- mcc_move
- mcc_default_name
- mcc_lastchange
1 /*
2 * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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.
32 */
33
34 #include "krb5_locl.h"
35
36 RCSID("$Id$");
37
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 time_t mtime;
49 } krb5_mcache;
50
51 static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
52 static struct krb5_mcache *mcc_head;
53
54 #define MCACHE(X) ((krb5_mcache *)(X)->data.data)
55
56 #define MISDEAD(X) ((X)->dead)
57
58 static const char*
59 mcc_get_name(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
60 krb5_ccache id)
61 {
62 return MCACHE(id)->name;
63 }
64
65 static krb5_mcache *
66 mcc_alloc(const char *name)
/* [<][>][^][v][top][bottom][index][help] */
67 {
68 krb5_mcache *m, *m_c;
69
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;
80 }
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;
91 }
92
93 m->dead = 0;
94 m->refcnt = 1;
95 m->primary_principal = NULL;
96 m->creds = NULL;
97 m->mtime = time(NULL);
98 m->next = mcc_head;
99 mcc_head = m;
100 HEIMDAL_MUTEX_unlock(&mcc_mutex);
101 return m;
102 }
103
104 static krb5_error_code
105 mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
/* [<][>][^][v][top][bottom][index][help] */
106 {
107 krb5_mcache *m;
108
109 HEIMDAL_MUTEX_lock(&mcc_mutex);
110 for (m = mcc_head; m != NULL; m = m->next)
111 if (strcmp(m->name, res) == 0)
112 break;
113 HEIMDAL_MUTEX_unlock(&mcc_mutex);
114
115 if (m != NULL) {
116 m->refcnt++;
117 (*id)->data.data = m;
118 (*id)->data.length = sizeof(*m);
119 return 0;
120 }
121
122 m = mcc_alloc(res);
123 if (m == NULL) {
124 krb5_set_error_message(context, KRB5_CC_NOMEM,
125 N_("malloc: out of memory", ""));
126 return KRB5_CC_NOMEM;
127 }
128
129 (*id)->data.data = m;
130 (*id)->data.length = sizeof(*m);
131
132 return 0;
133 }
134
135
136 static krb5_error_code
137 mcc_gen_new(krb5_context context, krb5_ccache *id)
/* [<][>][^][v][top][bottom][index][help] */
138 {
139 krb5_mcache *m;
140
141 m = mcc_alloc(NULL);
142
143 if (m == NULL) {
144 krb5_set_error_message(context, KRB5_CC_NOMEM,
145 N_("malloc: out of memory", ""));
146 return KRB5_CC_NOMEM;
147 }
148
149 (*id)->data.data = m;
150 (*id)->data.length = sizeof(*m);
151
152 return 0;
153 }
154
155 static krb5_error_code
156 mcc_initialize(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
157 krb5_ccache id,
158 krb5_principal primary_principal)
159 {
160 krb5_mcache *m = MCACHE(id);
161 m->dead = 0;
162 m->mtime = time(NULL);
163 return krb5_copy_principal (context,
164 primary_principal,
165 &m->primary_principal);
166 }
167
168 static int
169 mcc_close_internal(krb5_mcache *m)
/* [<][>][^][v][top][bottom][index][help] */
170 {
171 if (--m->refcnt != 0)
172 return 0;
173
174 if (MISDEAD(m)) {
175 free (m->name);
176 return 1;
177 }
178 return 0;
179 }
180
181 static krb5_error_code
182 mcc_close(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
183 krb5_ccache id)
184 {
185 if (mcc_close_internal(MCACHE(id)))
186 krb5_data_free(&id->data);
187 return 0;
188 }
189
190 static krb5_error_code
191 mcc_destroy(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
192 krb5_ccache id)
193 {
194 krb5_mcache **n, *m = MCACHE(id);
195 struct link *l;
196
197 if (m->refcnt == 0)
198 krb5_abortx(context, "mcc_destroy: refcnt already 0");
199
200 if (!MISDEAD(m)) {
201 /* if this is an active mcache, remove it from the linked
202 list, and free all data */
203 HEIMDAL_MUTEX_lock(&mcc_mutex);
204 for(n = &mcc_head; n && *n; n = &(*n)->next) {
205 if(m == *n) {
206 *n = m->next;
207 break;
208 }
209 }
210 HEIMDAL_MUTEX_unlock(&mcc_mutex);
211 if (m->primary_principal != NULL) {
212 krb5_free_principal (context, m->primary_principal);
213 m->primary_principal = NULL;
214 }
215 m->dead = 1;
216
217 l = m->creds;
218 while (l != NULL) {
219 struct link *old;
220
221 krb5_free_cred_contents (context, &l->cred);
222 old = l;
223 l = l->next;
224 free (old);
225 }
226 m->creds = NULL;
227 }
228 return 0;
229 }
230
231 static krb5_error_code
232 mcc_store_cred(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
233 krb5_ccache id,
234 krb5_creds *creds)
235 {
236 krb5_mcache *m = MCACHE(id);
237 krb5_error_code ret;
238 struct link *l;
239
240 if (MISDEAD(m))
241 return ENOENT;
242
243 l = malloc (sizeof(*l));
244 if (l == NULL) {
245 krb5_set_error_message(context, KRB5_CC_NOMEM,
246 N_("malloc: out of memory", ""));
247 return KRB5_CC_NOMEM;
248 }
249 l->next = m->creds;
250 m->creds = l;
251 memset (&l->cred, 0, sizeof(l->cred));
252 ret = krb5_copy_creds_contents (context, creds, &l->cred);
253 if (ret) {
254 m->creds = l->next;
255 free (l);
256 return ret;
257 }
258 m->mtime = time(NULL);
259 return 0;
260 }
261
262 static krb5_error_code
263 mcc_get_principal(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
264 krb5_ccache id,
265 krb5_principal *principal)
266 {
267 krb5_mcache *m = MCACHE(id);
268
269 if (MISDEAD(m) || m->primary_principal == NULL)
270 return ENOENT;
271 return krb5_copy_principal (context,
272 m->primary_principal,
273 principal);
274 }
275
276 static krb5_error_code
277 mcc_get_first (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
278 krb5_ccache id,
279 krb5_cc_cursor *cursor)
280 {
281 krb5_mcache *m = MCACHE(id);
282
283 if (MISDEAD(m))
284 return ENOENT;
285
286 *cursor = m->creds;
287 return 0;
288 }
289
290 static krb5_error_code
291 mcc_get_next (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
292 krb5_ccache id,
293 krb5_cc_cursor *cursor,
294 krb5_creds *creds)
295 {
296 krb5_mcache *m = MCACHE(id);
297 struct link *l;
298
299 if (MISDEAD(m))
300 return ENOENT;
301
302 l = *cursor;
303 if (l != NULL) {
304 *cursor = l->next;
305 return krb5_copy_creds_contents (context,
306 &l->cred,
307 creds);
308 } else
309 return KRB5_CC_END;
310 }
311
312 static krb5_error_code
313 mcc_end_get (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
314 krb5_ccache id,
315 krb5_cc_cursor *cursor)
316 {
317 return 0;
318 }
319
320 static krb5_error_code
321 mcc_remove_cred(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
322 krb5_ccache id,
323 krb5_flags which,
324 krb5_creds *mcreds)
325 {
326 krb5_mcache *m = MCACHE(id);
327 struct link **q, *p;
328 for(q = &m->creds, p = *q; p; p = *q) {
329 if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
330 *q = p->next;
331 krb5_free_cred_contents(context, &p->cred);
332 free(p);
333 m->mtime = time(NULL);
334 } else
335 q = &p->next;
336 }
337 return 0;
338 }
339
340 static krb5_error_code
341 mcc_set_flags(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
342 krb5_ccache id,
343 krb5_flags flags)
344 {
345 return 0; /* XXX */
346 }
347
348 struct mcache_iter {
349 krb5_mcache *cache;
350 };
351
352 static krb5_error_code
353 mcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
/* [<][>][^][v][top][bottom][index][help] */
354 {
355 struct mcache_iter *iter;
356
357 iter = calloc(1, sizeof(*iter));
358 if (iter == NULL) {
359 krb5_set_error_message(context, ENOMEM,
360 N_("malloc: out of memory", ""));
361 return ENOMEM;
362 }
363
364 HEIMDAL_MUTEX_lock(&mcc_mutex);
365 iter->cache = mcc_head;
366 if (iter->cache)
367 iter->cache->refcnt++;
368 HEIMDAL_MUTEX_unlock(&mcc_mutex);
369
370 *cursor = iter;
371 return 0;
372 }
373
374 static krb5_error_code
375 mcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
/* [<][>][^][v][top][bottom][index][help] */
376 {
377 struct mcache_iter *iter = cursor;
378 krb5_error_code ret;
379 krb5_mcache *m;
380
381 if (iter->cache == NULL)
382 return KRB5_CC_END;
383
384 HEIMDAL_MUTEX_lock(&mcc_mutex);
385 m = iter->cache;
386 if (m->next)
387 m->next->refcnt++;
388 iter->cache = m->next;
389 HEIMDAL_MUTEX_unlock(&mcc_mutex);
390
391 ret = _krb5_cc_allocate(context, &krb5_mcc_ops, id);
392 if (ret)
393 return ret;
394
395 (*id)->data.data = m;
396 (*id)->data.length = sizeof(*m);
397
398 return 0;
399 }
400
401 static krb5_error_code
402 mcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
/* [<][>][^][v][top][bottom][index][help] */
403 {
404 struct mcache_iter *iter = cursor;
405
406 if (iter->cache)
407 mcc_close_internal(iter->cache);
408 iter->cache = NULL;
409 free(iter);
410 return 0;
411 }
412
413 static krb5_error_code
414 mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
/* [<][>][^][v][top][bottom][index][help] */
415 {
416 krb5_mcache *mfrom = MCACHE(from), *mto = MCACHE(to);
417 struct link *creds;
418 krb5_principal principal;
419 krb5_mcache **n;
420
421 HEIMDAL_MUTEX_lock(&mcc_mutex);
422
423 /* drop the from cache from the linked list to avoid lookups */
424 for(n = &mcc_head; n && *n; n = &(*n)->next) {
425 if(mfrom == *n) {
426 *n = mfrom->next;
427 break;
428 }
429 }
430
431 /* swap creds */
432 creds = mto->creds;
433 mto->creds = mfrom->creds;
434 mfrom->creds = creds;
435 /* swap principal */
436 principal = mto->primary_principal;
437 mto->primary_principal = mfrom->primary_principal;
438 mfrom->primary_principal = principal;
439
440 mto->mtime = mfrom->mtime = time(NULL);
441
442 HEIMDAL_MUTEX_unlock(&mcc_mutex);
443 mcc_destroy(context, from);
444
445 return 0;
446 }
447
448 static krb5_error_code
449 mcc_default_name(krb5_context context, char **str)
/* [<][>][^][v][top][bottom][index][help] */
450 {
451 *str = strdup("MEMORY:");
452 if (*str == NULL) {
453 krb5_set_error_message(context, ENOMEM,
454 N_("malloc: out of memory", ""));
455 return ENOMEM;
456 }
457 return 0;
458 }
459
460 static krb5_error_code
461 mcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
/* [<][>][^][v][top][bottom][index][help] */
462 {
463 *mtime = MCACHE(id)->mtime;
464 return 0;
465 }
466
467
468 /**
469 * Variable containing the MEMORY based credential cache implemention.
470 *
471 * @ingroup krb5_ccache
472 */
473
474 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = {
475 KRB5_CC_OPS_VERSION,
476 "MEMORY",
477 mcc_get_name,
478 mcc_resolve,
479 mcc_gen_new,
480 mcc_initialize,
481 mcc_destroy,
482 mcc_close,
483 mcc_store_cred,
484 NULL, /* mcc_retrieve */
485 mcc_get_principal,
486 mcc_get_first,
487 mcc_get_next,
488 mcc_end_get,
489 mcc_remove_cred,
490 mcc_set_flags,
491 NULL,
492 mcc_get_cache_first,
493 mcc_get_cache_next,
494 mcc_end_cache_get,
495 mcc_move,
496 mcc_default_name,
497 NULL,
498 mcc_lastchange
499 };