1 /* 2 * Copyright (c) 1997 - 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 36 RCSID("$Id: cache.c 22127 2007-12-04 00:54:37Z lha $"); 37 38 /** 39 * Add a new ccache type with operations `ops', overwriting any 40 * existing one if `override'. 41 * 42 * @param context a Keberos context 43 * @param ops type of plugin symbol 44 * @param override flag to select if the registration is to overide 45 * an existing ops with the same name. 46 * 47 * @return Return an error code or 0. 48 * 49 * @ingroup krb5_ccache 50 */ 51 52 krb5_error_code KRB5_LIB_FUNCTION 53 krb5_cc_register(krb5_context context, 54 const krb5_cc_ops *ops, 55 krb5_boolean override) 56 { 57 int i; 58 59 for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 60 if(strcmp(context->cc_ops[i].prefix, ops->prefix) == 0) { 61 if(!override) { 62 krb5_set_error_string(context, 63 "ccache type %s already exists", 64 ops->prefix); 65 return KRB5_CC_TYPE_EXISTS; 66 } 67 break; 68 } 69 } 70 if(i == context->num_cc_ops) { 71 krb5_cc_ops *o = realloc(context->cc_ops, 72 (context->num_cc_ops + 1) * 73 sizeof(*context->cc_ops)); 74 if(o == NULL) { 75 krb5_set_error_string(context, "malloc: out of memory"); 76 return KRB5_CC_NOMEM; 77 } 78 context->num_cc_ops++; 79 context->cc_ops = o; 80 memset(context->cc_ops + i, 0, 81 (context->num_cc_ops - i) * sizeof(*context->cc_ops)); 82 } 83 memcpy(&context->cc_ops[i], ops, sizeof(context->cc_ops[i])); 84 return 0; 85 } 86 87 /* 88 * Allocate the memory for a `id' and the that function table to 89 * `ops'. Returns 0 or and error code. 90 */ 91 92 krb5_error_code 93 _krb5_cc_allocate(krb5_context context, 94 const krb5_cc_ops *ops, 95 krb5_ccache *id) 96 { 97 krb5_ccache p; 98 99 p = malloc (sizeof(*p)); 100 if(p == NULL) { 101 krb5_set_error_string(context, "malloc: out of memory"); 102 return KRB5_CC_NOMEM; 103 } 104 p->ops = ops; 105 *id = p; 106 107 return 0; 108 } 109 110 /* 111 * Allocate memory for a new ccache in `id' with operations `ops' 112 * and name `residual'. Return 0 or an error code. 113 */ 114 115 static krb5_error_code 116 allocate_ccache (krb5_context context, 117 const krb5_cc_ops *ops, 118 const char *residual, 119 krb5_ccache *id) 120 { 121 krb5_error_code ret; 122 123 ret = _krb5_cc_allocate(context, ops, id); 124 if (ret) 125 return ret; 126 ret = (*id)->ops->resolve(context, id, residual); 127 if(ret) 128 free(*id); 129 return ret; 130 } 131 132 /** 133 * Find and allocate a ccache in `id' from the specification in `residual'. 134 * If the ccache name doesn't contain any colon, interpret it as a file name. 135 * 136 * @param context a Keberos context. 137 * @param name string name of a credential cache. 138 * @param id return pointer to a found credential cache. 139 * 140 * @return Return 0 or an error code. In case of an error, id is set 141 * to NULL. 142 * 143 * @ingroup krb5_ccache 144 */ 145 146 147 krb5_error_code KRB5_LIB_FUNCTION 148 krb5_cc_resolve(krb5_context context, 149 const char *name, 150 krb5_ccache *id) 151 { 152 int i; 153 154 *id = NULL; 155 156 for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 157 size_t prefix_len = strlen(context->cc_ops[i].prefix); 158 159 if(strncmp(context->cc_ops[i].prefix, name, prefix_len) == 0 160 && name[prefix_len] == ':') { 161 return allocate_ccache (context, &context->cc_ops[i], 162 name + prefix_len + 1, 163 id); 164 } 165 } 166 if (strchr (name, ':') == NULL) 167 return allocate_ccache (context, &krb5_fcc_ops, name, id); 168 else { 169 krb5_set_error_string(context, "unknown ccache type %s", name); 170 return KRB5_CC_UNKNOWN_TYPE; 171 } 172 } 173 174 /** 175 * Generate a new ccache of type `ops' in `id'. 176 * 177 * @return Return 0 or an error code. 178 * 179 * @ingroup krb5_ccache 180 */ 181 182 183 krb5_error_code KRB5_LIB_FUNCTION 184 krb5_cc_gen_new(krb5_context context, 185 const krb5_cc_ops *ops, 186 krb5_ccache *id) 187 { 188 return krb5_cc_new_unique(context, ops->prefix, NULL, id); 189 } 190 191 /** 192 * Generates a new unique ccache of `type` in `id'. If `type' is NULL, 193 * the library chooses the default credential cache type. The supplied 194 * `hint' (that can be NULL) is a string that the credential cache 195 * type can use to base the name of the credential on, this is to make 196 * it easier for the user to differentiate the credentials. 197 * 198 * @return Returns 0 or an error code. 199 * 200 * @ingroup krb5_ccache 201 */ 202 203 krb5_error_code KRB5_LIB_FUNCTION 204 krb5_cc_new_unique(krb5_context context, const char *type, 205 const char *hint, krb5_ccache *id) 206 { 207 const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE; 208 krb5_error_code ret; 209 210 if (type) { 211 ops = krb5_cc_get_prefix_ops(context, type); 212 if (ops == NULL) { 213 krb5_set_error_string(context, 214 "Credential cache type %s is unknown", type); 215 return KRB5_CC_UNKNOWN_TYPE; 216 } 217 } 218 219 ret = _krb5_cc_allocate(context, ops, id); 220 if (ret) 221 return ret; 222 return (*id)->ops->gen_new(context, id); 223 } 224 225 /** 226 * Return the name of the ccache `id' 227 * 228 * @ingroup krb5_ccache 229 */ 230 231 232 const char* KRB5_LIB_FUNCTION 233 krb5_cc_get_name(krb5_context context, 234 krb5_ccache id) 235 { 236 return id->ops->get_name(context, id); 237 } 238 239 /** 240 * Return the type of the ccache `id'. 241 * 242 * @ingroup krb5_ccache 243 */ 244 245 246 const char* KRB5_LIB_FUNCTION 247 krb5_cc_get_type(krb5_context context, 248 krb5_ccache id) 249 { 250 return id->ops->prefix; 251 } 252 253 /** 254 * Return the complete resolvable name the ccache `id' in `str�. 255 * `str` should be freed with free(3). 256 * Returns 0 or an error (and then *str is set to NULL). 257 * 258 * @ingroup krb5_ccache 259 */ 260 261 262 krb5_error_code KRB5_LIB_FUNCTION 263 krb5_cc_get_full_name(krb5_context context, 264 krb5_ccache id, 265 char **str) 266 { 267 const char *type, *name; 268 269 *str = NULL; 270 271 type = krb5_cc_get_type(context, id); 272 if (type == NULL) { 273 krb5_set_error_string(context, "cache have no name of type"); 274 return KRB5_CC_UNKNOWN_TYPE; 275 } 276 277 name = krb5_cc_get_name(context, id); 278 if (name == NULL) { 279 krb5_set_error_string(context, "cache of type %s have no name", type); 280 return KRB5_CC_BADNAME; 281 } 282 283 if (asprintf(str, "%s:%s", type, name) == -1) { 284 krb5_set_error_string(context, "malloc - out of memory"); 285 *str = NULL; 286 return ENOMEM; 287 } 288 return 0; 289 } 290 291 /** 292 * Return krb5_cc_ops of a the ccache `id'. 293 * 294 * @ingroup krb5_ccache 295 */ 296 297 298 const krb5_cc_ops * 299 krb5_cc_get_ops(krb5_context context, krb5_ccache id) 300 { 301 return id->ops; 302 } 303 304 /* 305 * Expand variables in `str' into `res' 306 */ 307 308 krb5_error_code 309 _krb5_expand_default_cc_name(krb5_context context, const char *str, char **res) 310 { 311 size_t tlen, len = 0; 312 char *tmp, *tmp2, *append; 313 314 *res = NULL; 315 316 while (str && *str) { 317 tmp = strstr(str, "%{"); 318 if (tmp && tmp != str) { 319 append = malloc((tmp - str) + 1); 320 if (append) { 321 memcpy(append, str, tmp - str); 322 append[tmp - str] = '\0'; 323 } 324 str = tmp; 325 } else if (tmp) { 326 tmp2 = strchr(tmp, '}'); 327 if (tmp2 == NULL) { 328 free(*res); 329 *res = NULL; 330 krb5_set_error_string(context, "variable missing }"); 331 return KRB5_CONFIG_BADFORMAT; 332 } 333 if (strncasecmp(tmp, "%{uid}", 6) == 0) 334 asprintf(&append, "%u", (unsigned)getuid()); 335 else if (strncasecmp(tmp, "%{null}", 7) == 0) 336 append = strdup(""); 337 else { 338 free(*res); 339 *res = NULL; 340 krb5_set_error_string(context, 341 "expand default cache unknown " 342 "variable \"%.*s\"", 343 (int)(tmp2 - tmp) - 2, tmp + 2); 344 return KRB5_CONFIG_BADFORMAT; 345 } 346 str = tmp2 + 1; 347 } else { 348 append = strdup(str); 349 str = NULL; 350 } 351 if (append == NULL) { 352 free(*res); 353 *res = NULL; 354 krb5_set_error_string(context, "malloc - out of memory"); 355 return ENOMEM; 356 } 357 358 tlen = strlen(append); 359 tmp = realloc(*res, len + tlen + 1); 360 if (tmp == NULL) { 361 free(append); 362 free(*res); 363 *res = NULL; 364 krb5_set_error_string(context, "malloc - out of memory"); 365 return ENOMEM; 366 } 367 *res = tmp; 368 memcpy(*res + len, append, tlen + 1); 369 len = len + tlen; 370 free(append); 371 } 372 return 0; 373 } 374 375 /* 376 * Return non-zero if envirnoment that will determine default krb5cc 377 * name has changed. 378 */ 379 380 static int 381 environment_changed(krb5_context context) 382 { 383 const char *e; 384 385 /* if the cc name was set, don't change it */ 386 if (context->default_cc_name_set) 387 return 0; 388 389 if(issuid()) 390 return 0; 391 392 e = getenv("KRB5CCNAME"); 393 if (e == NULL) { 394 if (context->default_cc_name_env) { 395 free(context->default_cc_name_env); 396 context->default_cc_name_env = NULL; 397 return 1; 398 } 399 } else { 400 if (context->default_cc_name_env == NULL) 401 return 1; 402 if (strcmp(e, context->default_cc_name_env) != 0) 403 return 1; 404 } 405 return 0; 406 } 407 408 /** 409 * Set the default cc name for `context' to `name'. 410 * 411 * @ingroup krb5_ccache 412 */ 413 414 415 krb5_error_code KRB5_LIB_FUNCTION 416 krb5_cc_set_default_name(krb5_context context, const char *name) 417 { 418 krb5_error_code ret = 0; 419 char *p; 420 421 if (name == NULL) { 422 const char *e = NULL; 423 424 if(!issuid()) { 425 e = getenv("KRB5CCNAME"); 426 if (e) { 427 p = strdup(e); 428 if (context->default_cc_name_env) 429 free(context->default_cc_name_env); 430 context->default_cc_name_env = strdup(e); 431 } 432 } 433 if (e == NULL) { 434 e = krb5_config_get_string(context, NULL, "libdefaults", 435 "default_cc_name", NULL); 436 if (e) { 437 ret = _krb5_expand_default_cc_name(context, e, &p); 438 if (ret) 439 return ret; 440 } 441 if (e == NULL) { 442 const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE; 443 ret = (*ops->default_name)(context, &p); 444 if (ret) 445 return ret; 446 } 447 } 448 context->default_cc_name_set = 0; 449 } else { 450 p = strdup(name); 451 context->default_cc_name_set = 1; 452 } 453 454 if (p == NULL) { 455 krb5_set_error_string(context, "malloc - out of memory"); 456 return ENOMEM; 457 } 458 459 if (context->default_cc_name) 460 free(context->default_cc_name); 461 462 context->default_cc_name = p; 463 464 return ret; 465 } 466 467 /** 468 * Return a pointer to a context static string containing the default 469 * ccache name. 470 * 471 * @return String to the default credential cache name. 472 * 473 * @ingroup krb5_ccache 474 */ 475 476 477 const char* KRB5_LIB_FUNCTION 478 krb5_cc_default_name(krb5_context context) 479 { 480 if (context->default_cc_name == NULL || environment_changed(context)) 481 krb5_cc_set_default_name(context, NULL); 482 483 return context->default_cc_name; 484 } 485 486 /** 487 * Open the default ccache in `id'. 488 * 489 * @return Return 0 or an error code. 490 * 491 * @ingroup krb5_ccache 492 */ 493 494 495 krb5_error_code KRB5_LIB_FUNCTION 496 krb5_cc_default(krb5_context context, 497 krb5_ccache *id) 498 { 499 const char *p = krb5_cc_default_name(context); 500 501 if (p == NULL) { 502 krb5_set_error_string(context, "malloc - out of memory"); 503 return ENOMEM; 504 } 505 return krb5_cc_resolve(context, p, id); 506 } 507 508 /** 509 * Create a new ccache in `id' for `primary_principal'. 510 * 511 * @return Return 0 or an error code. 512 * 513 * @ingroup krb5_ccache 514 */ 515 516 517 krb5_error_code KRB5_LIB_FUNCTION 518 krb5_cc_initialize(krb5_context context, 519 krb5_ccache id, 520 krb5_principal primary_principal) 521 { 522 return (*id->ops->init)(context, id, primary_principal); 523 } 524 525 526 /** 527 * Remove the ccache `id'. 528 * 529 * @return Return 0 or an error code. 530 * 531 * @ingroup krb5_ccache 532 */ 533 534 535 krb5_error_code KRB5_LIB_FUNCTION 536 krb5_cc_destroy(krb5_context context, 537 krb5_ccache id) 538 { 539 krb5_error_code ret; 540 541 ret = (*id->ops->destroy)(context, id); 542 krb5_cc_close (context, id); 543 return ret; 544 } 545 546 /** 547 * Stop using the ccache `id' and free the related resources. 548 * 549 * @return Return 0 or an error code. 550 * 551 * @ingroup krb5_ccache 552 */ 553 554 555 krb5_error_code KRB5_LIB_FUNCTION 556 krb5_cc_close(krb5_context context, 557 krb5_ccache id) 558 { 559 krb5_error_code ret; 560 ret = (*id->ops->close)(context, id); 561 free(id); 562 return ret; 563 } 564 565 /** 566 * Store `creds' in the ccache `id'. 567 * 568 * @return Return 0 or an error code. 569 * 570 * @ingroup krb5_ccache 571 */ 572 573 574 krb5_error_code KRB5_LIB_FUNCTION 575 krb5_cc_store_cred(krb5_context context, 576 krb5_ccache id, 577 krb5_creds *creds) 578 { 579 return (*id->ops->store)(context, id, creds); 580 } 581 582 /** 583 * Retrieve the credential identified by `mcreds' (and `whichfields') 584 * from `id' in `creds'. 'creds' must be free by the caller using 585 * krb5_free_cred_contents. 586 * 587 * @return Return 0 or an error code. 588 * 589 * @ingroup krb5_ccache 590 */ 591 592 593 krb5_error_code KRB5_LIB_FUNCTION 594 krb5_cc_retrieve_cred(krb5_context context, 595 krb5_ccache id, 596 krb5_flags whichfields, 597 const krb5_creds *mcreds, 598 krb5_creds *creds) 599 { 600 krb5_error_code ret; 601 krb5_cc_cursor cursor; 602 603 if (id->ops->retrieve != NULL) { 604 return (*id->ops->retrieve)(context, id, whichfields, 605 mcreds, creds); 606 } 607 608 ret = krb5_cc_start_seq_get(context, id, &cursor); 609 if (ret) 610 return ret; 611 while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){ 612 if(krb5_compare_creds(context, whichfields, mcreds, creds)){ 613 ret = 0; 614 break; 615 } 616 krb5_free_cred_contents (context, creds); 617 } 618 krb5_cc_end_seq_get(context, id, &cursor); 619 return ret; 620 } 621 622 /** 623 * Return the principal of `id' in `principal'. 624 * 625 * @return Return 0 or an error code. 626 * 627 * @ingroup krb5_ccache 628 */ 629 630 631 krb5_error_code KRB5_LIB_FUNCTION 632 krb5_cc_get_principal(krb5_context context, 633 krb5_ccache id, 634 krb5_principal *principal) 635 { 636 return (*id->ops->get_princ)(context, id, principal); 637 } 638 639 /** 640 * Start iterating over `id', `cursor' is initialized to the 641 * beginning. 642 * 643 * @return Return 0 or an error code. 644 * 645 * @ingroup krb5_ccache 646 */ 647 648 649 krb5_error_code KRB5_LIB_FUNCTION 650 krb5_cc_start_seq_get (krb5_context context, 651 const krb5_ccache id, 652 krb5_cc_cursor *cursor) 653 { 654 return (*id->ops->get_first)(context, id, cursor); 655 } 656 657 /** 658 * Retrieve the next cred pointed to by (`id', `cursor') in `creds' 659 * and advance `cursor'. 660 * 661 * @return Return 0 or an error code. 662 * 663 * @ingroup krb5_ccache 664 */ 665 666 667 krb5_error_code KRB5_LIB_FUNCTION 668 krb5_cc_next_cred (krb5_context context, 669 const krb5_ccache id, 670 krb5_cc_cursor *cursor, 671 krb5_creds *creds) 672 { 673 return (*id->ops->get_next)(context, id, cursor, creds); 674 } 675 676 /** 677 * Like krb5_cc_next_cred, but allow for selective retrieval 678 * 679 * @ingroup krb5_ccache 680 */ 681 682 683 krb5_error_code KRB5_LIB_FUNCTION 684 krb5_cc_next_cred_match(krb5_context context, 685 const krb5_ccache id, 686 krb5_cc_cursor * cursor, 687 krb5_creds * creds, 688 krb5_flags whichfields, 689 const krb5_creds * mcreds) 690 { 691 krb5_error_code ret; 692 while (1) { 693 ret = krb5_cc_next_cred(context, id, cursor, creds); 694 if (ret) 695 return ret; 696 if (mcreds == NULL || krb5_compare_creds(context, whichfields, mcreds, creds)) 697 return 0; 698 krb5_free_cred_contents(context, creds); 699 } 700 } 701 702 /** 703 * Destroy the cursor `cursor'. 704 * 705 * @ingroup krb5_ccache 706 */ 707 708 709 krb5_error_code KRB5_LIB_FUNCTION 710 krb5_cc_end_seq_get (krb5_context context, 711 const krb5_ccache id, 712 krb5_cc_cursor *cursor) 713 { 714 return (*id->ops->end_get)(context, id, cursor); 715 } 716 717 /** 718 * Remove the credential identified by `cred', `which' from `id'. 719 * 720 * @ingroup krb5_ccache 721 */ 722 723 724 krb5_error_code KRB5_LIB_FUNCTION 725 krb5_cc_remove_cred(krb5_context context, 726 krb5_ccache id, 727 krb5_flags which, 728 krb5_creds *cred) 729 { 730 if(id->ops->remove_cred == NULL) { 731 krb5_set_error_string(context, 732 "ccache %s does not support remove_cred", 733 id->ops->prefix); 734 return EACCES; /* XXX */ 735 } 736 return (*id->ops->remove_cred)(context, id, which, cred); 737 } 738 739 /** 740 * Set the flags of `id' to `flags'. 741 * 742 * @ingroup krb5_ccache 743 */ 744 745 746 krb5_error_code KRB5_LIB_FUNCTION 747 krb5_cc_set_flags(krb5_context context, 748 krb5_ccache id, 749 krb5_flags flags) 750 { 751 return (*id->ops->set_flags)(context, id, flags); 752 } 753 754 /** 755 * Copy the contents of `from' to `to'. 756 * 757 * @ingroup krb5_ccache 758 */ 759 760 761 krb5_error_code KRB5_LIB_FUNCTION 762 krb5_cc_copy_cache_match(krb5_context context, 763 const krb5_ccache from, 764 krb5_ccache to, 765 krb5_flags whichfields, 766 const krb5_creds * mcreds, 767 unsigned int *matched) 768 { 769 krb5_error_code ret; 770 krb5_cc_cursor cursor; 771 krb5_creds cred; 772 krb5_principal princ; 773 774 ret = krb5_cc_get_principal(context, from, &princ); 775 if (ret) 776 return ret; 777 ret = krb5_cc_initialize(context, to, princ); 778 if (ret) { 779 krb5_free_principal(context, princ); 780 return ret; 781 } 782 ret = krb5_cc_start_seq_get(context, from, &cursor); 783 if (ret) { 784 krb5_free_principal(context, princ); 785 return ret; 786 } 787 if (matched) 788 *matched = 0; 789 while (ret == 0 && 790 krb5_cc_next_cred_match(context, from, &cursor, &cred, 791 whichfields, mcreds) == 0) { 792 if (matched) 793 (*matched)++; 794 ret = krb5_cc_store_cred(context, to, &cred); 795 krb5_free_cred_contents(context, &cred); 796 } 797 krb5_cc_end_seq_get(context, from, &cursor); 798 krb5_free_principal(context, princ); 799 return ret; 800 } 801 802 /** 803 * Just like krb5_cc_copy_cache_match, but copy everything. 804 * 805 * @ingroup krb5_ccache 806 */ 807 808 809 krb5_error_code KRB5_LIB_FUNCTION 810 krb5_cc_copy_cache(krb5_context context, 811 const krb5_ccache from, 812 krb5_ccache to) 813 { 814 return krb5_cc_copy_cache_match(context, from, to, 0, NULL, NULL); 815 } 816 817 /** 818 * Return the version of `id'. 819 * 820 * @ingroup krb5_ccache 821 */ 822 823 824 krb5_error_code KRB5_LIB_FUNCTION 825 krb5_cc_get_version(krb5_context context, 826 const krb5_ccache id) 827 { 828 if(id->ops->get_version) 829 return (*id->ops->get_version)(context, id); 830 else 831 return 0; 832 } 833 834 /** 835 * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred 836 * 837 * @ingroup krb5_ccache 838 */ 839 840 841 void KRB5_LIB_FUNCTION 842 krb5_cc_clear_mcred(krb5_creds *mcred) 843 { 844 memset(mcred, 0, sizeof(*mcred)); 845 } 846 847 /** 848 * Get the cc ops that is registered in `context' to handle the 849 * `prefix'. `prefix' can be a complete credential cache name or a 850 * prefix, the function will only use part up to the first colon (:) 851 * if there is one. 852 * Returns NULL if ops not found. 853 * 854 * @ingroup krb5_ccache 855 */ 856 857 858 const krb5_cc_ops * 859 krb5_cc_get_prefix_ops(krb5_context context, const char *prefix) 860 { 861 char *p, *p1; 862 int i; 863 864 if (prefix[0] == '/') 865 return &krb5_fcc_ops; 866 867 p = strdup(prefix); 868 if (p == NULL) { 869 krb5_set_error_string(context, "malloc - out of memory"); 870 return NULL; 871 } 872 p1 = strchr(p, ':'); 873 if (p1) 874 *p1 = '\0'; 875 876 for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 877 if(strcmp(context->cc_ops[i].prefix, p) == 0) { 878 free(p); 879 return &context->cc_ops[i]; 880 } 881 } 882 free(p); 883 return NULL; 884 } 885 886 struct krb5_cc_cache_cursor_data { 887 const krb5_cc_ops *ops; 888 krb5_cc_cursor cursor; 889 }; 890 891 /** 892 * Start iterating over all caches of `type'. If `type' is NULL, the 893 * default type is * used. `cursor' is initialized to the beginning. 894 * 895 * @return Return 0 or an error code. 896 * 897 * @ingroup krb5_ccache 898 */ 899 900 901 krb5_error_code KRB5_LIB_FUNCTION 902 krb5_cc_cache_get_first (krb5_context context, 903 const char *type, 904 krb5_cc_cache_cursor *cursor) 905 { 906 const krb5_cc_ops *ops; 907 krb5_error_code ret; 908 909 if (type == NULL) 910 type = krb5_cc_default_name(context); 911 912 ops = krb5_cc_get_prefix_ops(context, type); 913 if (ops == NULL) { 914 krb5_set_error_string(context, "Unknown type \"%s\" when iterating " 915 "trying to iterate the credential caches", type); 916 return KRB5_CC_UNKNOWN_TYPE; 917 } 918 919 if (ops->get_cache_first == NULL) { 920 krb5_set_error_string(context, "Credential cache type %s doesn't support " 921 "iterations over caches", ops->prefix); 922 return KRB5_CC_NOSUPP; 923 } 924 925 *cursor = calloc(1, sizeof(**cursor)); 926 if (*cursor == NULL) { 927 krb5_set_error_string(context, "malloc - out of memory"); 928 return ENOMEM; 929 } 930 931 (*cursor)->ops = ops; 932 933 ret = ops->get_cache_first(context, &(*cursor)->cursor); 934 if (ret) { 935 free(*cursor); 936 *cursor = NULL; 937 } 938 return ret; 939 } 940 941 /** 942 * Retrieve the next cache pointed to by (`cursor') in `id' 943 * and advance `cursor'. 944 * 945 * @return Return 0 or an error code. 946 * 947 * @ingroup krb5_ccache 948 */ 949 950 951 krb5_error_code KRB5_LIB_FUNCTION 952 krb5_cc_cache_next (krb5_context context, 953 krb5_cc_cache_cursor cursor, 954 krb5_ccache *id) 955 { 956 return cursor->ops->get_cache_next(context, cursor->cursor, id); 957 } 958 959 /** 960 * Destroy the cursor `cursor'. 961 * 962 * @return Return 0 or an error code. 963 * 964 * @ingroup krb5_ccache 965 */ 966 967 968 krb5_error_code KRB5_LIB_FUNCTION 969 krb5_cc_cache_end_seq_get (krb5_context context, 970 krb5_cc_cache_cursor cursor) 971 { 972 krb5_error_code ret; 973 ret = cursor->ops->end_cache_get(context, cursor->cursor); 974 cursor->ops = NULL; 975 free(cursor); 976 return ret; 977 } 978 979 /** 980 * Search for a matching credential cache of type `type' that have the 981 * `principal' as the default principal. If NULL is used for `type', 982 * the default type is used. On success, `id' needs to be freed with 983 * krb5_cc_close or krb5_cc_destroy. 984 * 985 * @return On failure, error code is returned and `id' is set to NULL. 986 * 987 * @ingroup krb5_ccache 988 */ 989 990 991 krb5_error_code KRB5_LIB_FUNCTION 992 krb5_cc_cache_match (krb5_context context, 993 krb5_principal client, 994 const char *type, 995 krb5_ccache *id) 996 { 997 krb5_cc_cache_cursor cursor; 998 krb5_error_code ret; 999 krb5_ccache cache = NULL; 1000 1001 *id = NULL; 1002 1003 ret = krb5_cc_cache_get_first (context, type, &cursor); 1004 if (ret) 1005 return ret; 1006 1007 while ((ret = krb5_cc_cache_next (context, cursor, &cache)) == 0) { 1008 krb5_principal principal; 1009 1010 ret = krb5_cc_get_principal(context, cache, &principal); 1011 if (ret == 0) { 1012 krb5_boolean match; 1013 1014 match = krb5_principal_compare(context, principal, client); 1015 krb5_free_principal(context, principal); 1016 if (match) 1017 break; 1018 } 1019 1020 krb5_cc_close(context, cache); 1021 cache = NULL; 1022 } 1023 1024 krb5_cc_cache_end_seq_get(context, cursor); 1025 1026 if (cache == NULL) { 1027 char *str; 1028 1029 krb5_unparse_name(context, client, &str); 1030 1031 krb5_set_error_string(context, "Principal %s not found in a " 1032 "credential cache", str ? str : "<out of memory>"); 1033 if (str) 1034 free(str); 1035 return KRB5_CC_NOTFOUND; 1036 } 1037 *id = cache; 1038 1039 return 0; 1040 } 1041 1042 /** 1043 * Move the content from one credential cache to another. The 1044 * operation is an atomic switch. 1045 * 1046 * @param context a Keberos context 1047 * @param from the credential cache to move the content from 1048 * @param to the credential cache to move the content to 1049 1050 * @return On sucess, from is freed. On failure, error code is 1051 * returned and from and to are both still allocated. 1052 * 1053 * @ingroup krb5_ccache 1054 */ 1055 1056 krb5_error_code 1057 krb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 1058 { 1059 krb5_error_code ret; 1060 1061 if (strcmp(from->ops->prefix, to->ops->prefix) != 0) { 1062 krb5_set_error_string(context, "Moving credentials between diffrent " 1063 "types not yet supported"); 1064 return KRB5_CC_NOSUPP; 1065 } 1066 1067 ret = (*to->ops->move)(context, from, to); 1068 if (ret == 0) { 1069 memset(from, 0, sizeof(*from)); 1070 free(from); 1071 } 1072 return ret; 1073 } 1074