source: branches/samba-3.5.x/source4/heimdal/lib/krb5/mcache.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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