drop unused files
[heimdal.git] / lib / krb5 / acache.c
blobffdeda08df3839df372a6c20a8653471d1ee41ee
1 /*
2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "krb5_locl.h"
35 #include <krb5_ccapi.h>
36 #ifdef HAVE_DLFCN_H
37 #include <dlfcn.h>
38 #endif
40 RCSID("$Id$");
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;
46 #ifdef HAVE_DLOPEN
47 static void *cc_handle;
48 #endif
50 typedef struct krb5_acc {
51 char *cache_name;
52 cc_context_t context;
53 cc_ccache_t ccache;
54 } krb5_acc;
56 static krb5_error_code acc_close(krb5_context, krb5_ccache);
58 #define ACACHE(X) ((krb5_acc *)(X)->data.data)
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 { ccNoError, 0 }
74 static krb5_error_code
75 translate_cc_error(krb5_context context, cc_int32 error)
77 int i;
78 krb5_clear_error_string(context);
79 for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++)
80 if (cc_errors[i].error == error)
81 return cc_errors[i].ret;
82 return KRB5_FCC_INTERNAL;
85 static krb5_error_code
86 init_ccapi(krb5_context context)
88 const char *lib;
90 HEIMDAL_MUTEX_lock(&acc_mutex);
91 if (init_func) {
92 HEIMDAL_MUTEX_unlock(&acc_mutex);
93 krb5_clear_error_string(context);
94 return 0;
97 lib = krb5_config_get_string(context, NULL,
98 "libdefaults", "ccapi_library",
99 NULL);
100 if (lib == NULL) {
101 #ifdef __APPLE__
102 lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos";
103 #else
104 lib = "/usr/lib/libkrb5_cc.so";
105 #endif
108 #ifdef HAVE_DLOPEN
110 #ifndef RTLD_LAZY
111 #define RTLD_LAZY 0
112 #endif
114 cc_handle = dlopen(lib, RTLD_LAZY);
115 if (cc_handle == NULL) {
116 HEIMDAL_MUTEX_unlock(&acc_mutex);
117 krb5_set_error_string(context, "Failed to load %s", lib);
118 return KRB5_CC_NOSUPP;
121 init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize");
122 HEIMDAL_MUTEX_unlock(&acc_mutex);
123 if (init_func == NULL) {
124 krb5_set_error_string(context, "Failed to find cc_initialize"
125 "in %s: %s", lib, dlerror());
126 dlclose(cc_handle);
127 return KRB5_CC_NOSUPP;
130 return 0;
131 #else
132 HEIMDAL_MUTEX_unlock(&acc_mutex);
133 krb5_set_error_string(context, "no support for shared object");
134 return KRB5_CC_NOSUPP;
135 #endif
138 static krb5_error_code
139 make_cred_from_ccred(krb5_context context,
140 const cc_credentials_v5_t *incred,
141 krb5_creds *cred)
143 krb5_error_code ret;
144 int i;
146 memset(cred, 0, sizeof(*cred));
148 ret = krb5_parse_name(context, incred->client, &cred->client);
149 if (ret)
150 goto fail;
152 ret = krb5_parse_name(context, incred->server, &cred->server);
153 if (ret)
154 goto fail;
156 cred->session.keytype = incred->keyblock.type;
157 cred->session.keyvalue.length = incred->keyblock.length;
158 cred->session.keyvalue.data = malloc(incred->keyblock.length);
159 if (cred->session.keyvalue.data == NULL)
160 goto nomem;
161 memcpy(cred->session.keyvalue.data, incred->keyblock.data,
162 incred->keyblock.length);
164 cred->times.authtime = incred->authtime;
165 cred->times.starttime = incred->starttime;
166 cred->times.endtime = incred->endtime;
167 cred->times.renew_till = incred->renew_till;
169 ret = krb5_data_copy(&cred->ticket,
170 incred->ticket.data,
171 incred->ticket.length);
172 if (ret)
173 goto nomem;
175 ret = krb5_data_copy(&cred->second_ticket,
176 incred->second_ticket.data,
177 incred->second_ticket.length);
178 if (ret)
179 goto nomem;
181 cred->authdata.val = NULL;
182 cred->authdata.len = 0;
184 cred->addresses.val = NULL;
185 cred->addresses.len = 0;
187 for (i = 0; incred->authdata && incred->authdata[i]; i++)
190 if (i) {
191 cred->authdata.val = calloc(i, sizeof(cred->authdata.val[0]));
192 if (cred->authdata.val == NULL)
193 goto nomem;
194 cred->authdata.len = i;
195 for (i = 0; i < cred->authdata.len; i++) {
196 cred->authdata.val[i].ad_type = incred->authdata[i]->type;
197 ret = krb5_data_copy(&cred->authdata.val[i].ad_data,
198 incred->authdata[i]->data,
199 incred->authdata[i]->length);
200 if (ret)
201 goto nomem;
205 for (i = 0; incred->addresses && incred->addresses[i]; i++)
208 if (i) {
209 cred->addresses.val = calloc(i, sizeof(cred->addresses.val[0]));
210 if (cred->addresses.val == NULL)
211 goto nomem;
212 cred->addresses.len = i;
214 for (i = 0; i < cred->addresses.len; i++) {
215 cred->addresses.val[i].addr_type = incred->addresses[i]->type;
216 ret = krb5_data_copy(&cred->addresses.val[i].address,
217 incred->addresses[i]->data,
218 incred->addresses[i]->length);
219 if (ret)
220 goto nomem;
224 cred->flags.i = 0;
225 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDABLE)
226 cred->flags.b.forwardable = 1;
227 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDED)
228 cred->flags.b.forwarded = 1;
229 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXIABLE)
230 cred->flags.b.proxiable = 1;
231 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXY)
232 cred->flags.b.proxy = 1;
233 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_MAY_POSTDATE)
234 cred->flags.b.may_postdate = 1;
235 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_POSTDATED)
236 cred->flags.b.postdated = 1;
237 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INVALID)
238 cred->flags.b.invalid = 1;
239 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_RENEWABLE)
240 cred->flags.b.renewable = 1;
241 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INITIAL)
242 cred->flags.b.initial = 1;
243 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PRE_AUTH)
244 cred->flags.b.pre_authent = 1;
245 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_HW_AUTH)
246 cred->flags.b.hw_authent = 1;
247 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED)
248 cred->flags.b.transited_policy_checked = 1;
249 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE)
250 cred->flags.b.ok_as_delegate = 1;
251 if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_ANONYMOUS)
252 cred->flags.b.anonymous = 1;
254 return 0;
256 nomem:
257 ret = ENOMEM;
258 krb5_set_error_string(context, "malloc - out of memory");
260 fail:
261 krb5_free_cred_contents(context, cred);
262 return ret;
265 static void
266 free_ccred(cc_credentials_v5_t *cred)
268 int i;
270 if (cred->addresses) {
271 for (i = 0; cred->addresses[i] != 0; i++) {
272 if (cred->addresses[i]->data)
273 free(cred->addresses[i]->data);
274 free(cred->addresses[i]);
276 free(cred->addresses);
278 if (cred->server)
279 free(cred->server);
280 if (cred->client)
281 free(cred->client);
282 memset(cred, 0, sizeof(*cred));
285 static krb5_error_code
286 make_ccred_from_cred(krb5_context context,
287 const krb5_creds *incred,
288 cc_credentials_v5_t *cred)
290 krb5_error_code ret;
291 int i;
293 memset(cred, 0, sizeof(*cred));
295 ret = krb5_unparse_name(context, incred->client, &cred->client);
296 if (ret)
297 goto fail;
299 ret = krb5_unparse_name(context, incred->server, &cred->server);
300 if (ret)
301 goto fail;
303 cred->keyblock.type = incred->session.keytype;
304 cred->keyblock.length = incred->session.keyvalue.length;
305 cred->keyblock.data = incred->session.keyvalue.data;
307 cred->authtime = incred->times.authtime;
308 cred->starttime = incred->times.starttime;
309 cred->endtime = incred->times.endtime;
310 cred->renew_till = incred->times.renew_till;
312 cred->ticket.length = incred->ticket.length;
313 cred->ticket.data = incred->ticket.data;
315 cred->second_ticket.length = incred->second_ticket.length;
316 cred->second_ticket.data = incred->second_ticket.data;
318 /* XXX this one should also be filled in */
319 cred->authdata = NULL;
321 cred->addresses = calloc(incred->addresses.len + 1,
322 sizeof(cred->addresses[0]));
323 if (cred->addresses == NULL) {
325 ret = ENOMEM;
326 goto fail;
329 for (i = 0; i < incred->addresses.len; i++) {
330 cc_data *addr;
331 addr = malloc(sizeof(*addr));
332 if (addr == NULL) {
333 ret = ENOMEM;
334 goto fail;
336 addr->type = incred->addresses.val[i].addr_type;
337 addr->length = incred->addresses.val[i].address.length;
338 addr->data = malloc(addr->length);
339 if (addr->data == NULL) {
340 ret = ENOMEM;
341 goto fail;
343 memcpy(addr->data, incred->addresses.val[i].address.data,
344 addr->length);
345 cred->addresses[i] = addr;
347 cred->addresses[i] = NULL;
349 cred->ticket_flags = 0;
350 if (incred->flags.b.forwardable)
351 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE;
352 if (incred->flags.b.forwarded)
353 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED;
354 if (incred->flags.b.proxiable)
355 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE;
356 if (incred->flags.b.proxy)
357 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY;
358 if (incred->flags.b.may_postdate)
359 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE;
360 if (incred->flags.b.postdated)
361 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED;
362 if (incred->flags.b.invalid)
363 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID;
364 if (incred->flags.b.renewable)
365 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE;
366 if (incred->flags.b.initial)
367 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL;
368 if (incred->flags.b.pre_authent)
369 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH;
370 if (incred->flags.b.hw_authent)
371 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH;
372 if (incred->flags.b.transited_policy_checked)
373 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED;
374 if (incred->flags.b.ok_as_delegate)
375 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE;
376 if (incred->flags.b.anonymous)
377 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS;
379 return 0;
381 fail:
382 free_ccred(cred);
384 krb5_clear_error_string(context);
385 return ret;
388 static char *
389 get_cc_name(cc_ccache_t cache)
391 cc_string_t name;
392 cc_int32 error;
393 char *str;
395 error = (*cache->func->get_name)(cache, &name);
396 if (error)
397 return NULL;
399 str = strdup(name->data);
400 (*name->func->release)(name);
401 return str;
405 static const char*
406 acc_get_name(krb5_context context,
407 krb5_ccache id)
409 krb5_acc *a = ACACHE(id);
410 static char n[255];
411 char *name;
413 name = get_cc_name(a->ccache);
414 if (name == NULL) {
415 krb5_set_error_string(context, "malloc: out of memory");
416 return NULL;
418 strlcpy(n, name, sizeof(n));
419 free(name);
420 return n;
423 static krb5_error_code
424 acc_alloc(krb5_context context, krb5_ccache *id)
426 krb5_error_code ret;
427 cc_int32 error;
428 krb5_acc *a;
430 ret = init_ccapi(context);
431 if (ret)
432 return ret;
434 ret = krb5_data_alloc(&(*id)->data, sizeof(*a));
435 if (ret) {
436 krb5_clear_error_string(context);
437 return ret;
440 a = ACACHE(*id);
442 error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
443 if (error) {
444 krb5_data_free(&(*id)->data);
445 return translate_cc_error(context, error);
448 a->cache_name = NULL;
450 return 0;
453 static krb5_error_code
454 acc_resolve(krb5_context context, krb5_ccache *id, const char *res)
456 krb5_error_code ret;
457 cc_int32 error;
458 krb5_acc *a;
460 ret = acc_alloc(context, id);
461 if (ret)
462 return ret;
464 a = ACACHE(*id);
466 error = (*a->context->func->open_ccache)(a->context, res,
467 &a->ccache);
468 if (error == 0) {
469 a->cache_name = get_cc_name(a->ccache);
470 if (a->cache_name == NULL) {
471 acc_close(context, *id);
472 *id = NULL;
473 krb5_set_error_string(context, "malloc: out of memory");
474 return ENOMEM;
476 } else if (error == ccErrCCacheNotFound) {
477 a->ccache = NULL;
478 a->cache_name = NULL;
479 error = 0;
480 } else {
481 *id = NULL;
482 return translate_cc_error(context, error);
485 return 0;
488 static krb5_error_code
489 acc_gen_new(krb5_context context, krb5_ccache *id)
491 krb5_error_code ret;
492 krb5_acc *a;
494 ret = acc_alloc(context, id);
495 if (ret)
496 return ret;
498 a = ACACHE(*id);
500 a->ccache = NULL;
501 a->cache_name = NULL;
503 return 0;
506 static krb5_error_code
507 acc_initialize(krb5_context context,
508 krb5_ccache id,
509 krb5_principal primary_principal)
511 krb5_acc *a = ACACHE(id);
512 krb5_error_code ret;
513 int32_t error;
514 char *name;
516 ret = krb5_unparse_name(context, primary_principal, &name);
517 if (ret)
518 return ret;
520 error = (*a->context->func->create_new_ccache)(a->context,
521 cc_credentials_v5,
522 name,
523 &a->ccache);
524 free(name);
526 return translate_cc_error(context, error);
529 static krb5_error_code
530 acc_close(krb5_context context,
531 krb5_ccache id)
533 krb5_acc *a = ACACHE(id);
535 if (a->ccache) {
536 (*a->ccache->func->release)(a->ccache);
537 a->ccache = NULL;
539 if (a->cache_name) {
540 free(a->cache_name);
541 a->cache_name = NULL;
543 (*a->context->func->release)(a->context);
544 a->context = NULL;
545 krb5_data_free(&id->data);
546 return 0;
549 static krb5_error_code
550 acc_destroy(krb5_context context,
551 krb5_ccache id)
553 krb5_acc *a = ACACHE(id);
554 cc_int32 error = 0;
556 if (a->ccache) {
557 error = (*a->ccache->func->destroy)(a->ccache);
558 a->ccache = NULL;
560 if (a->context) {
561 error = (a->context->func->release)(a->context);
562 a->context = NULL;
564 return translate_cc_error(context, error);
567 static krb5_error_code
568 acc_store_cred(krb5_context context,
569 krb5_ccache id,
570 krb5_creds *creds)
572 krb5_acc *a = ACACHE(id);
573 cc_credentials_union cred;
574 cc_credentials_v5_t v5cred;
575 krb5_error_code ret;
576 cc_int32 error;
578 if (a->ccache == NULL) {
579 krb5_set_error_string(context, "No API credential found");
580 return KRB5_CC_NOTFOUND;
583 cred.version = cc_credentials_v5;
584 cred.credentials.credentials_v5 = &v5cred;
586 ret = make_ccred_from_cred(context,
587 creds,
588 &v5cred);
589 if (ret)
590 return ret;
592 error = (*a->ccache->func->store_credentials)(a->ccache, &cred);
593 if (error)
594 ret = translate_cc_error(context, error);
596 free_ccred(&v5cred);
598 return ret;
601 static krb5_error_code
602 acc_get_principal(krb5_context context,
603 krb5_ccache id,
604 krb5_principal *principal)
606 krb5_acc *a = ACACHE(id);
607 krb5_error_code ret;
608 int32_t error;
609 cc_string_t name;
611 if (a->ccache == NULL) {
612 krb5_set_error_string(context, "No API credential found");
613 return KRB5_CC_NOTFOUND;
616 error = (*a->ccache->func->get_principal)(a->ccache,
617 cc_credentials_v5,
618 &name);
619 if (error)
620 return translate_cc_error(context, error);
622 ret = krb5_parse_name(context, name->data, principal);
624 (*name->func->release)(name);
625 return ret;
628 static krb5_error_code
629 acc_get_first (krb5_context context,
630 krb5_ccache id,
631 krb5_cc_cursor *cursor)
633 cc_credentials_iterator_t iter;
634 krb5_acc *a = ACACHE(id);
635 int32_t error;
637 if (a->ccache == NULL) {
638 krb5_set_error_string(context, "No API credential found");
639 return KRB5_CC_NOTFOUND;
642 error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
643 if (error) {
644 krb5_clear_error_string(context);
645 return ENOENT;
647 *cursor = iter;
648 return 0;
652 static krb5_error_code
653 acc_get_next (krb5_context context,
654 krb5_ccache id,
655 krb5_cc_cursor *cursor,
656 krb5_creds *creds)
658 cc_credentials_iterator_t iter = *cursor;
659 cc_credentials_t cred;
660 krb5_error_code ret;
661 int32_t error;
663 while (1) {
664 error = (*iter->func->next)(iter, &cred);
665 if (error)
666 return translate_cc_error(context, error);
667 if (cred->data->version == cc_credentials_v5)
668 break;
669 (*cred->func->release)(cred);
672 ret = make_cred_from_ccred(context,
673 cred->data->credentials.credentials_v5,
674 creds);
675 (*cred->func->release)(cred);
676 return ret;
679 static krb5_error_code
680 acc_end_get (krb5_context context,
681 krb5_ccache id,
682 krb5_cc_cursor *cursor)
684 cc_credentials_iterator_t iter = *cursor;
685 (*iter->func->release)(iter);
686 return 0;
689 static krb5_error_code
690 acc_remove_cred(krb5_context context,
691 krb5_ccache id,
692 krb5_flags which,
693 krb5_creds *cred)
695 cc_credentials_iterator_t iter;
696 krb5_acc *a = ACACHE(id);
697 cc_credentials_t ccred;
698 krb5_error_code ret;
699 cc_int32 error;
700 char *client, *server;
702 if (a->ccache == NULL) {
703 krb5_set_error_string(context, "No API credential found");
704 return KRB5_CC_NOTFOUND;
707 if (cred->client) {
708 ret = krb5_unparse_name(context, cred->client, &client);
709 if (ret)
710 return ret;
711 } else
712 client = NULL;
714 ret = krb5_unparse_name(context, cred->server, &server);
715 if (ret) {
716 free(client);
717 return ret;
720 error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
721 if (error) {
722 free(server);
723 free(client);
724 return translate_cc_error(context, error);
727 ret = KRB5_CC_NOTFOUND;
728 while (1) {
729 cc_credentials_v5_t *v5cred;
731 error = (*iter->func->next)(iter, &ccred);
732 if (error)
733 break;
735 if (ccred->data->version != cc_credentials_v5)
736 goto next;
738 v5cred = ccred->data->credentials.credentials_v5;
740 if (client && strcmp(v5cred->client, client) != 0)
741 goto next;
743 if (strcmp(v5cred->server, server) != 0)
744 goto next;
746 (*a->ccache->func->remove_credentials)(a->ccache, ccred);
747 ret = 0;
748 next:
749 (*ccred->func->release)(ccred);
752 (*iter->func->release)(iter);
754 if (ret)
755 krb5_set_error_string(context, "Can't find credential %s in cache",
756 server);
757 free(server);
758 free(client);
760 return ret;
763 static krb5_error_code
764 acc_set_flags(krb5_context context,
765 krb5_ccache id,
766 krb5_flags flags)
768 return 0;
771 static krb5_error_code
772 acc_get_version(krb5_context context,
773 krb5_ccache id)
775 return 0;
778 struct cache_iter {
779 cc_context_t context;
780 cc_ccache_iterator_t iter;
783 static krb5_error_code
784 acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
786 struct cache_iter *iter;
787 krb5_error_code ret;
788 cc_int32 error;
790 ret = init_ccapi(context);
791 if (ret)
792 return ret;
794 iter = calloc(1, sizeof(*iter));
795 if (iter == NULL) {
796 krb5_set_error_string(context, "malloc - out of memory");
797 return ENOMEM;
800 error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL);
801 if (error) {
802 free(iter);
803 return translate_cc_error(context, error);
806 error = (*iter->context->func->new_ccache_iterator)(iter->context,
807 &iter->iter);
808 if (error) {
809 free(iter);
810 krb5_clear_error_string(context);
811 return ENOENT;
813 *cursor = iter;
814 return 0;
817 static krb5_error_code
818 acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
820 struct cache_iter *iter = cursor;
821 cc_ccache_t cache;
822 krb5_acc *a;
823 krb5_error_code ret;
824 int32_t error;
826 error = (*iter->iter->func->next)(iter->iter, &cache);
827 if (error)
828 return translate_cc_error(context, error);
830 ret = _krb5_cc_allocate(context, &krb5_acc_ops, id);
831 if (ret) {
832 (*cache->func->release)(cache);
833 return ret;
836 ret = acc_alloc(context, id);
837 if (ret) {
838 (*cache->func->release)(cache);
839 free(*id);
840 return ret;
843 a = ACACHE(*id);
844 a->ccache = cache;
846 a->cache_name = get_cc_name(a->ccache);
847 if (a->cache_name == NULL) {
848 acc_close(context, *id);
849 *id = NULL;
850 krb5_set_error_string(context, "malloc: out of memory");
851 return ENOMEM;
853 return 0;
856 static krb5_error_code
857 acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
859 struct cache_iter *iter = cursor;
861 (*iter->iter->func->release)(iter->iter);
862 iter->iter = NULL;
863 (*iter->context->func->release)(iter->context);
864 iter->context = NULL;
865 free(iter);
866 return 0;
869 static krb5_error_code
870 acc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
872 krb5_acc *afrom = ACACHE(from);
873 krb5_acc *ato = ACACHE(to);
874 int32_t error;
876 if (ato->ccache == NULL) {
877 cc_string_t name;
879 error = (*afrom->ccache->func->get_principal)(afrom->ccache,
880 cc_credentials_v5,
881 &name);
882 if (error)
883 return translate_cc_error(context, error);
885 error = (*ato->context->func->create_new_ccache)(ato->context,
886 cc_credentials_v5,
887 name->data,
888 &ato->ccache);
889 (*name->func->release)(name);
890 if (error)
891 return translate_cc_error(context, error);
895 error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache);
896 return translate_cc_error(context, error);
899 static krb5_error_code
900 acc_default_name(krb5_context context, char **str)
902 krb5_error_code ret;
903 cc_context_t cc;
904 cc_string_t name;
905 int32_t error;
907 ret = init_ccapi(context);
908 if (ret)
909 return ret;
911 error = (*init_func)(&cc, ccapi_version_3, NULL, NULL);
912 if (error)
913 return translate_cc_error(context, error);
915 error = (*cc->func->get_default_ccache_name)(cc, &name);
916 if (error) {
917 (*cc->func->release)(cc);
918 return translate_cc_error(context, error);
921 asprintf(str, "API:%s", name->data);
922 (*name->func->release)(name);
923 (*cc->func->release)(cc);
925 if (*str == NULL) {
926 krb5_set_error_string(context, "out of memory");
927 return ENOMEM;
929 return 0;
934 * Variable containing the API based credential cache implemention.
936 * @ingroup krb5_ccache
939 const krb5_cc_ops krb5_acc_ops = {
940 "API",
941 acc_get_name,
942 acc_resolve,
943 acc_gen_new,
944 acc_initialize,
945 acc_destroy,
946 acc_close,
947 acc_store_cred,
948 NULL, /* acc_retrieve */
949 acc_get_principal,
950 acc_get_first,
951 acc_get_next,
952 acc_end_get,
953 acc_remove_cred,
954 acc_set_flags,
955 acc_get_version,
956 acc_get_cache_first,
957 acc_get_cache_next,
958 acc_end_cache_get,
959 acc_move,
960 acc_default_name