~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/mcache.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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,
 
60
             krb5_ccache id)
 
61
{
 
62
    return MCACHE(id)->name;
 
63
}
 
64
 
 
65
static krb5_mcache *
 
66
mcc_alloc(const char *name)
 
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)
 
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)
 
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,
 
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)
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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)
 
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)
 
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)
 
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)
 
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)
 
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)
 
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
};