~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/acache.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) 2004 - 2007 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
#include <krb5_ccapi.h>
 
36
#ifdef HAVE_DLFCN_H
 
37
#include <dlfcn.h>
 
38
#endif
 
39
 
 
40
RCSID("$Id$");
 
41
 
 
42
/* XXX should we fetch these for each open ? */
 
43
static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER;
 
44
static cc_initialize_func init_func;
 
45
 
 
46
#ifdef HAVE_DLOPEN
 
47
static void *cc_handle;
 
48
#endif
 
49
 
 
50
typedef struct krb5_acc {
 
51
    char *cache_name;
 
52
    cc_context_t context;
 
53
    cc_ccache_t ccache;
 
54
} krb5_acc;
 
55
 
 
56
static krb5_error_code acc_close(krb5_context, krb5_ccache);
 
57
 
 
58
#define ACACHE(X) ((krb5_acc *)(X)->data.data)
 
59
 
 
60
static const struct {
 
61
    cc_int32 error;
 
62
    krb5_error_code ret;
 
63
} cc_errors[] = {
 
64
    { ccErrBadName,             KRB5_CC_BADNAME },
 
65
    { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
 
66
    { ccErrCCacheNotFound,      KRB5_FCC_NOFILE },
 
67
    { ccErrContextNotFound,     KRB5_CC_NOTFOUND },
 
68
    { ccIteratorEnd,            KRB5_CC_END },
 
69
    { ccErrNoMem,               KRB5_CC_NOMEM },
 
70
    { ccErrServerUnavailable,   KRB5_CC_NOSUPP },
 
71
    { ccErrInvalidCCache,       KRB5_CC_BADNAME },
 
72
    { ccNoError,                0 }
 
73
};
 
74
 
 
75
static krb5_error_code
 
76
translate_cc_error(krb5_context context, cc_int32 error)
 
77
{
 
78
    int i;
 
79
    krb5_clear_error_message(context);
 
80
    for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++)
 
81
        if (cc_errors[i].error == error)
 
82
            return cc_errors[i].ret;
 
83
    return KRB5_FCC_INTERNAL;
 
84
}
 
85
 
 
86
static krb5_error_code
 
87
init_ccapi(krb5_context context)
 
88
{
 
89
    const char *lib;
 
90
 
 
91
    HEIMDAL_MUTEX_lock(&acc_mutex);
 
92
    if (init_func) {
 
93
        HEIMDAL_MUTEX_unlock(&acc_mutex);
 
94
        krb5_clear_error_message(context);
 
95
        return 0;
 
96
    }
 
97
 
 
98
    lib = krb5_config_get_string(context, NULL,
 
99
                                 "libdefaults", "ccapi_library",
 
100
                                 NULL);
 
101
    if (lib == NULL) {
 
102
#ifdef __APPLE__
 
103
        lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos";
 
104
#else
 
105
        lib = "/usr/lib/libkrb5_cc.so";
 
106
#endif
 
107
    }
 
108
 
 
109
#ifdef HAVE_DLOPEN
 
110
 
 
111
#ifndef RTLD_LAZY
 
112
#define RTLD_LAZY 0
 
113
#endif
 
114
 
 
115
    cc_handle = dlopen(lib, RTLD_LAZY);
 
116
    if (cc_handle == NULL) {
 
117
        HEIMDAL_MUTEX_unlock(&acc_mutex);
 
118
        krb5_set_error_message(context, KRB5_CC_NOSUPP,
 
119
                               N_("Failed to load API cache module %s", "file"),
 
120
                               lib);
 
121
        return KRB5_CC_NOSUPP;
 
122
    }
 
123
 
 
124
    init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize");
 
125
    HEIMDAL_MUTEX_unlock(&acc_mutex);
 
126
    if (init_func == NULL) {
 
127
        krb5_set_error_message(context, KRB5_CC_NOSUPP,
 
128
                               N_("Failed to find cc_initialize"
 
129
                                 "in %s: %s", "file, error"), lib, dlerror());
 
130
        dlclose(cc_handle);
 
131
        return KRB5_CC_NOSUPP;
 
132
    }
 
133
 
 
134
    return 0;
 
135
#else
 
136
    HEIMDAL_MUTEX_unlock(&acc_mutex);
 
137
    krb5_set_error_message(context, KRB5_CC_NOSUPP,
 
138
                           N_("no support for shared object", "file, error"));
 
139
    return KRB5_CC_NOSUPP;
 
140
#endif
 
141
}
 
142
 
 
143
static krb5_error_code
 
144
make_cred_from_ccred(krb5_context context,
 
145
                     const cc_credentials_v5_t *incred,
 
146
                     krb5_creds *cred)
 
