No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / acache.c
blob5ead5521a9b7a2d155839c978ef1cddd3a1967c7
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("$Heimdal: acache.c 22099 2007-12-03 17:14:34Z lha $"
41 "$NetBSD$");
43 /* XXX should we fetch these for each open ? */
44 static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER;
45 static cc_initialize_func init_func;
47 #ifdef HAVE_DLOPEN
48 static void *cc_handle;
49 #endif
51 typedef struct krb5_acc {
52 char *cache_name;
53 cc_context_t context;
54 cc_ccache_t ccache;
55 } krb5_acc;
57 static krb5_error_code acc_close(krb5_context, krb5_ccache);
59 #define ACACHE(X) ((krb5_acc *)(X)->data.data)
61 static const struct {
62 cc_int32 error;
63 krb5_error_code ret;
64 } cc_errors[] = {
65 { ccErrBadName, KRB5_CC_BADNAME },
66 { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
67 { ccErrCCacheNotFound, KRB5_FCC_NOFILE },
68 { ccErrContextNotFound, KRB5_CC_NOTFOUND },
69 { ccIteratorEnd, KRB5_CC_END },
70 { ccErrNoMem, KRB5_CC_NOMEM },
71 { ccErrServerUnavailable, KRB5_CC_NOSUPP },
72 { ccNoError, 0 }
75 static krb5_error_code
76 translate_cc_error(krb5_context context, cc_int32 error)
78 int i;
79 krb5_clear_error_string(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;
86 static krb5_error_code
87 init_ccapi(krb5_context context)
89 const char *lib;
91 HEIMDAL_MUTEX_lock(&acc_mutex);
92 if (init_func) {
93 HEIMDAL_MUTEX_unlock(&acc_mutex);
94 krb5_clear_error_string(context);
95 return 0;
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
109 #ifdef HAVE_DLOPEN
111 #ifndef RTLD_LAZY
112 #define RTLD_LAZY 0
113 #endif
115 cc_handle = dlopen(lib, RTLD_LAZY);
116 if (cc_handle == NULL) {
117 HEIMDAL_MUTEX_unlock(&acc_mutex);
118 krb5_set_error_string(context, "Failed to load %s", lib);
119 return KRB5_CC_NOSUPP;
122 init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize");
123 HEIMDAL_MUTEX_unlock(&acc_mutex);
124 if (init_func == NULL) {
125 krb5_set_error_string(context, "Failed to find cc_initialize"
126 "in %s: %s", lib, dlerror());
127 dlclose(cc_handle);
128 return KRB5_CC_NOSUPP;
131 return 0;
132 #else
133 HEIMDAL_MUTEX_unlock(&acc_mutex);
134 krb5_set_error_string(context, "no support for shared object");
135 return KRB5_CC_NOSUPP;
136 #endif
139 static krb5_error_code
140 make_cred_from_ccred(krb5_context context,
141 const cc_credentials_v5_t *incred,
142 krb5_creds *cred)
144 krb5_error_code ret;
145 int i;
147 memset(cred, 0, sizeof(*cred));
149 ret = krb5_parse_name(context, incred->client, &cred->client);
150 if (ret)
151 goto fail;
153 ret = krb5_parse_name(context, incred->server, &cred->server);
154 if (ret)
155 goto fail;
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);
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;
170 ret = krb5_data_copy(&cred->ticket,
171 incred->ticket.data,
172 incred->ticket.length);
173 if (ret)
174 goto nomem;
176 ret = krb5_data_copy(&cred->second_ticket,
177 incred->second_ticket.data,
178 incred->second_ticket.length);
179 if (ret)
180 goto nomem;
182 cred->authdata.val = NULL;
183 cred->authdata.len = 0;
185 cred->addresses.val = NULL;
186 cred->addresses.len = 0;
188 for (i = 0; incred->authdata && incred->authdata[i]; i++)
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;
206 for (i = 0; incred->addresses && incred->addresses[i]; i++)
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;
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;
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;
255 return 0;
257 nomem:
258 ret = ENOMEM;
259 krb5_set_error_string(context, "malloc - out of memory");
261 fail:
262 krb5_free_cred_contents(context, cred);
263 return ret;
266 static void
267 free_ccred(cc_credentials_v5_t *cred)
269 int i;
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]);
277 free(cred->addresses);
279 if (cred->server)
280 free(cred->server);
281 if (cred->client)
282 free(cred->client);
283 memset(cred, 0, sizeof(*cred));
286 static krb5_error_code
287 make_ccred_from_cred(krb5_context context,
288 const krb5_creds *incred,
289 cc_credentials_v5_t *cred)
291 krb5_error_code ret;
292 int i;
294 memset(cred, 0, sizeof(*cred));
296 ret = krb5_unparse_name(context, incred->client, &cred->client);
297 if (ret)
298 goto fail;
300 ret = krb5_unparse_name(context, incred->server, &cred->server);
301 if (ret)
302 goto fail;
304 cred->keyblock.type = incred->session.keytype;
305 cred->keyblock.length = incred->session.keyvalue.length;
306 cred->keyblock.data = incred->session.keyvalue.data;
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;
313 cred->ticket.length = incred->ticket.length;
314 cred->ticket.data = incred->ticket.data;
316 cred->second_ticket.length = incred->second_ticket.length;
317 cred->second_ticket.data = incred->second_ticket.data;
319 /* XXX this one should also be filled in */
320 cred->authdata = NULL;
322 cred->addresses = calloc(incred->addresses.len + 1,
323 sizeof(cred->addresses[0]));
324 if (cred->addresses == NULL) {
326 ret = ENOMEM;
327 goto fail;
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;
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 ret = ENOMEM;
342 goto fail;
344 memcpy(addr->data, incred->addresses.val[i].address.data,
345 addr->length);
346 cred->addresses[i] = addr;
348 cred->addresses[i] = NULL;
350 cred->ticket_flags = 0;
351 if (incred->flags.b.forwardable)
352 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE;
353 if (incred->flags.b.forwarded)
354 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED;
355 if (incred->flags.b.proxiable)
356 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE;
357 if (incred->flags.b.proxy)
358 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY;
359 if (incred->flags.b.may_postdate)
360 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE;
361 if (incred->flags.b.postdated)
362 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED;
363 if (incred->flags.b.invalid)
364 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID;
365 if (incred->flags.b.renewable)
366 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE;
367 if (incred->flags.b.initial)
368 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL;
369 if (incred->flags.b.pre_authent)
370 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH;
371 if (incred->flags.b.hw_authent)
372 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH;
373 if (incred->flags.b.transited_policy_checked)
374 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED;
375 if (incred->flags.b.ok_as_delegate)
376 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE;
377 if (incred->flags.b.anonymous)
378 cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS;
380 return 0;
382 fail:
383 free_ccred(cred);
385 krb5_clear_error_string(context);
386 return ret;
389 static char *
390 get_cc_name(cc_ccache_t cache)
392 cc_string_t name;
393 cc_int32 error;
394 char *str;
396 error = (*cache->func->get_name)(cache, &name);
397 if (error)
398 return NULL;
400 str = strdup(name->data);
401 (*name->func->release)(name);
402 return str;
406 static const char*
407 acc_get_name(krb5_context context,
408 krb5_ccache id)
410 krb5_acc *a = ACACHE(id);
411 static char n[255];
412 char *name;
414 name = get_cc_name(a->ccache);
415 if (name == NULL) {
416 krb5_set_error_string(context, "malloc: out of memory");
417 return NULL;
419 strlcpy(n, name, sizeof(n));
420 free(name);
421 return n;
424 static krb5_error_code
425 acc_alloc(krb5_context context, krb5_ccache *id)
427 krb5_error_code ret;
428 cc_int32 error;
429 krb5_acc *a;
431 ret = init_ccapi(context);
432 if (ret)
433 return ret;
435 ret = krb5_data_alloc(&(*id)->data, sizeof(*a));
436 if (ret) {
437 krb5_clear_error_string(context);
438 return ret;
441 a = ACACHE(*id);
443 error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
444 if (error) {
445 krb5_data_free(&(*id)->data);
446 return translate_cc_error(context, error);
449 a->cache_name = NULL;
451 return 0;
454 static krb5_error_code
455 acc_resolve(krb5_context context, krb5_ccache *id, const char *res)
457 krb5_error_code ret;
458 cc_int32 error;
459 krb5_acc *a;
461 ret = acc_alloc(context, id);
462 if (ret)
463 return ret;
465 a = ACACHE(*id);
467 error = (*a->context->func->open_ccache)(a->context, res,
468 &a->ccache);
469 if (error == 0) {
470 a->cache_name = get_cc_name(a->ccache);
471 if (a->cache_name == NULL) {
472 acc_close(context, *id);
473 *id = NULL;
474 krb5_set_error_string(context, "malloc: out of memory");
475 return ENOMEM;
477 } else if (error == ccErrCCacheNotFound) {
478 a->ccache = NULL;
479 a->cache_name = NULL;
480 error = 0;
481 } else {
482 *id = NULL;
483 return translate_cc_error(context, error);
486 return 0;
489 static krb5_error_code
490 acc_gen_new(krb5_context context, krb5_ccache *id)
492 krb5_error_code ret;
493 krb5_acc *a;
495 ret = acc_alloc(context, id);
496 if (ret)
497 return ret;
499 a = ACACHE(*id);
501 a->ccache = NULL;
502 a->cache_name = NULL;
504 return 0;
507 static krb5_error_code
508 acc_initialize(krb5_context context,
509 krb5_ccache id,
510 krb5_principal primary_principal)
512 krb5_acc *a = ACACHE(id);
513 krb5_error_code ret;
514 int32_t error;
515 char *name;
517 ret = krb5_unparse_name(context, primary_principal, &name);
518 if (ret)
519 return ret;
521 error = (*a->context->func->create_new_ccache)(a->context,
522 cc_credentials_v5,
523 name,
524 &a->ccache);
525 free(name);
527 return translate_cc_error(context, error);
530 static krb5_error_code
531 acc_close(krb5_context context,
532 krb5_ccache id)
534 krb5_acc *a = ACACHE(id);
536 if (a->ccache) {
537 (*a->ccache->func->release)(a->ccache);
538 a->ccache = NULL;
540 if (a->cache_name) {
541 free(a->cache_name);
542 a->cache_name = NULL;
544 (*a->context->func->release)(a->context);
545 a->context = NULL;
546 krb5_data_free(&id->data);
547 return 0;
550 static krb5_error_code
551 acc_destroy(krb5_context context,
552 krb5_ccache id)
554 krb5_acc *a = ACACHE(id);
555 cc_int32 error = 0;
557 if (a->ccache) {
558 error = (*a->ccache->func->destroy)(a->ccache);
559 a->ccache = NULL;
561 if (a->context) {
562 error = (a->context->func->release)(a->context);
563 a->context = NULL;
565 return translate_cc_error(context, error);
568 static krb5_error_code
569 acc_store_cred(krb5_context context,
570 krb5_ccache id,
571 krb5_creds *creds)
573 krb5_acc *a = ACACHE(id);
574 cc_credentials_union cred;
575 cc_credentials_v5_t v5cred;
576 krb5_error_code ret;
577 cc_int32 error;
579 if (a->ccache == NULL) {
580 krb5_set_error_string(context, "No API credential found");
581 return KRB5_CC_NOTFOUND;
584 cred.version = cc_credentials_v5;
585 cred.credentials.credentials_v5 = &v5cred;
587 ret = make_ccred_from_cred(context,
588 creds,
589 &v5cred);
590 if (ret)
591 return ret;
593 error = (*a->ccache->func->store_credentials)(a->ccache, &cred);
594 if (error)
595 ret = translate_cc_error(context, error);
597 free_ccred(&v5cred);
599 return ret;
602 static krb5_error_code
603 acc_get_principal(krb5_context context,
604 krb5_ccache id,
605 krb5_principal *principal)
607 krb5_acc *a = ACACHE(id);
608 krb5_error_code ret;
609 int32_t error;
610 cc_string_t name;
612 if (a->ccache == NULL) {
613 krb5_set_error_string(context, "No API credential found");
614 return KRB5_CC_NOTFOUND;
617 error = (*a->ccache->func->get_principal)(a->ccache,
618 cc_credentials_v5,
619 &name);
620 if (error)
621 return translate_cc_error(context, error);
623 ret = krb5_parse_name(context, name->data, principal);
625 (*name->func->release)(name);
626 return ret;
629 static krb5_error_code
630 acc_get_first (krb5_context context,
631 krb5_ccache id,
632 krb5_cc_cursor *cursor)
634 cc_credentials_iterator_t iter;
635 krb5_acc *a = ACACHE(id);
636 int32_t error;
638 if (a->ccache == NULL) {
639 krb5_set_error_string(context, "No API credential found");
640 return KRB5_CC_NOTFOUND;
643 error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
644 if (error) {
645 krb5_clear_error_string(context);
646 return ENOENT;
648 *cursor = iter;
649 return 0;
653 static krb5_error_code
654 acc_get_next (krb5_context context,
655 krb5_ccache id,
656 krb5_cc_cursor *cursor,
657 krb5_creds *creds)
659 cc_credentials_iterator_t iter = *cursor;
660 cc_credentials_t cred;
661 krb5_error_code ret;
662 int32_t error;
664 while (1) {
665 error = (*iter->func->next)(iter, &cred);
666 if (error)
667 return translate_cc_error(context, error);
668 if (cred->data->version == cc_credentials_v5)
669 break;
670 (*cred->func->release)(cred);
673 ret = make_cred_from_ccred(context,
674 cred->data->credentials.credentials_v5,
675 creds);
676 (*cred->func->release)(cred);
677 return ret;
680 static krb5_error_code
681 acc_end_get (krb5_context context,
682 krb5_ccache id,
683 krb5_cc_cursor *cursor)
685 cc_credentials_iterator_t iter = *cursor;
686 (*iter->func->release)(iter);
687 return 0;
690 static krb5_error_code
691 acc_remove_cred(krb5_context context,
692 krb5_ccache id,
693 krb5_flags which,
694 krb5_creds *cred)
696 cc_credentials_iterator_t iter;
697 krb5_acc *a = ACACHE(id);
698 cc_credentials_t ccred;
699 krb5_error_code ret;
700 cc_int32 error;
701 char *client, *server;
703 if (a->ccache == NULL) {
704 krb5_set_error_string(context, "No API credential found");
705 return KRB5_CC_NOTFOUND;
708 if (cred->client) {
709 ret = krb5_unparse_name(context, cred->client, &client);
710 if (ret)
711 return ret;
712 } else
713 client = NULL;
715 ret = krb5_unparse_name(context, cred->server, &server);
716 if (ret) {
717 free(client);
718 return ret;
721 error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
722 if (error) {
723 free(server);
724 free(client);
725 return translate_cc_error(context, error);
728 ret = KRB5_CC_NOTFOUND;
729 while (1) {
730 cc_credentials_v5_t *v5cred;
732 error = (*iter->func->next)(iter, &ccred);
733 if (error)
734 break;
736 if (ccred->data->version != cc_credentials_v5)
737 goto next;
739 v5cred = ccred->data->credentials.credentials_v5;
741 if (client && strcmp(v5cred->client, client) != 0)
742 goto next;
744 if (strcmp(v5cred->server, server) != 0)
745 goto next;
747 (*a->ccache->func->remove_credentials)(a->ccache, ccred);
748 ret = 0;
749 next:
750 (*ccred->func->release)(ccred);
753 (*iter->func->release)(iter);
755 if (ret)
756 krb5_set_error_string(context, "Can't find credential %s in cache",
757 server);
758 free(server);
759 free(client);
761 return ret;
764 static krb5_error_code
765 acc_set_flags(krb5_context context,
766 krb5_ccache id,
767 krb5_flags flags)
769 return 0;
772 static krb5_error_code
773 acc_get_version(krb5_context context,
774 krb5_ccache id)
776 return 0;
779 struct cache_iter {
780 cc_context_t context;
781 cc_ccache_iterator_t iter;
784 static krb5_error_code
785 acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
787 struct cache_iter *iter;
788 krb5_error_code ret;
789 cc_int32 error;
791 ret = init_ccapi(context);
792 if (ret)
793 return ret;
795 iter = calloc(1, sizeof(*iter));
796 if (iter == NULL) {
797 krb5_set_error_string(context, "malloc - out of memory");
798 return ENOMEM;
801 error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL);
802 if (error) {
803 free(iter);
804 return translate_cc_error(context, error);
807 error = (*iter->context->func->new_ccache_iterator)(iter->context,
808 &iter->iter);
809 if (error) {
810 free(iter);
811 krb5_clear_error_string(context);
812 return ENOENT;
814 *cursor = iter;
815 return 0;
818 static krb5_error_code
819 acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
821 struct cache_iter *iter = cursor;
822 cc_ccache_t cache;
823 krb5_acc *a;
824 krb5_error_code ret;
825 int32_t error;
827 error = (*iter->iter->func->next)(iter->iter, &cache);
828 if (error)
829 return translate_cc_error(context, error);
831 ret = _krb5_cc_allocate(context, &krb5_acc_ops, id);
832 if (ret) {
833 (*cache->func->release)(cache);
834 return ret;
837 ret = acc_alloc(context, id);
838 if (ret) {
839 (*cache->func->release)(cache);
840 free(*id);
841 return ret;
844 a = ACACHE(*id);
845 a->ccache = cache;
847 a->cache_name = get_cc_name(a->ccache);
848 if (a->cache_name == NULL) {
849 acc_close(context, *id);
850 *id = NULL;
851 krb5_set_error_string(context, "malloc: out of memory");
852 return ENOMEM;
854 return 0;
857 static krb5_error_code
858 acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
860 struct cache_iter *iter = cursor;
862 (*iter->iter->func->release)(iter->iter);
863 iter->iter = NULL;
864 (*iter->context->func->release)(iter->context);
865 iter->context = NULL;
866 free(iter);
867 return 0;
870 static krb5_error_code
871 acc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
873 krb5_acc *afrom = ACACHE(from);
874 krb5_acc *ato = ACACHE(to);
875 int32_t error;
877 if (ato->ccache == NULL) {
878 cc_string_t name;
880 error = (*afrom->ccache->func->get_principal)(afrom->ccache,
881 cc_credentials_v5,
882 &name);
883 if (error)
884 return translate_cc_error(context, error);
886 error = (*ato->context->func->create_new_ccache)(ato->context,
887 cc_credentials_v5,
888 name->data,
889 &ato->ccache);
890 (*name->func->release)(name);
891 if (error)
892 return translate_cc_error(context, error);
896 error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache);
897 return translate_cc_error(context, error);
900 static krb5_error_code
901 acc_default_name(krb5_context context, char **str)
903 krb5_error_code ret;
904 cc_context_t cc;
905 cc_string_t name;
906 int32_t error;
908 ret = init_ccapi(context);
909 if (ret)
910 return ret;
912 error = (*init_func)(&cc, ccapi_version_3, NULL, NULL);
913 if (error)
914 return translate_cc_error(context, error);
916 error = (*cc->func->get_default_ccache_name)(cc, &name);
917 if (error) {
918 (*cc->func->release)(cc);
919 return translate_cc_error(context, error);
922 asprintf(str, "API:%s", name->data);
923 (*name->func->release)(name);
924 (*cc->func->release)(cc);
926 if (*str == NULL) {
927 krb5_set_error_string(context, "out of memory");
928 return ENOMEM;
930 return 0;
935 * Variable containing the API based credential cache implemention.
937 * @ingroup krb5_ccache
940 const krb5_cc_ops krb5_acc_ops = {
941 "API",
942 acc_get_name,
943 acc_resolve,
944 acc_gen_new,
945 acc_initialize,
946 acc_destroy,
947 acc_close,
948 acc_store_cred,
949 NULL, /* acc_retrieve */
950 acc_get_principal,
951 acc_get_first,
952 acc_get_next,
953 acc_end_get,
954 acc_remove_cred,
955 acc_set_flags,
956 acc_get_version,
957 acc_get_cache_first,
958 acc_get_cache_next,
959 acc_end_cache_get,
960 acc_move,
961 acc_default_name