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: acache.c 22099 2007-12-03 17:14:34Z lha $"); 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 { ccNoError, 0 } 72 }; 73 74 static krb5_error_code 75 translate_cc_error(krb5_context context, cc_int32 error) 76 { 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; 83 } 84 85 static krb5_error_code 86 init_ccapi(krb5_context context) 87 { 88 const char *lib; 89 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; 95 } 96 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 106 } 107 108 #ifdef HAVE_DLOPEN 109 110 #ifndef RTLD_LAZY 111 #define RTLD_LAZY 0 112 #endif 113 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; 119 } 120 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; 128 } 129 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 136 } 137 138 static krb5_error_code 139 make_cred_from_ccred(krb5_context context, 140 const cc_credentials_v5_t *incred, 141 krb5_creds *cred) 142 { 143 krb5_error_code ret; 144 int i; 145 146 memset(cred, 0, sizeof(*cred)); 147 148 ret = krb5_parse_name(context, incred->client, &cred->client); 149 if (ret) 150 goto fail; 151 152 ret = krb5_parse_name(context, incred->server, &cred->server); 153 if (ret) 154 goto fail; 155 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); 163 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; 168 169 ret = krb5_data_copy(&cred->ticket, 170 incred->ticket.data, 171 incred->ticket.length); 172 if (ret) 173 goto nomem; 174 175 ret = krb5_data_copy(&cred->second_ticket, 176 incred->second_ticket.data, 177 incred->second_ticket.length); 178 if (ret) 179 goto nomem; 180 181 cred->authdata.val = NULL; 182 cred->authdata.len = 0; 183 184 cred->addresses.val = NULL; 185 cred->addresses.len = 0; 186 187 for (i = 0; incred->authdata && incred->authdata[i]; i++) 188 ; 189 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; 202 } 203 } 204 205 for (i = 0; incred->addresses && incred->addresses[i]; i++) 206 ; 207 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; 213 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; 221 } 222 } 223 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; 253 254 return 0; 255 256 nomem: 257 ret = ENOMEM; 258 krb5_set_error_string(context, "malloc - out of memory"); 259 260 fail: 261 krb5_free_cred_contents(context, cred); 262 return ret; 263 } 264 265 static void 266 free_ccred(cc_credentials_v5_t *cred) 267 { 268 int i; 269 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]); 275 } 276 free(cred->addresses); 277 } 278 if (cred->server) 279 free(cred->server); 280 if (cred->client) 281 free(cred->client); 282 memset(cred, 0, sizeof(*cred)); 283 } 284 285 static krb5_error_code 286 make_ccred_from_cred(krb5_context context, 287 const krb5_creds *incred, 288 cc_credentials_v5_t *cred) 289 { 290 krb5_error_code ret; 291 int i; 292 293 memset(cred, 0, sizeof(*cred)); 294 295 ret = krb5_unparse_name(context, incred->client, &cred->client); 296 if (ret) 297 goto fail; 298 299 ret = krb5_unparse_name(context, incred->server, &cred->server); 300 if (ret) 301 goto fail; 302 303 cred->keyblock.type = incred->session.keytype; 304 cred->keyblock.length = incred->session.keyvalue.length; 305 cred->keyblock.data = incred->session.keyvalue.data; 306 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; 311 312 cred->ticket.length = incred->ticket.length; 313 cred->ticket.data = incred->ticket.data; 314 315 cred->second_ticket.length = incred->second_ticket.length; 316 cred->second_ticket.data = incred->second_ticket.data; 317 318 /* XXX this one should also be filled in */ 319 cred->authdata = NULL; 320 321 cred->addresses = calloc(incred->addresses.len + 1, 322 sizeof(cred->addresses[0])); 323 if (cred->addresses == NULL) { 324 325 ret = ENOMEM; 326 goto fail; 327 } 328 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; 335 } 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; 342 } 343 memcpy(addr->data, incred->addresses.val[i].address.data, 344 addr->length); 345 cred->addresses[i] = addr; 346 } 347 cred->addresses[i] = NULL; 348 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; 378 379 return 0; 380 381 fail: 382 free_ccred(cred); 383 384 krb5_clear_error_string(context); 385 return ret; 386 } 387 388 static char * 389 get_cc_name(cc_ccache_t cache) 390 { 391 cc_string_t name; 392 cc_int32 error; 393 char *str; 394 395 error = (*cache->func->get_name)(cache, &name); 396 if (error) 397 return NULL; 398 399 str = strdup(name->data); 400 (*name->func->release)(name); 401 return str; 402 } 403 404 405 static const char* 406 acc_get_name(krb5_context context, 407 krb5_ccache id) 408 { 409 krb5_acc *a = ACACHE(id); 410 static char n[255]; 411 char *name; 412 413 name = get_cc_name(a->ccache); 414 if (name == NULL) { 415 krb5_set_error_string(context, "malloc: out of memory"); 416 return NULL; 417 } 418 strlcpy(n, name, sizeof(n)); 419 free(name); 420 return n; 421 } 422 423 static krb5_error_code 424 acc_alloc(krb5_context context, krb5_ccache *id) 425 { 426 krb5_error_code ret; 427 cc_int32 error; 428 krb5_acc *a; 429 430 ret = init_ccapi(context); 431 if (ret) 432 return ret; 433 434 ret = krb5_data_alloc(&(*id)->data, sizeof(*a)); 435 if (ret) { 436 krb5_clear_error_string(context); 437 return ret; 438 } 439 440 a = ACACHE(*id); 441 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); 446 } 447 448 a->cache_name = NULL; 449 450 return 0; 451 } 452 453 static krb5_error_code 454 acc_resolve(krb5_context context, krb5_ccache *id, const char *res) 455 { 456 krb5_error_code ret; 457 cc_int32 error; 458 krb5_acc *a; 459 460 ret = acc_alloc(context, id); 461 if (ret) 462 return ret; 463 464 a = ACACHE(*id); 465 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; 475 } 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); 483 } 484 485 return 0; 486 } 487 488 static krb5_error_code 489 acc_gen_new(krb5_context context, krb5_ccache *id) 490 { 491 krb5_error_code ret; 492 krb5_acc *a; 493 494 ret = acc_alloc(context, id); 495 if (ret) 496 return ret; 497 498 a = ACACHE(*id); 499 500 a->ccache = NULL; 501 a->cache_name = NULL; 502 503 return 0; 504 } 505 506 static krb5_error_code 507 acc_initialize(krb5_context context, 508 krb5_ccache id, 509 krb5_principal primary_principal) 510 { 511 krb5_acc *a = ACACHE(id); 512 krb5_error_code ret; 513 int32_t error; 514 char *name; 515 516 ret = krb5_unparse_name(context, primary_principal, &name); 517 if (ret) 518 return ret; 519 520 error = (*a->context->func->create_new_ccache)(a->context, 521 cc_credentials_v5, 522 name, 523 &a->ccache); 524 free(name); 525 526 return translate_cc_error(context, error); 527 } 528 529 static krb5_error_code 530 acc_close(krb5_context context, 531 krb5_ccache id) 532 { 533 krb5_acc *a = ACACHE(id); 534 535 if (a->ccache) { 536 (*a->ccache->func->release)(a->ccache); 537 a->ccache = NULL; 538 } 539 if (a->cache_name) { 540 free(a->cache_name); 541 a->cache_name = NULL; 542 } 543 (*a->context->func->release)(a->context); 544 a->context = NULL; 545 krb5_data_free(&id->data); 546 return 0; 547 } 548 549 static krb5_error_code 550 acc_destroy(krb5_context context, 551 krb5_ccache id) 552 { 553 krb5_acc *a = ACACHE(id); 554 cc_int32 error = 0; 555 556 if (a->ccache) { 557 error = (*a->ccache->func->destroy)(a->ccache); 558 a->ccache = NULL; 559 } 560 if (a->context) { 561 error = (a->context->func->release)(a->context); 562 a->context = NULL; 563 } 564 return translate_cc_error(context, error); 565 } 566 567 static krb5_error_code 568 acc_store_cred(krb5_context context, 569 krb5_ccache id, 570 krb5_creds *creds) 571 { 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; 577 578 if (a->ccache == NULL) { 579 krb5_set_error_string(context, "No API credential found"); 580 return KRB5_CC_NOTFOUND; 581 } 582 583 cred.version = cc_credentials_v5; 584 cred.credentials.credentials_v5 = &v5cred; 585 586 ret = make_ccred_from_cred(context, 587 creds, 588 &v5cred); 589 if (ret) 590 return ret; 591 592 error = (*a->ccache->func->store_credentials)(a->ccache, &cred); 593 if (error) 594 ret = translate_cc_error(context, error); 595 596 free_ccred(&v5cred); 597 598 return ret; 599 } 600 601 static krb5_error_code 602 acc_get_principal(krb5_context context, 603 krb5_ccache id, 604 krb5_principal *principal) 605 { 606 krb5_acc *a = ACACHE(id); 607 krb5_error_code ret; 608 int32_t error; 609 cc_string_t name; 610 611 if (a->ccache == NULL) { 612 krb5_set_error_string(context, "No API credential found"); 613 return KRB5_CC_NOTFOUND; 614 } 615 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); 621 622 ret = krb5_parse_name(context, name->data, principal); 623 624 (*name->func->release)(name); 625 return ret; 626 } 627 628 static krb5_error_code 629 acc_get_first (krb5_context context, 630 krb5_ccache id, 631 krb5_cc_cursor *cursor) 632 { 633 cc_credentials_iterator_t iter; 634 krb5_acc *a = ACACHE(id); 635 int32_t error; 636 637 if (a->ccache == NULL) { 638 krb5_set_error_string(context, "No API credential found"); 639 return KRB5_CC_NOTFOUND; 640 } 641 642 error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter); 643 if (error) { 644 krb5_clear_error_string(context); 645 return ENOENT; 646 } 647 *cursor = iter; 648 return 0; 649 } 650 651 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) 657 { 658 cc_credentials_iterator_t iter = *cursor; 659 cc_credentials_t cred; 660 krb5_error_code ret; 661 int32_t error; 662 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); 670 } 671 672 ret = make_cred_from_ccred(context, 673 cred->data->credentials.credentials_v5, 674 creds); 675 (*cred->func->release)(cred); 676 return ret; 677 } 678 679 static krb5_error_code 680 acc_end_get (krb5_context context, 681 krb5_ccache id, 682 krb5_cc_cursor *cursor) 683 { 684 cc_credentials_iterator_t iter = *cursor; 685 (*iter->func->release)(iter); 686 return 0; 687 } 688 689 static krb5_error_code 690 acc_remove_cred(krb5_context context, 691 krb5_ccache id, 692 krb5_flags which, 693 krb5_creds *cred) 694 { 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; 701 702 if (a->ccache == NULL) { 703 krb5_set_error_string(context, "No API credential found"); 704 return KRB5_CC_NOTFOUND; 705 } 706 707 if (cred->client) { 708 ret = krb5_unparse_name(context, cred->client, &client); 709 if (ret) 710 return ret; 711 } else 712 client = NULL; 713 714 ret = krb5_unparse_name(context, cred->server, &server); 715 if (ret) { 716 free(client); 717 return ret; 718 } 719 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); 725 } 726 727 ret = KRB5_CC_NOTFOUND; 728 while (1) { 729 cc_credentials_v5_t *v5cred; 730 731 error = (*iter->func->next)(iter, &ccred); 732 if (error) 733 break; 734 735 if (ccred->data->version != cc_credentials_v5) 736 goto next; 737 738 v5cred = ccred->data->credentials.credentials_v5; 739 740 if (client && strcmp(v5cred->client, client) != 0) 741 goto next; 742 743 if (strcmp(v5cred->server, server) != 0) 744 goto next; 745 746 (*a->ccache->func->remove_credentials)(a->ccache, ccred); 747 ret = 0; 748 next: 749 (*ccred->func->release)(ccred); 750 } 751 752 (*iter->func->release)(iter); 753 754 if (ret) 755 krb5_set_error_string(context, "Can't find credential %s in cache", 756 server); 757 free(server); 758 free(client); 759 760 return ret; 761 } 762 763 static krb5_error_code 764 acc_set_flags(krb5_context context, 765 krb5_ccache id, 766 krb5_flags flags) 767 { 768 return 0; 769 } 770 771 static krb5_error_code 772 acc_get_version(krb5_context context, 773 krb5_ccache id) 774 { 775 return 0; 776 } 777 778 struct cache_iter { 779 cc_context_t context; 780 cc_ccache_iterator_t iter; 781 }; 782 783 static krb5_error_code 784 acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) 785 { 786 struct cache_iter *iter; 787 krb5_error_code ret; 788 cc_int32 error; 789 790 ret = init_ccapi(context); 791 if (ret) 792 return ret; 793 794 iter = calloc(1, sizeof(*iter)); 795 if (iter == NULL) { 796 krb5_set_error_string(context, "malloc - out of memory"); 797 return ENOMEM; 798 } 799 800 error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL); 801 if (error) { 802 free(iter); 803 return translate_cc_error(context, error); 804 } 805 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; 812 } 813 *cursor = iter; 814 return 0; 815 } 816 817 static krb5_error_code 818 acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) 819 { 820 struct cache_iter *iter = cursor; 821 cc_ccache_t cache; 822 krb5_acc *a; 823 krb5_error_code ret; 824 int32_t error; 825 826 error = (*iter->iter->func->next)(iter->iter, &cache); 827 if (error) 828 return translate_cc_error(context, error); 829 830 ret = _krb5_cc_allocate(context, &krb5_acc_ops, id); 831 if (ret) { 832 (*cache->func->release)(cache); 833 return ret; 834 } 835 836 ret = acc_alloc(context, id); 837 if (ret) { 838 (*cache->func->release)(cache); 839 free(*id); 840 return ret; 841 } 842 843 a = ACACHE(*id); 844 a->ccache = cache; 845 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; 852 } 853 return 0; 854 } 855 856 static krb5_error_code 857 acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) 858 { 859 struct cache_iter *iter = cursor; 860 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; 867 } 868 869 static krb5_error_code 870 acc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 871 { 872 krb5_acc *afrom = ACACHE(from); 873 krb5_acc *ato = ACACHE(to); 874 int32_t error; 875 876 if (ato->ccache == NULL) { 877 cc_string_t name; 878 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); 884 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); 892 } 893 894 895 error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache); 896 return translate_cc_error(context, error); 897 } 898 899 static krb5_error_code 900 acc_default_name(krb5_context context, char **str) 901 { 902 krb5_error_code ret; 903 cc_context_t cc; 904 cc_string_t name; 905 int32_t error; 906 907 ret = init_ccapi(context); 908 if (ret) 909 return ret; 910 911 error = (*init_func)(&cc, ccapi_version_3, NULL, NULL); 912 if (error) 913 return translate_cc_error(context, error); 914 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); 919 } 920 921 asprintf(str, "API:%s", name->data); 922 (*name->func->release)(name); 923 (*cc->func->release)(cc); 924 925 if (*str == NULL) { 926 krb5_set_error_string(context, "out of memory"); 927 return ENOMEM; 928 } 929 return 0; 930 } 931 932 933 /** 934 * Variable containing the API based credential cache implemention. 935 * 936 * @ingroup krb5_ccache 937 */ 938 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 961 }; 962