147
{
 
148
    krb5_error_code ret;
 
149
    unsigned int i;
 
150
 
 
151
    memset(cred, 0, sizeof(*cred));
 
152
 
 
153
    ret = krb5_parse_name(context, incred->client, &cred->client);
 
154
    if (ret)
 
155
        goto fail;
 
156
 
 
157
    ret = krb5_parse_name(context, incred->server, &cred->server);
 
158
    if (ret)
 
159
        goto fail;
 
160
 
 
161
    cred->session.keytype = incred->keyblock.type;
 
162
    cred->session.keyvalue.length = incred->keyblock.length;
 
163
    cred->session.keyvalue.data = malloc(incred->keyblock.length);
 
164
    if (cred->session.keyvalue.data == NULL)
 
165
        goto nomem;
 
166
    memcpy(cred->session.keyvalue.data, incred->keyblock.data,
 
167
           incred->keyblock.length);
 
168
 
 
169
    cred->times.authtime = incred->authtime;
 
170
    cred->times.starttime = incred->starttime;
 
171
    cred->times.endtime = incred->endtime;
 
172
    cred->times.renew_till = incred->renew_till;
 
173
 
 
174
    ret = krb5_data_copy(&cred->ticket,
 
175
                         incred->ticket.data,
 
176
                         incred->ticket.length);
 
177
    if (ret)
 
178
        goto nomem;
 
179
 
 
180
    ret = krb5_data_copy(&cred->second_ticket,
 
181
                         incred->second_ticket.data,
 
182
                         incred->second_ticket.length);
 
183
    if (ret)
 
184
        goto nomem;
 
185
 
 
186
    cred->authdata.val = NULL;
 
187
    cred->authdata.len = 0;
 
188
 
 
189
    cred->addresses.val = NULL;
 
190
    cred->addresses.len = 0;
 
191
 
 
192
    for (i = 0; incred->authdata && incred->authdata[i]; i++)
 
193
        ;
 
194
 
 
195
    if (i) {
 
196
        cred->authdata.val = calloc(i, sizeof(cred->authdata.val[0]));
 
197
        if (cred->authdata.val == NULL)
 
198
            goto nomem;
 
199
        cred->authdata.len = i;
 
200
        for (i = 0; i < cred->authdata.len; i++) {
 
201
            cred->authdata.val[i].ad_type = incred->authdata[i]->type;
 
202
            ret = krb5_data_copy(&cred->authdata.val[i].ad_data,
 
203
                                 incred->authdata[i]->data,
 
204
                                 incred->authdata[i]->length);
 
205
            if (ret)
 
206
                goto nomem;
 
207
        }
 
208
    }
 
209
 
 
210
    for (i = 0; incred->addresses && incred->addresses[i]; i++)
 
211
        ;
 
212
 
 
213
    if (i) {
 
214
        cred->addresses.val = calloc(i, sizeof(cred->addresses.val[0]));
 
215
        if (cred->addresses.val == NULL)
 
216
            goto nomem;
 
217
        cred->addresses.len = i;
 
218
        
 
219
        for (i = 0; i < cred->addresses.len; i++) {
 
220
            cred->addresses.val[i].addr_type = incred->addresses[i]->type;
 
221
            ret = krb5_data_copy(&cred->addresses.val[i].address,
 
222
                                 incred->addresses[i]->data,
 
223
                                 incred->addresses[i]->length);
 
224
            if (ret)
 
225
                goto nomem;
 
226
        }
 
227
    }
 
228
 
 
229
    cred->flags.i = 0;
 
230
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDABLE)
 
231
        cred->flags.b.forwardable = 1;
 
232
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDED)
 
233
        cred->flags.b.forwarded = 1;
 
234
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXIABLE)
 
235
        cred->flags.b.proxiable = 1;
 
236
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXY)
 
237
        cred->flags.b.proxy = 1;
 
238
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_MAY_POSTDATE)
 
239
        cred->flags.b.may_postdate = 1;
 
240
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_POSTDATED)
 
241
        cred->flags.b.postdated = 1;
 
242
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INVALID)
 
243
        cred->flags.b.invalid = 1;
 
244
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_RENEWABLE)
 
245
        cred->flags.b.renewable = 1;
 
246
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INITIAL)
 
247
        cred->flags.b.initial = 1;
 
248
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PRE_AUTH)
 
249
        cred->flags.b.pre_authent = 1;
 
250
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_HW_AUTH)
 
251
        cred->flags.b.hw_authent = 1;
 
252
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED)
 
253
        cred->flags.b.transited_policy_checked = 1;
 
254
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE)
 
255
        cred->flags.b.ok_as_delegate = 1;
 
