1/* $NetBSD: cache.c,v 1.1.1.1 2011/04/13 18:15:31 elric Exp $ */ 2 3/* 4 * Copyright (c) 1997 - 2008 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 40/** 41 * @page krb5_ccache_intro The credential cache functions 42 * @section section_krb5_ccache Kerberos credential caches 43 * 44 * krb5_ccache structure holds a Kerberos credential cache. 45 * 46 * Heimdal support the follow types of credential caches: 47 * 48 * - SCC 49 * Store the credential in a database 50 * - FILE 51 * Store the credential in memory 52 * - MEMORY 53 * Store the credential in memory 54 * - API 55 * A credential cache server based solution for Mac OS X 56 * - KCM 57 * A credential cache server based solution for all platforms 58 * 59 * @subsection Example 60 * 61 * This is a minimalistic version of klist: 62@code 63#include <krb5/krb5.h> 64 65int 66main (int argc, char **argv) 67{ 68 krb5_context context; 69 krb5_cc_cursor cursor; 70 krb5_error_code ret; 71 krb5_ccache id; 72 krb5_creds creds; 73 74 if (krb5_init_context (&context) != 0) 75 errx(1, "krb5_context"); 76 77 ret = krb5_cc_default (context, &id); 78 if (ret) 79 krb5_err(context, 1, ret, "krb5_cc_default"); 80 81 ret = krb5_cc_start_seq_get(context, id, &cursor); 82 if (ret) 83 krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); 84 85 while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){ 86 char *principal; 87 88 krb5_unparse_name(context, creds.server, &principal); 89 printf("principal: %s\\n", principal); 90 free(principal); 91 krb5_free_cred_contents (context, &creds); 92 } 93 ret = krb5_cc_end_seq_get(context, id, &cursor); 94 if (ret) 95 krb5_err(context, 1, ret, "krb5_cc_end_seq_get"); 96 97 krb5_cc_close(context, id); 98 99 krb5_free_context(context); 100 return 0; 101} 102* @endcode 103*/ 104 105/** 106 * Add a new ccache type with operations `ops', overwriting any 107 * existing one if `override'. 108 * 109 * @param context a Keberos context 110 * @param ops type of plugin symbol 111 * @param override flag to select if the registration is to overide 112 * an existing ops with the same name. 113 * 114 * @return Return an error code or 0, see krb5_get_error_message(). 115 * 116 * @ingroup krb5_ccache 117 */ 118 119KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 120krb5_cc_register(krb5_context context, 121 const krb5_cc_ops *ops, 122 krb5_boolean override) 123{ 124 int i; 125 126 for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { 127 if(strcmp(context->cc_ops[i]->prefix, ops->prefix) == 0) { 128 if(!override) { 129 krb5_set_error_message(context, 130 KRB5_CC_TYPE_EXISTS, 131 N_("cache type %s already exists", "type"), 132 ops->prefix); 133 return KRB5_CC_TYPE_EXISTS; 134 } 135 break; 136 } 137 } 138 if(i == context->num_cc_ops) { 139 const krb5_cc_ops **o = realloc(rk_UNCONST(context->cc_ops), 140 (context->num_cc_ops + 1) * 141 sizeof(context->cc_ops[0])); 142 if(o == NULL) { 143 krb5_set_error_message(context, KRB5_CC_NOMEM, 144 N_("malloc: out of memory", "")); 145 return KRB5_CC_NOMEM; 146 } 147 context->cc_ops = o; 148 context->cc_ops[context->num_cc_ops] = NULL; 149 context->num_cc_ops++; 150 } 151 context->cc_ops[i] = ops; 152 return 0; 153} 154 155/* 156 * Allocate the memory for a `id' and the that function table to 157 * `ops'. Returns 0 or and error code. 158 */ 159 160krb5_error_code 161_krb5_cc_allocate(krb5_context context, 162 const krb5_cc_ops *ops, 163 krb5_ccache *id) 164{ 165 krb5_ccache p; 166 167 p = malloc (sizeof(*p)); 168 if(p == NULL) { 169 krb5_set_error_message(context, KRB5_CC_NOMEM, 170 N_("malloc: out of memory", "")); 171 return KRB5_CC_NOMEM; 172 } 173 p->ops = ops; 174 *id = p; 175 176 return 0; 177} 178 179/* 180 * Allocate memory for a new ccache in `id' with operations `ops' 181 * and name `residual'. Return 0 or an error code. 182 */ 183 184static krb5_error_code 185allocate_ccache (krb5_context context, 186 const krb5_cc_ops *ops, 187 const char *residual, 188 krb5_ccache *id) 189{ 190 krb5_error_code ret; 191#ifdef KRB5_USE_PATH_TOKENS 192 char * exp_residual = NULL; 193 194 ret = _krb5_expand_path_tokens(context, residual, &exp_residual); 195 if (ret) 196 return ret; 197 198 residual = exp_residual; 199#endif 200 201 ret = _krb5_cc_allocate(context, ops, id); 202 if (ret) { 203#ifdef KRB5_USE_PATH_TOKENS 204 if (exp_residual) 205 free(exp_residual); 206#endif 207 return ret; 208 } 209 210 ret = (*id)->ops->resolve(context, id, residual); 211 if(ret) { 212 free(*id); 213 *id = NULL; 214 } 215 216#ifdef KRB5_USE_PATH_TOKENS 217 if (exp_residual) 218 free(exp_residual); 219#endif 220 221 return ret; 222} 223 224static int 225is_possible_path_name(const char * name) 226{ 227 const char * colon; 228 229 if ((colon = strchr(name, ':')) == NULL) 230 return TRUE; 231 232#ifdef _WIN32 233 /* <drive letter>:\path\to\cache ? */ 234 235 if (colon == name + 1 && 236 strchr(colon + 1, ':') == NULL) 237 return TRUE; 238#endif 239 240 return FALSE; 241} 242 243/** 244 * Find and allocate a ccache in `id' from the specification in `residual'. 245 * If the ccache name doesn't contain any colon, interpret it as a file name. 246 * 247 * @param context a Keberos context. 248 * @param name string name of a credential cache. 249 * @param id return pointer to a found credential cache. 250 * 251 * @return Return 0 or an error code. In case of an error, id is set 252 * to NULL, see krb5_get_error_message(). 253 * 254 * @ingroup krb5_ccache 255 */ 256 257 258KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 259krb5_cc_resolve(krb5_context context, 260 const char *name, 261 krb5_ccache *id) 262{ 263 int i; 264 265 *id = NULL; 266 267 for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { 268 size_t prefix_len = strlen(context->cc_ops[i]->prefix); 269 270 if(strncmp(context->cc_ops[i]->prefix, name, prefix_len) == 0 271 && name[prefix_len] == ':') { 272 return allocate_ccache (context, context->cc_ops[i], 273 name + prefix_len + 1, 274 id); 275 } 276 } 277 if (is_possible_path_name(name)) 278 return allocate_ccache (context, &krb5_fcc_ops, name, id); 279 else { 280 krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 281 N_("unknown ccache type %s", "name"), name); 282 return KRB5_CC_UNKNOWN_TYPE; 283 } 284} 285 286/** 287 * Generates a new unique ccache of `type` in `id'. If `type' is NULL, 288 * the library chooses the default credential cache type. The supplied 289 * `hint' (that can be NULL) is a string that the credential cache 290 * type can use to base the name of the credential on, this is to make 291 * it easier for the user to differentiate the credentials. 292 * 293 * @return Return an error code or 0, see krb5_get_error_message(). 294 * 295 * @ingroup krb5_ccache 296 */ 297 298KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 299krb5_cc_new_unique(krb5_context context, const char *type, 300 const char *hint, krb5_ccache *id) 301{ 302 const krb5_cc_ops *ops; 303 krb5_error_code ret; 304 305 ops = krb5_cc_get_prefix_ops(context, type); 306 if (ops == NULL) { 307 krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 308 "Credential cache type %s is unknown", type); 309 return KRB5_CC_UNKNOWN_TYPE; 310 } 311 312 ret = _krb5_cc_allocate(context, ops, id); 313 if (ret) 314 return ret; 315 ret = (*id)->ops->gen_new(context, id); 316 if (ret) { 317 free(*id); 318 *id = NULL; 319 } 320 return ret; 321} 322 323/** 324 * Return the name of the ccache `id' 325 * 326 * @ingroup krb5_ccache 327 */ 328 329 330KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 331krb5_cc_get_name(krb5_context context, 332 krb5_ccache id) 333{ 334 return id->ops->get_name(context, id); 335} 336 337/** 338 * Return the type of the ccache `id'. 339 * 340 * @ingroup krb5_ccache 341 */ 342 343 344KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 345krb5_cc_get_type(krb5_context context, 346 krb5_ccache id) 347{ 348 return id->ops->prefix; 349} 350 351/** 352 * Return the complete resolvable name the cache 353 354 * @param context a Keberos context 355 * @param id return pointer to a found credential cache 356 * @param str the returned name of a credential cache, free with krb5_xfree() 357 * 358 * @return Returns 0 or an error (and then *str is set to NULL). 359 * 360 * @ingroup krb5_ccache 361 */ 362 363 364KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 365krb5_cc_get_full_name(krb5_context context, 366 krb5_ccache id, 367 char **str) 368{ 369 const char *type, *name; 370 371 *str = NULL; 372 373 type = krb5_cc_get_type(context, id); 374 if (type == NULL) { 375 krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 376 "cache have no name of type"); 377 return KRB5_CC_UNKNOWN_TYPE; 378 } 379 380 name = krb5_cc_get_name(context, id); 381 if (name == NULL) { 382 krb5_set_error_message(context, KRB5_CC_BADNAME, 383 "cache of type %s have no name", type); 384 return KRB5_CC_BADNAME; 385 } 386 387 if (asprintf(str, "%s:%s", type, name) == -1) { 388 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 389 *str = NULL; 390 return ENOMEM; 391 } 392 return 0; 393} 394 395/** 396 * Return krb5_cc_ops of a the ccache `id'. 397 * 398 * @ingroup krb5_ccache 399 */ 400 401 402KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL 403krb5_cc_get_ops(krb5_context context, krb5_ccache id) 404{ 405 return id->ops; 406} 407 408/* 409 * Expand variables in `str' into `res' 410 */ 411 412krb5_error_code 413_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res) 414{ 415 return _krb5_expand_path_tokens(context, str, res); 416} 417 418/* 419 * Return non-zero if envirnoment that will determine default krb5cc 420 * name has changed. 421 */ 422 423static int 424environment_changed(krb5_context context) 425{ 426 const char *e; 427 428 /* if the cc name was set, don't change it */ 429 if (context->default_cc_name_set) 430 return 0; 431 432 /* XXX performance: always ask KCM/API if default name has changed */ 433 if (context->default_cc_name && 434 (strncmp(context->default_cc_name, "KCM:", 4) == 0 || 435 strncmp(context->default_cc_name, "API:", 4) == 0)) 436 return 1; 437 438 if(issuid()) 439 return 0; 440 441 e = getenv("KRB5CCNAME"); 442 if (e == NULL) { 443 if (context->default_cc_name_env) { 444 free(context->default_cc_name_env); 445 context->default_cc_name_env = NULL; 446 return 1; 447 } 448 } else { 449 if (context->default_cc_name_env == NULL) 450 return 1; 451 if (strcmp(e, context->default_cc_name_env) != 0) 452 return 1; 453 } 454 return 0; 455} 456 457/** 458 * Switch the default default credential cache for a specific 459 * credcache type (and name for some implementations). 460 * 461 * @return Return an error code or 0, see krb5_get_error_message(). 462 * 463 * @ingroup krb5_ccache 464 */ 465 466KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 467krb5_cc_switch(krb5_context context, krb5_ccache id) 468{ 469 470 if (id->ops->set_default == NULL) 471 return 0; 472 473 return (*id->ops->set_default)(context, id); 474} 475 476/** 477 * Return true if the default credential cache support switch 478 * 479 * @ingroup krb5_ccache 480 */ 481 482KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 483krb5_cc_support_switch(krb5_context context, const char *type) 484{ 485 const krb5_cc_ops *ops; 486 487 ops = krb5_cc_get_prefix_ops(context, type); 488 if (ops && ops->set_default) 489 return 1; 490 return FALSE; 491} 492 493/** 494 * Set the default cc name for `context' to `name'. 495 * 496 * @ingroup krb5_ccache 497 */ 498 499KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 500krb5_cc_set_default_name(krb5_context context, const char *name) 501{ 502 krb5_error_code ret = 0; 503 char *p = NULL, *exp_p = NULL; 504 505 if (name == NULL) { 506 const char *e = NULL; 507 508 if(!issuid()) { 509 e = getenv("KRB5CCNAME"); 510 if (e) { 511 p = strdup(e); 512 if (context->default_cc_name_env) 513 free(context->default_cc_name_env); 514 context->default_cc_name_env = strdup(e); 515 } 516 } 517 518#ifdef _WIN32 519 if (e == NULL) { 520 e = p = _krb5_get_default_cc_name_from_registry(); 521 } 522#endif 523 if (e == NULL) { 524 e = krb5_config_get_string(context, NULL, "libdefaults", 525 "default_cc_name", NULL); 526 if (e) { 527 ret = _krb5_expand_default_cc_name(context, e, &p); 528 if (ret) 529 return ret; 530 } 531 if (e == NULL) { 532 const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE; 533 e = krb5_config_get_string(context, NULL, "libdefaults", 534 "default_cc_type", NULL); 535 if (e) { 536 ops = krb5_cc_get_prefix_ops(context, e); 537 if (ops == NULL) { 538 krb5_set_error_message(context, 539 KRB5_CC_UNKNOWN_TYPE, 540 "Credential cache type %s " 541 "is unknown", e); 542 return KRB5_CC_UNKNOWN_TYPE; 543 } 544 } 545 ret = (*ops->get_default_name)(context, &p); 546 if (ret) 547 return ret; 548 } 549 } 550 context->default_cc_name_set = 0; 551 } else { 552 p = strdup(name); 553 context->default_cc_name_set = 1; 554 } 555 556 if (p == NULL) { 557 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 558 return ENOMEM; 559 } 560 561 ret = _krb5_expand_path_tokens(context, p, &exp_p); 562 free(p); 563 if (ret) 564 return ret; 565 566 if (context->default_cc_name) 567 free(context->default_cc_name); 568 569 context->default_cc_name = exp_p; 570 571 return 0; 572} 573 574/** 575 * Return a pointer to a context static string containing the default 576 * ccache name. 577 * 578 * @return String to the default credential cache name. 579 * 580 * @ingroup krb5_ccache 581 */ 582 583 584KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 585krb5_cc_default_name(krb5_context context) 586{ 587 if (context->default_cc_name == NULL || environment_changed(context)) 588 krb5_cc_set_default_name(context, NULL); 589 590 return context->default_cc_name; 591} 592 593/** 594 * Open the default ccache in `id'. 595 * 596 * @return Return an error code or 0, see krb5_get_error_message(). 597 * 598 * @ingroup krb5_ccache 599 */ 600 601 602KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 603krb5_cc_default(krb5_context context, 604 krb5_ccache *id) 605{ 606 const char *p = krb5_cc_default_name(context); 607 608 if (p == NULL) { 609 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 610 return ENOMEM; 611 } 612 return krb5_cc_resolve(context, p, id); 613} 614 615/** 616 * Create a new ccache in `id' for `primary_principal'. 617 * 618 * @return Return an error code or 0, see krb5_get_error_message(). 619 * 620 * @ingroup krb5_ccache 621 */ 622 623 624KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 625krb5_cc_initialize(krb5_context context, 626 krb5_ccache id, 627 krb5_principal primary_principal) 628{ 629 return (*id->ops->init)(context, id, primary_principal); 630} 631 632 633/** 634 * Remove the ccache `id'. 635 * 636 * @return Return an error code or 0, see krb5_get_error_message(). 637 * 638 * @ingroup krb5_ccache 639 */ 640 641 642KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 643krb5_cc_destroy(krb5_context context, 644 krb5_ccache id) 645{ 646 krb5_error_code ret; 647 648 ret = (*id->ops->destroy)(context, id); 649 krb5_cc_close (context, id); 650 return ret; 651} 652 653/** 654 * Stop using the ccache `id' and free the related resources. 655 * 656 * @return Return an error code or 0, see krb5_get_error_message(). 657 * 658 * @ingroup krb5_ccache 659 */ 660 661 662KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 663krb5_cc_close(krb5_context context, 664 krb5_ccache id) 665{ 666 krb5_error_code ret; 667 ret = (*id->ops->close)(context, id); 668 free(id); 669 return ret; 670} 671 672/** 673 * Store `creds' in the ccache `id'. 674 * 675 * @return Return an error code or 0, see krb5_get_error_message(). 676 * 677 * @ingroup krb5_ccache 678 */ 679 680 681KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 682krb5_cc_store_cred(krb5_context context, 683 krb5_ccache id, 684 krb5_creds *creds) 685{ 686 return (*id->ops->store)(context, id, creds); 687} 688 689/** 690 * Retrieve the credential identified by `mcreds' (and `whichfields') 691 * from `id' in `creds'. 'creds' must be free by the caller using 692 * krb5_free_cred_contents. 693 * 694 * @param context A Kerberos 5 context 695 * @param id a Kerberos 5 credential cache 696 * @param whichfields what fields to use for matching credentials, same 697 * flags as whichfields in krb5_compare_creds() 698 * @param mcreds template credential to use for comparing 699 * @param creds returned credential, free with krb5_free_cred_contents() 700 * 701 * @return Return an error code or 0, see krb5_get_error_message(). 702 * 703 * @ingroup krb5_ccache 704 */ 705 706 707KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 708krb5_cc_retrieve_cred(krb5_context context, 709 krb5_ccache id, 710 krb5_flags whichfields, 711 const krb5_creds *mcreds, 712 krb5_creds *creds) 713{ 714 krb5_error_code ret; 715 krb5_cc_cursor cursor; 716 717 if (id->ops->retrieve != NULL) { 718 return (*id->ops->retrieve)(context, id, whichfields, 719 mcreds, creds); 720 } 721 722 ret = krb5_cc_start_seq_get(context, id, &cursor); 723 if (ret) 724 return ret; 725 while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){ 726 if(krb5_compare_creds(context, whichfields, mcreds, creds)){ 727 ret = 0; 728 break; 729 } 730 krb5_free_cred_contents (context, creds); 731 } 732 krb5_cc_end_seq_get(context, id, &cursor); 733 return ret; 734} 735 736/** 737 * Return the principal of `id' in `principal'. 738 * 739 * @return Return an error code or 0, see krb5_get_error_message(). 740 * 741 * @ingroup krb5_ccache 742 */ 743 744 745KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 746krb5_cc_get_principal(krb5_context context, 747 krb5_ccache id, 748 krb5_principal *principal) 749{ 750 return (*id->ops->get_princ)(context, id, principal); 751} 752 753/** 754 * Start iterating over `id', `cursor' is initialized to the 755 * beginning. Caller must free the cursor with krb5_cc_end_seq_get(). 756 * 757 * @return Return an error code or 0, see krb5_get_error_message(). 758 * 759 * @ingroup krb5_ccache 760 */ 761 762 763KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 764krb5_cc_start_seq_get (krb5_context context, 765 const krb5_ccache id, 766 krb5_cc_cursor *cursor) 767{ 768 return (*id->ops->get_first)(context, id, cursor); 769} 770 771/** 772 * Retrieve the next cred pointed to by (`id', `cursor') in `creds' 773 * and advance `cursor'. 774 * 775 * @return Return an error code or 0, see krb5_get_error_message(). 776 * 777 * @ingroup krb5_ccache 778 */ 779 780 781KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 782krb5_cc_next_cred (krb5_context context, 783 const krb5_ccache id, 784 krb5_cc_cursor *cursor, 785 krb5_creds *creds) 786{ 787 return (*id->ops->get_next)(context, id, cursor, creds); 788} 789 790/** 791 * Destroy the cursor `cursor'. 792 * 793 * @ingroup krb5_ccache 794 */ 795 796 797KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 798krb5_cc_end_seq_get (krb5_context context, 799 const krb5_ccache id, 800 krb5_cc_cursor *cursor) 801{ 802 return (*id->ops->end_get)(context, id, cursor); 803} 804 805/** 806 * Remove the credential identified by `cred', `which' from `id'. 807 * 808 * @ingroup krb5_ccache 809 */ 810 811 812KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 813krb5_cc_remove_cred(krb5_context context, 814 krb5_ccache id, 815 krb5_flags which, 816 krb5_creds *cred) 817{ 818 if(id->ops->remove_cred == NULL) { 819 krb5_set_error_message(context, 820 EACCES, 821 "ccache %s does not support remove_cred", 822 id->ops->prefix); 823 return EACCES; /* XXX */ 824 } 825 return (*id->ops->remove_cred)(context, id, which, cred); 826} 827 828/** 829 * Set the flags of `id' to `flags'. 830 * 831 * @ingroup krb5_ccache 832 */ 833 834 835KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 836krb5_cc_set_flags(krb5_context context, 837 krb5_ccache id, 838 krb5_flags flags) 839{ 840 return (*id->ops->set_flags)(context, id, flags); 841} 842 843/** 844 * Get the flags of `id', store them in `flags'. 845 * 846 * @ingroup krb5_ccache 847 */ 848 849KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 850krb5_cc_get_flags(krb5_context context, 851 krb5_ccache id, 852 krb5_flags *flags) 853{ 854 *flags = 0; 855 return 0; 856} 857 858/** 859 * Copy the contents of `from' to `to' if the given match function 860 * return true. 861 * 862 * @param context A Kerberos 5 context. 863 * @param from the cache to copy data from. 864 * @param to the cache to copy data to. 865 * @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied. 866 * @param matchctx context passed to match function. 867 * @param matched set to true if there was a credential that matched, may be NULL. 868 * 869 * @return Return an error code or 0, see krb5_get_error_message(). 870 * 871 * @ingroup krb5_ccache 872 */ 873 874KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 875krb5_cc_copy_match_f(krb5_context context, 876 const krb5_ccache from, 877 krb5_ccache to, 878 krb5_boolean (*match)(krb5_context, void *, const krb5_creds *), 879 void *matchctx, 880 unsigned int *matched) 881{ 882 krb5_error_code ret; 883 krb5_cc_cursor cursor; 884 krb5_creds cred; 885 krb5_principal princ; 886 887 if (matched) 888 *matched = 0; 889 890 ret = krb5_cc_get_principal(context, from, &princ); 891 if (ret) 892 return ret; 893 ret = krb5_cc_initialize(context, to, princ); 894 if (ret) { 895 krb5_free_principal(context, princ); 896 return ret; 897 } 898 ret = krb5_cc_start_seq_get(context, from, &cursor); 899 if (ret) { 900 krb5_free_principal(context, princ); 901 return ret; 902 } 903 904 while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) { 905 if (match == NULL || (*match)(context, matchctx, &cred) == 0) { 906 if (matched) 907 (*matched)++; 908 ret = krb5_cc_store_cred(context, to, &cred); 909 if (ret) 910 break; 911 } 912 krb5_free_cred_contents(context, &cred); 913 } 914 krb5_cc_end_seq_get(context, from, &cursor); 915 krb5_free_principal(context, princ); 916 if (ret == KRB5_CC_END) 917 ret = 0; 918 return ret; 919} 920 921/** 922 * Just like krb5_cc_copy_match_f(), but copy everything. 923 * 924 * @ingroup @krb5_ccache 925 */ 926 927KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 928krb5_cc_copy_cache(krb5_context context, 929 const krb5_ccache from, 930 krb5_ccache to) 931{ 932 return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL); 933} 934 935/** 936 * Return the version of `id'. 937 * 938 * @ingroup krb5_ccache 939 */ 940 941 942KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 943krb5_cc_get_version(krb5_context context, 944 const krb5_ccache id) 945{ 946 if(id->ops->get_version) 947 return (*id->ops->get_version)(context, id); 948 else 949 return 0; 950} 951 952/** 953 * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred 954 * 955 * @ingroup krb5_ccache 956 */ 957 958 959KRB5_LIB_FUNCTION void KRB5_LIB_CALL 960krb5_cc_clear_mcred(krb5_creds *mcred) 961{ 962 memset(mcred, 0, sizeof(*mcred)); 963} 964 965/** 966 * Get the cc ops that is registered in `context' to handle the 967 * prefix. prefix can be a complete credential cache name or a 968 * prefix, the function will only use part up to the first colon (:) 969 * if there is one. If prefix the argument is NULL, the default ccache 970 * implemtation is returned. 971 * 972 * @return Returns NULL if ops not found. 973 * 974 * @ingroup krb5_ccache 975 */ 976 977 978KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL 979krb5_cc_get_prefix_ops(krb5_context context, const char *prefix) 980{ 981 char *p, *p1; 982 int i; 983 984 if (prefix == NULL) 985 return KRB5_DEFAULT_CCTYPE; 986 if (prefix[0] == '/') 987 return &krb5_fcc_ops; 988 989 p = strdup(prefix); 990 if (p == NULL) { 991 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 992 return NULL; 993 } 994 p1 = strchr(p, ':'); 995 if (p1) 996 *p1 = '\0'; 997 998 for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { 999 if(strcmp(context->cc_ops[i]->prefix, p) == 0) { 1000 free(p); 1001 return context->cc_ops[i]; 1002 } 1003 } 1004 free(p); 1005 return NULL; 1006} 1007 1008struct krb5_cc_cache_cursor_data { 1009 const krb5_cc_ops *ops; 1010 krb5_cc_cursor cursor; 1011}; 1012 1013/** 1014 * Start iterating over all caches of specified type. See also 1015 * krb5_cccol_cursor_new(). 1016 1017 * @param context A Kerberos 5 context 1018 * @param type optional type to iterate over, if NULL, the default cache is used. 1019 * @param cursor cursor should be freed with krb5_cc_cache_end_seq_get(). 1020 * 1021 * @return Return an error code or 0, see krb5_get_error_message(). 1022 * 1023 * @ingroup krb5_ccache 1024 */ 1025 1026 1027KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1028krb5_cc_cache_get_first (krb5_context context, 1029 const char *type, 1030 krb5_cc_cache_cursor *cursor) 1031{ 1032 const krb5_cc_ops *ops; 1033 krb5_error_code ret; 1034 1035 if (type == NULL) 1036 type = krb5_cc_default_name(context); 1037 1038 ops = krb5_cc_get_prefix_ops(context, type); 1039 if (ops == NULL) { 1040 krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 1041 "Unknown type \"%s\" when iterating " 1042 "trying to iterate the credential caches", type); 1043 return KRB5_CC_UNKNOWN_TYPE; 1044 } 1045 1046 if (ops->get_cache_first == NULL) { 1047 krb5_set_error_message(context, KRB5_CC_NOSUPP, 1048 N_("Credential cache type %s doesn't support " 1049 "iterations over caches", "type"), 1050 ops->prefix); 1051 return KRB5_CC_NOSUPP; 1052 } 1053 1054 *cursor = calloc(1, sizeof(**cursor)); 1055 if (*cursor == NULL) { 1056 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1057 return ENOMEM; 1058 } 1059 1060 (*cursor)->ops = ops; 1061 1062 ret = ops->get_cache_first(context, &(*cursor)->cursor); 1063 if (ret) { 1064 free(*cursor); 1065 *cursor = NULL; 1066 } 1067 return ret; 1068} 1069 1070/** 1071 * Retrieve the next cache pointed to by (`cursor') in `id' 1072 * and advance `cursor'. 1073 * 1074 * @param context A Kerberos 5 context 1075 * @param cursor the iterator cursor, returned by krb5_cc_cache_get_first() 1076 * @param id next ccache 1077 * 1078 * @return Return 0 or an error code. Returns KRB5_CC_END when the end 1079 * of caches is reached, see krb5_get_error_message(). 1080 * 1081 * @ingroup krb5_ccache 1082 */ 1083 1084 1085KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1086krb5_cc_cache_next (krb5_context context, 1087 krb5_cc_cache_cursor cursor, 1088 krb5_ccache *id) 1089{ 1090 return cursor->ops->get_cache_next(context, cursor->cursor, id); 1091} 1092 1093/** 1094 * Destroy the cursor `cursor'. 1095 * 1096 * @return Return an error code or 0, see krb5_get_error_message(). 1097 * 1098 * @ingroup krb5_ccache 1099 */ 1100 1101 1102KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1103krb5_cc_cache_end_seq_get (krb5_context context, 1104 krb5_cc_cache_cursor cursor) 1105{ 1106 krb5_error_code ret; 1107 ret = cursor->ops->end_cache_get(context, cursor->cursor); 1108 cursor->ops = NULL; 1109 free(cursor); 1110 return ret; 1111} 1112 1113/** 1114 * Search for a matching credential cache that have the 1115 * `principal' as the default principal. On success, `id' needs to be 1116 * freed with krb5_cc_close() or krb5_cc_destroy(). 1117 * 1118 * @param context A Kerberos 5 context 1119 * @param client The principal to search for 1120 * @param id the returned credential cache 1121 * 1122 * @return On failure, error code is returned and `id' is set to NULL. 1123 * 1124 * @ingroup krb5_ccache 1125 */ 1126 1127 1128KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1129krb5_cc_cache_match (krb5_context context, 1130 krb5_principal client, 1131 krb5_ccache *id) 1132{ 1133 krb5_cccol_cursor cursor; 1134 krb5_error_code ret; 1135 krb5_ccache cache = NULL; 1136 1137 *id = NULL; 1138 1139 ret = krb5_cccol_cursor_new (context, &cursor); 1140 if (ret) 1141 return ret; 1142 1143 while (krb5_cccol_cursor_next (context, cursor, &cache) == 0 && cache != NULL) { 1144 krb5_principal principal; 1145 1146 ret = krb5_cc_get_principal(context, cache, &principal); 1147 if (ret == 0) { 1148 krb5_boolean match; 1149 1150 match = krb5_principal_compare(context, principal, client); 1151 krb5_free_principal(context, principal); 1152 if (match) 1153 break; 1154 } 1155 1156 krb5_cc_close(context, cache); 1157 cache = NULL; 1158 } 1159 1160 krb5_cccol_cursor_free(context, &cursor); 1161 1162 if (cache == NULL) { 1163 char *str; 1164 1165 krb5_unparse_name(context, client, &str); 1166 1167 krb5_set_error_message(context, KRB5_CC_NOTFOUND, 1168 N_("Principal %s not found in any " 1169 "credential cache", ""), 1170 str ? str : "<out of memory>"); 1171 if (str) 1172 free(str); 1173 return KRB5_CC_NOTFOUND; 1174 } 1175 *id = cache; 1176 1177 return 0; 1178} 1179 1180/** 1181 * Move the content from one credential cache to another. The 1182 * operation is an atomic switch. 1183 * 1184 * @param context a Keberos context 1185 * @param from the credential cache to move the content from 1186 * @param to the credential cache to move the content to 1187 1188 * @return On sucess, from is freed. On failure, error code is 1189 * returned and from and to are both still allocated, see krb5_get_error_message(). 1190 * 1191 * @ingroup krb5_ccache 1192 */ 1193 1194KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1195krb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 1196{ 1197 krb5_error_code ret; 1198 1199 if (strcmp(from->ops->prefix, to->ops->prefix) != 0) { 1200 krb5_set_error_message(context, KRB5_CC_NOSUPP, 1201 N_("Moving credentials between diffrent " 1202 "types not yet supported", "")); 1203 return KRB5_CC_NOSUPP; 1204 } 1205 1206 ret = (*to->ops->move)(context, from, to); 1207 if (ret == 0) { 1208 memset(from, 0, sizeof(*from)); 1209 free(from); 1210 } 1211 return ret; 1212} 1213 1214#define KRB5_CONF_NAME "krb5_ccache_conf_data" 1215#define KRB5_REALM_NAME "X-CACHECONF:" 1216 1217static krb5_error_code 1218build_conf_principals(krb5_context context, krb5_ccache id, 1219 krb5_const_principal principal, 1220 const char *name, krb5_creds *cred) 1221{ 1222 krb5_principal client; 1223 krb5_error_code ret; 1224 char *pname = NULL; 1225 1226 memset(cred, 0, sizeof(*cred)); 1227 1228 ret = krb5_cc_get_principal(context, id, &client); 1229 if (ret) 1230 return ret; 1231 1232 if (principal) { 1233 ret = krb5_unparse_name(context, principal, &pname); 1234 if (ret) 1235 return ret; 1236 } 1237 1238 ret = krb5_make_principal(context, &cred->server, 1239 KRB5_REALM_NAME, 1240 KRB5_CONF_NAME, name, pname, NULL); 1241 free(pname); 1242 if (ret) { 1243 krb5_free_principal(context, client); 1244 return ret; 1245 } 1246 ret = krb5_copy_principal(context, client, &cred->client); 1247 krb5_free_principal(context, client); 1248 return ret; 1249} 1250 1251/** 1252 * Return TRUE (non zero) if the principal is a configuration 1253 * principal (generated part of krb5_cc_set_config()). Returns FALSE 1254 * (zero) if not a configuration principal. 1255 * 1256 * @param context a Keberos context 1257 * @param principal principal to check if it a configuration principal 1258 * 1259 * @ingroup krb5_ccache 1260 */ 1261 1262KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1263krb5_is_config_principal(krb5_context context, 1264 krb5_const_principal principal) 1265{ 1266 if (strcmp(principal->realm, KRB5_REALM_NAME) != 0) 1267 return FALSE; 1268 1269 if (principal->name.name_string.len == 0 || 1270 strcmp(principal->name.name_string.val[0], KRB5_CONF_NAME) != 0) 1271 return FALSE; 1272 1273 return TRUE; 1274} 1275 1276/** 1277 * Store some configuration for the credential cache in the cache. 1278 * Existing configuration under the same name is over-written. 1279 * 1280 * @param context a Keberos context 1281 * @param id the credential cache to store the data for 1282 * @param principal configuration for a specific principal, if 1283 * NULL, global for the whole cache. 1284 * @param name name under which the configuraion is stored. 1285 * @param data data to store, if NULL, configure is removed. 1286 * 1287 * @ingroup krb5_ccache 1288 */ 1289 1290KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1291krb5_cc_set_config(krb5_context context, krb5_ccache id, 1292 krb5_const_principal principal, 1293 const char *name, krb5_data *data) 1294{ 1295 krb5_error_code ret; 1296 krb5_creds cred; 1297 1298 ret = build_conf_principals(context, id, principal, name, &cred); 1299 if (ret) 1300 goto out; 1301 1302 /* Remove old configuration */ 1303 ret = krb5_cc_remove_cred(context, id, 0, &cred); 1304 if (ret && ret != KRB5_CC_NOTFOUND) 1305 goto out; 1306 1307 if (data) { 1308 /* not that anyone care when this expire */ 1309 cred.times.authtime = time(NULL); 1310 cred.times.endtime = cred.times.authtime + 3600 * 24 * 30; 1311 1312 ret = krb5_data_copy(&cred.ticket, data->data, data->length); 1313 if (ret) 1314 goto out; 1315 1316 ret = krb5_cc_store_cred(context, id, &cred); 1317 } 1318 1319out: 1320 krb5_free_cred_contents (context, &cred); 1321 return ret; 1322} 1323 1324/** 1325 * Get some configuration for the credential cache in the cache. 1326 * 1327 * @param context a Keberos context 1328 * @param id the credential cache to store the data for 1329 * @param principal configuration for a specific principal, if 1330 * NULL, global for the whole cache. 1331 * @param name name under which the configuraion is stored. 1332 * @param data data to fetched, free with krb5_data_free() 1333 * 1334 * @ingroup krb5_ccache 1335 */ 1336 1337 1338KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1339krb5_cc_get_config(krb5_context context, krb5_ccache id, 1340 krb5_const_principal principal, 1341 const char *name, krb5_data *data) 1342{ 1343 krb5_creds mcred, cred; 1344 krb5_error_code ret; 1345 1346 memset(&cred, 0, sizeof(cred)); 1347 krb5_data_zero(data); 1348 1349 ret = build_conf_principals(context, id, principal, name, &mcred); 1350 if (ret) 1351 goto out; 1352 1353 ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred); 1354 if (ret) 1355 goto out; 1356 1357 ret = krb5_data_copy(data, cred.ticket.data, cred.ticket.length); 1358 1359out: 1360 krb5_free_cred_contents (context, &cred); 1361 krb5_free_cred_contents (context, &mcred); 1362 return ret; 1363} 1364 1365/* 1366 * 1367 */ 1368 1369struct krb5_cccol_cursor_data { 1370 int idx; 1371 krb5_cc_cache_cursor cursor; 1372}; 1373 1374/** 1375 * Get a new cache interation cursor that will interate over all 1376 * credentials caches independent of type. 1377 * 1378 * @param context a Keberos context 1379 * @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free(). 1380 * 1381 * @return Returns 0 or and error code, see krb5_get_error_message(). 1382 * 1383 * @ingroup krb5_ccache 1384 */ 1385 1386KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1387krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor) 1388{ 1389 *cursor = calloc(1, sizeof(**cursor)); 1390 if (*cursor == NULL) { 1391 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1392 return ENOMEM; 1393 } 1394 (*cursor)->idx = 0; 1395 (*cursor)->cursor = NULL; 1396 1397 return 0; 1398} 1399 1400/** 1401 * Get next credential cache from the iteration. 1402 * 1403 * @param context A Kerberos 5 context 1404 * @param cursor the iteration cursor 1405 * @param cache the returned cursor, pointer is set to NULL on failure 1406 * and a cache on success. The returned cache needs to be freed 1407 * with krb5_cc_close() or destroyed with krb5_cc_destroy(). 1408 * MIT Kerberos behavies slightly diffrent and sets cache to NULL 1409 * when all caches are iterated over and return 0. 1410 * 1411 * @return Return 0 or and error, KRB5_CC_END is returned at the end 1412 * of iteration. See krb5_get_error_message(). 1413 * 1414 * @ingroup krb5_ccache 1415 */ 1416 1417 1418KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1419krb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor, 1420 krb5_ccache *cache) 1421{ 1422 krb5_error_code ret; 1423 1424 *cache = NULL; 1425 1426 while (cursor->idx < context->num_cc_ops) { 1427 1428 if (cursor->cursor == NULL) { 1429 ret = krb5_cc_cache_get_first (context, 1430 context->cc_ops[cursor->idx]->prefix, 1431 &cursor->cursor); 1432 if (ret) { 1433 cursor->idx++; 1434 continue; 1435 } 1436 } 1437 ret = krb5_cc_cache_next(context, cursor->cursor, cache); 1438 if (ret == 0) 1439 break; 1440 1441 krb5_cc_cache_end_seq_get(context, cursor->cursor); 1442 cursor->cursor = NULL; 1443 if (ret != KRB5_CC_END) 1444 break; 1445 1446 cursor->idx++; 1447 } 1448 if (cursor->idx >= context->num_cc_ops) { 1449 krb5_set_error_message(context, KRB5_CC_END, 1450 N_("Reached end of credential caches", "")); 1451 return KRB5_CC_END; 1452 } 1453 1454 return 0; 1455} 1456 1457/** 1458 * End an iteration and free all resources, can be done before end is reached. 1459 * 1460 * @param context A Kerberos 5 context 1461 * @param cursor the iteration cursor to be freed. 1462 * 1463 * @return Return 0 or and error, KRB5_CC_END is returned at the end 1464 * of iteration. See krb5_get_error_message(). 1465 * 1466 * @ingroup krb5_ccache 1467 */ 1468 1469KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1470krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor) 1471{ 1472 krb5_cccol_cursor c = *cursor; 1473 1474 *cursor = NULL; 1475 if (c) { 1476 if (c->cursor) 1477 krb5_cc_cache_end_seq_get(context, c->cursor); 1478 free(c); 1479 } 1480 return 0; 1481} 1482 1483/** 1484 * Return the last time the credential cache was modified. 1485 * 1486 * @param context A Kerberos 5 context 1487 * @param id The credential cache to probe 1488 * @param mtime the last modification time, set to 0 on error. 1489 1490 * @return Return 0 or and error. See krb5_get_error_message(). 1491 * 1492 * @ingroup krb5_ccache 1493 */ 1494 1495 1496KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1497krb5_cc_last_change_time(krb5_context context, 1498 krb5_ccache id, 1499 krb5_timestamp *mtime) 1500{ 1501 *mtime = 0; 1502 return (*id->ops->lastchange)(context, id, mtime); 1503} 1504 1505/** 1506 * Return the last modfication time for a cache collection. The query 1507 * can be limited to a specific cache type. If the function return 0 1508 * and mtime is 0, there was no credentials in the caches. 1509 * 1510 * @param context A Kerberos 5 context 1511 * @param type The credential cache to probe, if NULL, all type are traversed. 1512 * @param mtime the last modification time, set to 0 on error. 1513 1514 * @return Return 0 or and error. See krb5_get_error_message(). 1515 * 1516 * @ingroup krb5_ccache 1517 */ 1518 1519KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1520krb5_cccol_last_change_time(krb5_context context, 1521 const char *type, 1522 krb5_timestamp *mtime) 1523{ 1524 krb5_cccol_cursor cursor; 1525 krb5_error_code ret; 1526 krb5_ccache id; 1527 krb5_timestamp t = 0; 1528 1529 *mtime = 0; 1530 1531 ret = krb5_cccol_cursor_new (context, &cursor); 1532 if (ret) 1533 return ret; 1534 1535 while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) { 1536 1537 if (type && strcmp(krb5_cc_get_type(context, id), type) != 0) 1538 continue; 1539 1540 ret = krb5_cc_last_change_time(context, id, &t); 1541 krb5_cc_close(context, id); 1542 if (ret) 1543 continue; 1544 if (t > *mtime) 1545 *mtime = t; 1546 } 1547 1548 krb5_cccol_cursor_free(context, &cursor); 1549 1550 return 0; 1551} 1552/** 1553 * Return a friendly name on credential cache. Free the result with krb5_xfree(). 1554 * 1555 * @return Return an error code or 0, see krb5_get_error_message(). 1556 * 1557 * @ingroup krb5_ccache 1558 */ 1559 1560KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1561krb5_cc_get_friendly_name(krb5_context context, 1562 krb5_ccache id, 1563 char **name) 1564{ 1565 krb5_error_code ret; 1566 krb5_data data; 1567 1568 ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data); 1569 if (ret) { 1570 krb5_principal principal; 1571 ret = krb5_cc_get_principal(context, id, &principal); 1572 if (ret) 1573 return ret; 1574 ret = krb5_unparse_name(context, principal, name); 1575 krb5_free_principal(context, principal); 1576 } else { 1577 ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data); 1578 krb5_data_free(&data); 1579 if (ret <= 0) { 1580 ret = ENOMEM; 1581 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1582 } else 1583 ret = 0; 1584 } 1585 1586 return ret; 1587} 1588 1589/** 1590 * Set the friendly name on credential cache. 1591 * 1592 * @return Return an error code or 0, see krb5_get_error_message(). 1593 * 1594 * @ingroup krb5_ccache 1595 */ 1596 1597KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1598krb5_cc_set_friendly_name(krb5_context context, 1599 krb5_ccache id, 1600 const char *name) 1601{ 1602 krb5_data data; 1603 1604 data.data = rk_UNCONST(name); 1605 data.length = strlen(name); 1606 1607 return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data); 1608} 1609 1610/** 1611 * Get the lifetime of the initial ticket in the cache 1612 * 1613 * Get the lifetime of the initial ticket in the cache, if the initial 1614 * ticket was not found, the error code KRB5_CC_END is returned. 1615 * 1616 * @param context A Kerberos 5 context. 1617 * @param id a credential cache 1618 * @param t the relative lifetime of the initial ticket 1619 * 1620 * @return Return an error code or 0, see krb5_get_error_message(). 1621 * 1622 * @ingroup krb5_ccache 1623 */ 1624 1625KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1626krb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t) 1627{ 1628 krb5_cc_cursor cursor; 1629 krb5_error_code ret; 1630 krb5_creds cred; 1631 time_t now; 1632 1633 *t = 0; 1634 now = time(NULL); 1635 1636 ret = krb5_cc_start_seq_get(context, id, &cursor); 1637 if (ret) 1638 return ret; 1639 1640 while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) { 1641 if (cred.flags.b.initial) { 1642 if (now < cred.times.endtime) 1643 *t = cred.times.endtime - now; 1644 krb5_free_cred_contents(context, &cred); 1645 break; 1646 } 1647 krb5_free_cred_contents(context, &cred); 1648 } 1649 1650 krb5_cc_end_seq_get(context, id, &cursor); 1651 1652 return ret; 1653} 1654 1655/** 1656 * Set the time offset betwen the client and the KDC 1657 * 1658 * If the backend doesn't support KDC offset, use the context global setting. 1659 * 1660 * @param context A Kerberos 5 context. 1661 * @param id a credential cache 1662 * @param offset the offset in seconds 1663 * 1664 * @return Return an error code or 0, see krb5_get_error_message(). 1665 * 1666 * @ingroup krb5_ccache 1667 */ 1668 1669KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1670krb5_cc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat offset) 1671{ 1672 if (id->ops->set_kdc_offset == NULL) { 1673 context->kdc_sec_offset = offset; 1674 context->kdc_usec_offset = 0; 1675 return 0; 1676 } 1677 return (*id->ops->set_kdc_offset)(context, id, offset); 1678} 1679 1680/** 1681 * Get the time offset betwen the client and the KDC 1682 * 1683 * If the backend doesn't support KDC offset, use the context global setting. 1684 * 1685 * @param context A Kerberos 5 context. 1686 * @param id a credential cache 1687 * @param offset the offset in seconds 1688 * 1689 * @return Return an error code or 0, see krb5_get_error_message(). 1690 * 1691 * @ingroup krb5_ccache 1692 */ 1693 1694KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1695krb5_cc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *offset) 1696{ 1697 if (id->ops->get_kdc_offset == NULL) { 1698 *offset = context->kdc_sec_offset; 1699 return 0; 1700 } 1701 return (*id->ops->get_kdc_offset)(context, id, offset); 1702} 1703 1704 1705#ifdef _WIN32 1706 1707char * 1708_krb5_get_default_cc_name_from_registry() 1709{ 1710 HKEY hk_k5 = 0; 1711 LONG code; 1712 char * ccname = NULL; 1713 1714 code = RegOpenKeyEx(HKEY_CURRENT_USER, 1715 "Software\\MIT\\Kerberos5", 1716 0, KEY_READ, &hk_k5); 1717 1718 if (code != ERROR_SUCCESS) 1719 return NULL; 1720 1721 ccname = _krb5_parse_reg_value_as_string(NULL, hk_k5, "ccname", 1722 REG_NONE, 0); 1723 1724 RegCloseKey(hk_k5); 1725 1726 return ccname; 1727} 1728 1729#endif 1730