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