256
    if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_ANONYMOUS)
 
257
        cred->flags.b.anonymous = 1;
 
258
 
 
259
    return 0;
 
260
 
 
261
nomem:
 
262
    ret = ENOMEM;
 
263
    krb5_set_error_message(context, ret, N_("malloc: out of memory", "malloc"));
 
264
 
 
265
fail:
 
266
    krb5_free_cred_contents(context, cred);
 
267
    return ret;
 
268
}
 
269
 
 
270
static void
 
271
free_ccred(cc_credentials_v5_t *cred)
 
272
{
 
273
    int i;
 
274
 
 
275
    if (cred->addresses) {
 
276
        for (i = 0; cred->addresses[i] != 0; i++) {
 
277
            if (cred->addresses[i]->data)
 
278
                free(cred->addresses[i]->data);
 
279
            free(cred->addresses[i]);
 
280
        }
 
281
        free(cred->addresses);
 
282
    }
 
283
    if (cred->server)
 
284
        free(cred->server);
 
285
    if (cred->client)
 
286
        free(cred->client);
 
287
    memset(cred, 0, sizeof(*cred));
 
288
}
 
289
 
 
290
static krb5_error_code
 
291
make_ccred_from_cred(krb5_context context,
 
292
                     const krb5_creds *incred,
 
293
                     cc_credentials_v5_t *cred)
 
294
{
 
295
    krb5_error_code ret;
 
296
    int i;
 
297
 
 
298
    memset(cred, 0, sizeof(*cred));
 
299
 
 
300
    ret = krb5_unparse_name(context, incred->client, &cred->client);
 
301
    if (ret)
 
302
        goto fail;
 
303
 
 
304
    ret = krb5_unparse_name(context, incred->server, &cred->server);
 
305
    if (ret)
 
306
        goto fail;
 
307
 
 
308
    cred->keyblock.type = incred->session.keytype;
 
309
    cred->keyblock.length = incred->session.keyvalue.length;
 
310
    cred->keyblock.data = incred->session.keyvalue.data;
 
311
 
 
312
    cred->authtime = incred->times.authtime;
 
313
    cred->starttime = incred->times.starttime;
 
314
    cred->endtime = incred->times.endtime;
 
315
    cred->renew_till = incred->times.renew_till;
 
316
 
 
317
    cred->ticket.length = incred->ticket.length;
 
318
    cred->ticket.data = incred->ticket.data;
 
319
 
 
320
    cred->second_ticket.length = incred->second_ticket.length;
 
321
    cred->second_ticket.data = incred->second_ticket.data;
 
322
 
 
323
    /* XXX this one should also be filled in */
 
324
    cred->authdata = NULL;
 
325
 
 
326
    cred->addresses = calloc(incred->addresses.len + 1,
 
327
                             sizeof(cred->addresses[0]));
 
328
    if (cred->addresses == NULL) {
 
329
 
 
330
        ret = ENOMEM;
 
331
        goto fail;
 
332
    }
 
333
 
 
334
    for (i = 0; i < incred->addresses.len; i++) {
 
335
        cc_data *addr;
 
336
        addr = malloc(sizeof(*addr));
 
337
        if (addr == NULL) {
 
338
            ret = ENOMEM;
 
339
            goto fail;
 
340
        }
 
341
        addr->type = incred->addresses.val[i].addr_type;
 
342
        addr->length = incred->addresses.val[i].address.length;
 
343
        addr->data = malloc(addr->length);
 
344
        if (addr->data == NULL) {
 
345
            ret = ENOMEM;
 
346
            goto fail;
 
347
        }
 
348
        memcpy(addr->data, incred->addresses.val[i].address.data,
 
349
               addr->length);
 
350
        cred->addresses[i] = addr;
 
351
    }
 
352
    cred->addresses[i] = NULL;
 
353
 
 
354
    cred->ticket_flags = 0;
 
355
    if (incred->flags.b.forwardable)
 
356
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE;
 
357
    if (incred->flags.b.forwarded)
 
358
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED;
 
359
    if (incred->flags.b.proxiable)
 
360
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE;
 
361
    if (incred->flags.b.proxy)
 
362
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY;
 
363
    if (incred->flags.b.may_postdate)
 
364
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE;
 
365
    if (incred->flags.b.postdated)
 
366
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED;
 
367
    if (incred->flags.b.invalid)
 
368
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID;
 
369
    if (incred->flags.b.renewable)
 
370
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE;
 
371
    if (incred->flags.b.initial)
 
372
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL;
 
373
    if (incred->flags.b.pre_authent)
 
374
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH;
 
375
    if (incred->flags.b.hw_authent)
 
376
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH;
 
377
    if (incred->flags.b.transited_policy_checked)
 
378
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED;
 
379
    if (incred->flags.b.ok_as_delegate)
 
380
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE;
 
381
    if (incred->flags.b.anonymous)
 
382
        cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS;
 
383
 
 
384
    return 0;
 
385
 
 
386
fail:
 
387
    free_ccred(cred);
 
388
 
 
389
    krb5_clear_error_message(context);
 
390
    return ret;
 
391
}
 
