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

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

Samba 3.5.0: Initial import

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