392
 
 
393
static cc_int32
 
394
get_cc_name(krb5_acc *a)
 
395
{
 
396
    cc_string_t name;
 
397
    cc_int32 error;
 
398
 
 
399
    error = (*a->ccache->func->get_name)(a->ccache, &name);
 
400
    if (error)
 
401
        return error;
 
402
 
 
403
    a->cache_name = strdup(name->data);
 
404
    (*name->func->release)(name);
 
405
    if (a->cache_name == NULL)
 
406
        return ccErrNoMem;
 
407
    return ccNoError;
 
408
}
 
409
 
 
410
 
 
411
static const char*
 
412
acc_get_name(krb5_context context,
 
413
             krb5_ccache id)
 
414
{
 
415
    krb5_acc *a = ACACHE(id);
 
416
    int32_t error;
 
417
 
 
418
    if (a->cache_name == NULL) {
 
419
        krb5_error_code ret;
 
420
        krb5_principal principal;
 
421
        char *name;
 
422
 
 
423
        ret = _krb5_get_default_principal_local(context, &principal);
 
424
        if (ret)
 
425
            return NULL;
 
426
 
 
427
        ret = krb5_unparse_name(context, principal, &name);
 
428
        krb5_free_principal(context, principal);
 
429
        if (ret)
 
430
            return NULL;
 
431
 
 
432
        error = (*a->context->func->create_new_ccache)(a->context,
 
433
                                                       cc_credentials_v5,
 
434
                                                       name,
 
435
                                                       &a->ccache);
 
436
        krb5_xfree(name);
 
437
        if (error)
 
438
            return NULL;
 
439
 
 
440
        error = get_cc_name(a);
 
441
        if (error)
 
442
            return NULL;
 
443
    }
 
444
 
 
445
    return a->cache_name;
 
446
}
 
447
 
 
448
static krb5_error_code
 
449
acc_alloc(krb5_context context, krb5_ccache *id)
 
450
{
 
451
    krb5_error_code ret;
 
452
    cc_int32 error;
 
453
    krb5_acc *a;
 
454
 
 
455
    ret = init_ccapi(context);
 
456
    if (ret)
 
457
        return ret;
 
458
 
 
459
    ret = krb5_data_alloc(&(*id)->data, sizeof(*a));
 
460
    if (ret) {
 
461
        krb5_clear_error_message(context);
 
462
        return ret;
 
463
    }
 
464
 
 
465
    a = ACACHE(*id);
 
466
 
 
467
    error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
 
468
    if (error) {
 
469
        krb5_data_free(&(*id)->data);
 
470
        return translate_cc_error(context, error);
 
471
    }
 
472
 
 
473
    a->cache_name = NULL;
 
474
 
 
475
    return 0;
 
476
}
 
477
 
 
478
static krb5_error_code
 
479
acc_resolve(krb5_context context, krb5_ccache *id, const char *res)
 
480
{
 
481
    krb5_error_code ret;
 
482
    cc_int32 error;
 
483
    krb5_acc *a;
 
484
 
 
485
    ret = acc_alloc(context, id);
 
486
    if (ret)
 
487
        return ret;
 
488
 
 
489
    a = ACACHE(*id);
 
490
 
 
491
    error = (*a->context->func->open_ccache)(a->context, res, &a->ccache);
 
492
    if (error == ccNoError) {
 
493
        error = get_cc_name(a);
 
494
        if (error != ccNoError) {
 
495
            acc_close(context, *id);
 
496
            *id = NULL;
 
497
            return translate_cc_error(context, error);
 
498
        }
 
499
    } else if (error == ccErrCCacheNotFound) {
 
500
        a->ccache = NULL;
 
501
        a->cache_name = NULL;
 
502
        error = 0;
 
503
    } else {
 
504
        *id = NULL;
 
505
        return translate_cc_error(context, error);
 
506
    }
 
507
 
 
508
    return 0;
 
509
}
 
510
 
 
511
static krb5_error_code
 
512
acc_gen_new(krb5_context context, krb5_ccache *id)
 
513
{
 
514
    krb5_error_code ret;
 
515
    krb5_acc *a;
 
516
 
 
517
    ret = acc_alloc(context, id);
 
518
    if (ret)
 
519
        return ret;
 
520
 
 
521
    a = ACACHE(*id);
 
522
 
 
523
    a->ccache = NULL;
 
524
    a->cache_name = NULL;
 
525
 
 
526
    return 0;
 
527
}
 
528
 
 
529
static krb5_error_code
 
530
acc_initialize(krb5_context context,
 
531
               krb5_ccache id,
 
532
               krb5_principal primary_principal)
 
533
{
 
534
    krb5_acc *a = ACACHE(id);
 
535
    krb5_error_code ret;
 
536
    int32_t error;
 
537
    char *name;
 
538
 
 
539
    ret = krb5_unparse_name(context, primary_principal, &name);
 
540
    if (ret)
 
541
        return ret;
 
542
 
 
543
    if (a->cache_name == NULL) {
 
544
        error = (*a->context->func->create_new_ccache)(a->context,
 
545
                                                       cc_credentials_v5,
 
546
                                                       name,
 
547
                                                       &a->ccache);
 
548
        free(name);
 
549
        if (error == ccNoError)
 
550
            error = get_cc_name(a);
 
551
    } else {
 
552
        cc_credentials_iterator_t iter;
 
553
        cc_credentials_t ccred;
 
554
 
 
555
        error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
 
556
        if (error) {
 
557
            free(name);
 
558
            return translate_cc_error(context, error);
 
559
        }
 
560
 
 
561
        while (1) {
 
562
            error = (*iter->func->next)(iter, &ccred);
 
563
            if (error)
 
564
                break;
 
565
            (*a->ccache->func->remove_credentials)(a->ccache, ccred);
 
566
            (*ccred->func->release)(ccred);
 
567
        }
 
568
        (*iter->func->release)(iter);
 
569
 
 
570
        error = (*a->ccache->func->set_principal)(a->ccache,
 
571
                                                  cc_credentials_v5,
 
572
                                                  name);
 
573
    }
 
574
 
 
575
    return translate_cc_error(context, error);
 
576
}
 
577
 
 
578
static krb5_error_code
 
579
acc_close(krb5_context context,
 
580
          krb5_ccache id)
 
581
{
 
582
    krb5_acc *a = ACACHE(id);
 
583
 
 
584
    if (a->ccache) {
 
585
        (*a->ccache->func->release)(a->ccache);
 
586
        a->ccache = NULL;
 
587
    }
 
588
    if (a->cache_name) {
 
589
        free(a->cache_name);
 
590
        a->cache_name = NULL;
 
591
    }
 
592
    if (a->context) {
 
593
        (*a->context->func->release)(a->context);
 
594
        a->context = NULL;
 
595
    }
 
596
    krb5_data_free(&id->data);
 
597
    return 0;
 
598
}
 
599
 
 
600
static krb5_error_code
 
601
acc_destroy(krb5_context context,
 
602
            krb5_ccache id)
 
603
{
 
604
    krb5_acc *a = ACACHE(id);
 
605
    cc_int32 error = 0;
 
606
 
 
607
    if (a->ccache) {
 
608
        error = (*a->ccache->func->destroy)(a->ccache);
 
609
        a->ccache = NULL;
 
610
    }
 
611
    if (a->context) {
 
612
        error = (a->context->func->release)(a->context);
 
613
        a->context = NULL;
 
614
    }
 
615
    return translate_cc_error(context, error);
 
616
}
 
617
 
 
618
static krb5_error_code
 
619
acc_store_cred(krb5_context context,
 
620
               krb5_ccache id,
 
621
               krb5_creds *creds)
 
622
{
 
623
    krb5_acc *a = ACACHE(id);
 
624
    cc_credentials_union cred;
 
625
    cc_credentials_v5_t v5cred;
 
626
    krb5_error_code ret;
 
627
    cc_int32 error;
 
628
 
 
629
    if (a->ccache == NULL) {
 
630
        krb5_set_error_message(context, KRB5_CC_NOTFOUND,
 
631
                               N_("No API credential found", ""));
 
632
        return KRB5_CC_NOTFOUND;
 
633
    }
 
634
 
 
635
    cred.version = cc_credentials_v5;
 
636
    cred.credentials.credentials_v5 = &v5cred;
 
637
 
 
638
    ret = make_ccred_from_cred(context,
 
639
                               creds,
 
640
                               &v5cred);
 
641
    if (ret)
 
642
        return ret;
 
643
 
 
644
    error = (*a->ccache->func->store_credentials)(a->ccache, &cred);
 
645
    if (error)
 
646
        ret = translate_cc_error(context, error);
 
647
 
 
648
    free_ccred(&v5cred);
 
649
 
 
650
    return ret;
 
651
}
 
652
 
 
653
static krb5_error_code
 
654
acc_get_principal(krb5_context context,
 
655
                  krb5_ccache id,
 
656
                  krb5_principal *principal)
 
657
{
 
658
    krb5_acc *a = ACACHE(id);
 
659
    krb5_error_code ret;
 
660
    int32_t error;
 
661
    cc_string_t name;
 
662
 
 
663
    if (a->ccache == NULL) {
 
664
        krb5_set_error_message(context, KRB5_CC_NOTFOUND,
 
665
                               N_("No API credential found", ""));
 
666
        return KRB5_CC_NOTFOUND;
 
667
    }
 
668
 
 
669
    error = (*a->ccache->func->get_principal)(a->ccache,
 
670
                                              cc_credentials_v5,
 
671
                                              &name);
 
672
    if (error)
 
673
        return translate_cc_error(context, error);
 
674
 
 
675
    ret = krb5_parse_name(context, name->data, principal);
 
676
 
 
677
    (*name->func->release)(name);
 
678
    return ret;
 
679
}
 
680
 
 
681
static krb5_error_code
 
682
acc_get_first (krb5_context context,
 
683
               krb5_ccache id,
 
684
               krb5_cc_cursor *cursor)
 
685
{
 
686
    cc_credentials_iterator_t iter;
 
687
    krb5_acc *a = ACACHE(id);
 
688
    int32_t error;
 
689
 
 
690
    if (a->ccache == NULL) {
 
691
        krb5_set_error_message(context, KRB5_CC_NOTFOUND,
 
692
                               N_("No API credential found", ""));
 
693
        return KRB5_CC_NOTFOUND;
 
694
    }
 
695
 
 
696
    error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
 
697
    if (error) {
 
698
        krb5_clear_error_message(context);
 
699
        return ENOENT;
 
700
    }
 
701
    *cursor = iter;
 
702
    return 0;
 
703
}
 
704
 
 
705
 
 
706
static krb5_error_code
 
707
acc_get_next (krb5_context context,
 
708
              krb5_ccache id,
 
709
              krb5_cc_cursor *cursor,
 
710
              krb5_creds *creds)
 
711
{
 
712
    cc_credentials_iterator_t iter = *cursor;
 
713
    cc_credentials_t cred;
 
714
    krb5_error_code ret;
 
715
    int32_t error;
 
716
 
 
717
    while (1) {
 
718
        error = (*iter->func->next)(iter, &cred);
 
719
        if (error)
 
720
            return translate_cc_error(context, error);
 
721
        if (cred->data->version == cc_credentials_v5)
 
722
            break;
 
723
        (*cred->func->release)(cred);
 
724
    }
 
725
 
 
726
    ret = make_cred_from_ccred(context,
 
727
                               cred->data->credentials.credentials_v5,
 
728
                               creds);
 
729
    (*cred->func->release)(cred);
 
730
    return ret;
 
731
}
 
732
 
 
733
static krb5_error_code
 
734
acc_end_get (krb5_context context,
 
735
             krb5_ccache id,
 
736
             krb5_cc_cursor *cursor)
 
737
{
 
738
    cc_credentials_iterator_t iter = *cursor;
 
739
    (*iter->func->release)(iter);
 
740
    return 0;
 
741
}
 
742
 
 
743
static krb5_error_code
 
744
acc_remove_cred(krb5_context context,
 
745
                krb5_ccache id,
 
746
                krb5_flags which,
 
747
                krb5_creds *cred)
 
748
{
 
749
    cc_credentials_iterator_t iter;
 
750
    krb5_acc *a = ACACHE(id);
 
751
    cc_credentials_t ccred;
 
752
    krb5_error_code ret;
 
753
    cc_int32 error;
 
754
    char *client, *server;
 
755
 
 
756
    if (a->ccache == NULL) {
 
757
        krb5_set_error_message(context, KRB5_CC_NOTFOUND,
 
758
                               N_("No API credential found", ""));
 
759
        return KRB5_CC_NOTFOUND;
 
760
    }
 
761
 
 
762
    if (cred->client) {
 
763
        ret = krb5_unparse_name(context, cred->client, &client);
 
764
        if (ret)
 
765
            return ret;
 
766
    } else
 
767
        client = NULL;
 
768
 
 
769
    ret = krb5_unparse_name(context, cred->server, &server);
 
770
    if (ret) {
 
771
        free(client);
 
772
        return ret;
 
773
    }
 
774
 
 
775
    error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
 
776
    if (error) {
 
777
        free(server);
 
778
        free(client);
 
779
        return translate_cc_error(context, error);
 
780
    }
 
781
 
 
782
    ret = KRB5_CC_NOTFOUND;
 
783
    while (1) {
 
784
        cc_credentials_v5_t *v5cred;
 
785
 
 
786
        error = (*iter->func->next)(iter, &ccred);
 
787
        if (error)
 
788
            break;
 
789
 
 
790
        if (ccred->data->version != cc_credentials_v5)
 
791
            goto next;
 
792
 
 
793
        v5cred = ccred->data->credentials.credentials_v5;
 
794
 
 
795
        if (client && strcmp(v5cred->client, client) != 0)
 
796
            goto next;
 
797
 
 
798
        if (strcmp(v5cred->server, server) != 0)
 
799
            goto next;
 
800
 
 
801
        (*a->ccache->func->remove_credentials)(a->ccache, ccred);
 
802
        ret = 0;
 
803
    next:
 
804
        (*ccred->func->release)(ccred);
 
805
    }
 
806
 
 
807
    (*iter->func->release)(iter);
 
808
 
 
809
    if (ret)
 
810
        krb5_set_error_message(context, ret,
 
811
                               N_("Can't find credential %s in cache",
 
812
                                 "principal"), server);
 
813
    free(server);
 
814
    free(client);
 
815
 
 
816
    return ret;
 
817
}
 
818
 
 
819
static krb5_error_code
 
820
acc_set_flags(krb5_context context,
 
821
              krb5_ccache id,
 
822
              krb5_flags flags)
 
823
{
 
824
    return 0;
 
825
}
 
826
 
 
827
static int
 
828
acc_get_version(krb5_context context,
 
829
                krb5_ccache id)
 
830
{
 
831
    return 0;
 
832
}
 
833
                
 
834
struct cache_iter {
 
835
    cc_context_t context;
 
836
    cc_ccache_iterator_t iter;
 
837
};
 
838
 
 
839
static krb5_error_code
 
840
acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
 
841
{
 
842
    struct cache_iter *iter;
 
843
    krb5_error_code ret;
 
844
    cc_int32 error;
 
845
 
 
846
    ret = init_ccapi(context);
 
847
    if (ret)
 
848
        return ret;
 
849
 
 
850
    iter = calloc(1, sizeof(*iter));
 
851
    if (iter == NULL) {
 
852
        krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
 
853
        return ENOMEM;
 
854
    }
 
855
 
 
856
    error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL);
 
857
    if (error) {
 
858
        free(iter);
 
859
        return translate_cc_error(context, error);
 
860
    }
 
861
 
 
862
    error = (*iter->context->func->new_ccache_iterator)(iter->context,
 
863
                                                        &iter->iter);
 
864
    if (error) {
 
865
        free(iter);
 
866
        krb5_clear_error_message(context);
 
867
        return ENOENT;
 
868
    }
 
869
    *cursor = iter;
 
870
    return 0;
 
871
}
 
872
 
 
873
static krb5_error_code
 
874
acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
 
875
{
 
876
    struct cache_iter *iter = cursor;
 
877
    cc_ccache_t cache;
 
878
    krb5_acc *a;
 
879
    krb5_error_code ret;
 
880
    int32_t error;
 
881
 
 
882
    error = (*iter->iter->func->next)(iter->iter, &cache);
 
883
    if (error)
 
884
        return translate_cc_error(context, error);
 
885
 
 
886
    ret = _krb5_cc_allocate(context, &krb5_acc_ops, id);
 
887
    if (ret) {
 
888
        (*cache->func->release)(cache);
 
889
        return ret;
 
890
    }
 
891
 
 
892
    ret = acc_alloc(context, id);
 
893
    if (ret) {
 
894
        (*cache->func->release)(cache);
 
895
        free(*id);
 
896
        return ret;
 
897
    }
 
898
 
 
899
    a = ACACHE(*id);
 
900
    a->ccache = cache;
 
901
 
 
902
    error = get_cc_name(a);
 
903
    if (error) {
 
904
        acc_close(context, *id);
 
905
        *id = NULL;
 
906
        return translate_cc_error(context, error);
 
907
    }   
 
908
    return 0;
 
909
}
 
910
 
 
911
static krb5_error_code
 
912
acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
 
913
{
 
914
    struct cache_iter *iter = cursor;
 
915
 
 
916
    (*iter->iter->func->release)(iter->iter);
 
917
    iter->iter = NULL;
 
918
    (*iter->context->func->release)(iter->context);
 
919
    iter->context = NULL;
 
920
    free(iter);
 
921
    return 0;
 
922
}
 
923
 
 
924
static krb5_error_code
 
925
acc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
 
926
{
 
927
    krb5_acc *afrom = ACACHE(from);
 
928
    krb5_acc *ato = ACACHE(to);
 
929
    int32_t error;
 
930
 
 
931
    if (ato->ccache == NULL) {
 
932
        cc_string_t name;
 
933
 
 
934
        error = (*afrom->ccache->func->get_principal)(afrom->ccache,
 
935
                                                      cc_credentials_v5,
 
936
                                                      &name);
 
937
        if (error)
 
938
            return translate_cc_error(context, error);
 
939
 
 
940
        error = (*ato->context->func->create_new_ccache)(ato->context,
 
941
                                                         cc_credentials_v5,
 
942
                                                         name->data,
 
943
                                                         &ato->ccache);
 
944
        (*name->func->release)(name);
 
945
        if (error)
 
946
            return translate_cc_error(context, error);
 
947
    }
 
948
 
 
949
 
 
950
    error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache);
 
951
    return translate_cc_error(context, error);
 
952
}
 
953
 
 
954
static krb5_error_code
 
955
acc_get_default_name(krb5_context context, char **str)
 
956
{
 
957
    krb5_error_code ret;
 
958
    cc_context_t cc;
 
959
    cc_string_t name;
 
960
    int32_t error;
 
961
 
 
962
    ret = init_ccapi(context);
 
963
    if (ret)
 
964
        return ret;
 
965
 
 
966
    error = (*init_func)(&cc, ccapi_version_3, NULL, NULL);
 
967
    if (error)
 
968
        return translate_cc_error(context, error);
 
969
 
 
970
    error = (*cc->func->get_default_ccache_name)(cc, &name);
 
971
    if (error) {
 
972
        (*cc->func->release)(cc);
 
973
        return translate_cc_error(context, error);
 
974
    }
 
975
        
 
976
    asprintf(str, "API:%s", name->data);
 
977
    (*name->func->release)(name);
 
978
    (*cc->func->release)(cc);
 
979
 
 
980
    if (*str == NULL) {
 
981
        krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 
982
        return ENOMEM;
 
983
    }
 
984
    return 0;
 
985
}
 
986
 
 
987
static krb5_error_code
 
988
acc_set_default(krb5_context context, krb5_ccache id)
 
989
{
 
990
    krb5_acc *a = ACACHE(id);
 
991
    cc_int32 error;
 
992
 
 
993
    if (a->ccache == NULL) {
 
994
        krb5_set_error_message(context, KRB5_CC_NOTFOUND,
 
995
                               N_("No API credential found", ""));
 
996
        return KRB5_CC_NOTFOUND;
 
997
    }
 
998
 
 
999
    error = (*a->ccache->func->set_default)(a->ccache);
 
1000
    if (error)
 
1001
        return translate_cc_error(context, error);
 
1002
 
 
1003
    return 0;
 
1004
}
 
1005
 
 
1006
static krb5_error_code
 
1007
acc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
 
1008
{
 
1009
    krb5_acc *a = ACACHE(id);
 
1010
    cc_int32 error;
 
1011
    cc_time_t t;
 
1012
 
 
1013
    if (a->ccache == NULL) {
 
1014
        krb5_set_error_message(context, KRB5_CC_NOTFOUND,
 
1015
                               N_("No API credential found", ""));
 
1016
        return KRB5_CC_NOTFOUND;
 
1017
    }
 
1018
 
 
1019
    error = (*a->ccache->func->get_change_time)(a->ccache, &t);
 
1020
    if (error)
 
1021
        return translate_cc_error(context, error);
 
1022
 
 
1023
    *mtime = t;
 
1024
 
 
1025
    return 0;
 
1026
}
 
1027
 
 
1028
/**
 
1029
 * Variable containing the API based credential cache implemention.
 
1030
 *
 
1031
 * @ingroup krb5_ccache
 
1032
 */
 
1033
 
 
1034
KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = {
 
1035
    KRB5_CC_OPS_VERSION,
 
1036
    "API",
 
1037
    acc_get_name,
 
1038
    acc_resolve,
 
1039
    acc_gen_new,
 
1040
    acc_initialize,
 
1041
    acc_destroy,
 
1042
    acc_close,
 
1043
    acc_store_cred,
 
1044
    NULL, /* acc_retrieve */
 
1045
    acc_get_principal,
 
1046
    acc_get_first,
 
1047
    acc_get_next,
 
1048
    acc_end_get,
 
1049
    acc_remove_cred,
 
1050
    acc_set_flags,
 
1051
    acc_get_version,
 
1052
    acc_get_cache_first,
 
1053
    acc_get_cache_next,
 
1054
    acc_end_cache_get,
 
1055
    acc_move,
 
1056
    acc_get_default_name,
 
1057
    acc_set_default,
 
1058
    acc_lastchange
 
1059
};