1 /* 2 * Copyright (c) 1997 - 2001 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: get_cred.c,v 1.82 2001/01/19 04:29:44 assar Exp $"); 37 38 /* 39 * Take the `body' and encode it into `padata' using the credentials 40 * in `creds'. 41 */ 42 43 static krb5_error_code 44 make_pa_tgs_req(krb5_context context, 45 krb5_auth_context ac, 46 KDC_REQ_BODY *body, 47 PA_DATA *padata, 48 krb5_creds *creds) 49 { 50 u_char *buf; 51 size_t buf_size; 52 size_t len; 53 krb5_data in_data; 54 krb5_error_code ret; 55 56 buf_size = 1024; 57 buf = malloc (buf_size); 58 if (buf == NULL) 59 return ENOMEM; 60 61 do { 62 ret = encode_KDC_REQ_BODY(buf + buf_size - 1, buf_size, 63 body, &len); 64 if (ret){ 65 if (ret == ASN1_OVERFLOW) { 66 u_char *tmp; 67 68 buf_size *= 2; 69 tmp = realloc (buf, buf_size); 70 if (tmp == NULL) { 71 ret = ENOMEM; 72 goto out; 73 } 74 buf = tmp; 75 } else { 76 goto out; 77 } 78 } 79 } while (ret == ASN1_OVERFLOW); 80 81 in_data.length = len; 82 in_data.data = buf + buf_size - len; 83 ret = krb5_mk_req_internal(context, &ac, 0, &in_data, creds, 84 &padata->padata_value, 85 KRB5_KU_TGS_REQ_AUTH_CKSUM, 86 KRB5_KU_TGS_REQ_AUTH); 87 out: 88 free (buf); 89 if(ret) 90 return ret; 91 padata->padata_type = KRB5_PADATA_TGS_REQ; 92 return 0; 93 } 94 95 /* 96 * Set the `enc-authorization-data' in `req_body' based on `authdata' 97 */ 98 99 static krb5_error_code 100 set_auth_data (krb5_context context, 101 KDC_REQ_BODY *req_body, 102 krb5_authdata *authdata, 103 krb5_keyblock *key) 104 { 105 if(authdata->len) { 106 size_t len; 107 unsigned char *buf; 108 krb5_crypto crypto; 109 krb5_error_code ret; 110 111 len = length_AuthorizationData(authdata); 112 buf = malloc(len); 113 if (buf == NULL) 114 return ENOMEM; 115 ret = encode_AuthorizationData(buf + len - 1, 116 len, authdata, &len); 117 if (ret) { 118 free (buf); 119 return ret; 120 } 121 122 ALLOC(req_body->enc_authorization_data, 1); 123 if (req_body->enc_authorization_data == NULL) { 124 free (buf); 125 return ret; 126 } 127 ret = krb5_crypto_init(context, key, 0, &crypto); 128 if (ret) { 129 free (buf); 130 free (req_body->enc_authorization_data); 131 return ret; 132 } 133 krb5_encrypt_EncryptedData(context, 134 crypto, 135 KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, 136 /* KRB5_KU_TGS_REQ_AUTH_DAT_SESSION? */ 137 buf, 138 len, 139 0, 140 req_body->enc_authorization_data); 141 free (buf); 142 krb5_crypto_destroy(context, crypto); 143 } else { 144 req_body->enc_authorization_data = NULL; 145 } 146 return 0; 147 } 148 149 /* 150 * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' 151 * (if not-NULL), `in_creds', `krbtgt', and returning the generated 152 * subkey in `subkey'. 153 */ 154 155 static krb5_error_code 156 init_tgs_req (krb5_context context, 157 krb5_ccache ccache, 158 krb5_addresses *addresses, 159 krb5_kdc_flags flags, 160 Ticket *second_ticket, 161 krb5_creds *in_creds, 162 krb5_creds *krbtgt, 163 unsigned nonce, 164 krb5_keyblock **subkey, 165 TGS_REQ *t) 166 { 167 krb5_error_code ret; 168 169 memset(t, 0, sizeof(*t)); 170 t->pvno = 5; 171 t->msg_type = krb_tgs_req; 172 if (in_creds->session.keytype) { 173 ret = krb5_keytype_to_enctypes_default (context, 174 in_creds->session.keytype, 175 &t->req_body.etype.len, 176 &t->req_body.etype.val); 177 } else { 178 ret = krb5_init_etype(context, 179 &t->req_body.etype.len, 180 &t->req_body.etype.val, 181 NULL); 182 } 183 if (ret) 184 goto fail; 185 t->req_body.addresses = addresses; 186 t->req_body.kdc_options = flags.b; 187 ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); 188 if (ret) 189 goto fail; 190 ALLOC(t->req_body.sname, 1); 191 if (t->req_body.sname == NULL) { 192 ret = ENOMEM; 193 goto fail; 194 } 195 196 /* some versions of some code might require that the client be 197 present in TGS-REQs, but this is clearly against the spec */ 198 199 ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); 200 if (ret) 201 goto fail; 202 203 /* req_body.till should be NULL if there is no endtime specified, 204 but old MIT code (like DCE secd) doesn't like that */ 205 ALLOC(t->req_body.till, 1); 206 if(t->req_body.till == NULL){ 207 ret = ENOMEM; 208 goto fail; 209 } 210 *t->req_body.till = in_creds->times.endtime; 211 212 t->req_body.nonce = nonce; 213 if(second_ticket){ 214 ALLOC(t->req_body.additional_tickets, 1); 215 if (t->req_body.additional_tickets == NULL) { 216 ret = ENOMEM; 217 goto fail; 218 } 219 ALLOC_SEQ(t->req_body.additional_tickets, 1); 220 if (t->req_body.additional_tickets->val == NULL) { 221 ret = ENOMEM; 222 goto fail; 223 } 224 ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); 225 if (ret) 226 goto fail; 227 } 228 ALLOC(t->padata, 1); 229 if (t->padata == NULL) { 230 ret = ENOMEM; 231 goto fail; 232 } 233 ALLOC_SEQ(t->padata, 1); 234 if (t->padata->val == NULL) { 235 ret = ENOMEM; 236 goto fail; 237 } 238 239 { 240 krb5_auth_context ac; 241 krb5_keyblock *key; 242 243 ret = krb5_auth_con_init(context, &ac); 244 if(ret) 245 goto fail; 246 ret = krb5_generate_subkey (context, &krbtgt->session, &key); 247 if (ret) { 248 krb5_auth_con_free (context, ac); 249 goto fail; 250 } 251 ret = krb5_auth_con_setlocalsubkey(context, ac, key); 252 if (ret) { 253 krb5_free_keyblock (context, key); 254 krb5_auth_con_free (context, ac); 255 goto fail; 256 } 257 258 ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key); 259 if (ret) { 260 krb5_free_keyblock (context, key); 261 krb5_auth_con_free (context, ac); 262 goto fail; 263 } 264 265 ret = make_pa_tgs_req(context, 266 ac, 267 &t->req_body, 268 t->padata->val, 269 krbtgt); 270 if(ret) { 271 krb5_free_keyblock (context, key); 272 krb5_auth_con_free(context, ac); 273 goto fail; 274 } 275 *subkey = key; 276 277 krb5_auth_con_free(context, ac); 278 } 279 fail: 280 if (ret) 281 /* XXX - don't free addresses? */ 282 free_TGS_REQ (t); 283 return ret; 284 } 285 286 static krb5_error_code 287 get_krbtgt(krb5_context context, 288 krb5_ccache id, 289 krb5_realm realm, 290 krb5_creds **cred) 291 { 292 krb5_error_code ret; 293 krb5_creds tmp_cred; 294 295 memset(&tmp_cred, 0, sizeof(tmp_cred)); 296 297 ret = krb5_make_principal(context, 298 &tmp_cred.server, 299 realm, 300 KRB5_TGS_NAME, 301 realm, 302 NULL); 303 if(ret) 304 return ret; 305 ret = krb5_get_credentials(context, 306 KRB5_GC_CACHED, 307 id, 308 &tmp_cred, 309 cred); 310 krb5_free_principal(context, tmp_cred.server); 311 if(ret) 312 return ret; 313 return 0; 314 } 315 316 /* DCE compatible decrypt proc */ 317 static krb5_error_code 318 decrypt_tkt_with_subkey (krb5_context context, 319 krb5_keyblock *key, 320 krb5_key_usage usage, 321 krb5_const_pointer subkey, 322 krb5_kdc_rep *dec_rep) 323 { 324 krb5_error_code ret; 325 krb5_data data; 326 size_t size; 327 krb5_crypto crypto; 328 329 ret = krb5_crypto_init(context, key, 0, &crypto); 330 if (ret) 331 return ret; 332 ret = krb5_decrypt_EncryptedData (context, 333 crypto, 334 usage, 335 &dec_rep->kdc_rep.enc_part, 336 &data); 337 krb5_crypto_destroy(context, crypto); 338 if(ret && subkey){ 339 /* DCE compat -- try to decrypt with subkey */ 340 ret = krb5_crypto_init(context, (krb5_keyblock*)subkey, 0, &crypto); 341 if (ret) 342 return ret; 343 ret = krb5_decrypt_EncryptedData (context, 344 crypto, 345 KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, 346 &dec_rep->kdc_rep.enc_part, 347 &data); 348 krb5_crypto_destroy(context, crypto); 349 } 350 if (ret) 351 return ret; 352 353 ret = krb5_decode_EncASRepPart(context, 354 data.data, 355 data.length, 356 &dec_rep->enc_part, 357 &size); 358 if (ret) 359 ret = krb5_decode_EncTGSRepPart(context, 360 data.data, 361 data.length, 362 &dec_rep->enc_part, 363 &size); 364 krb5_data_free (&data); 365 return ret; 366 } 367 368 static krb5_error_code 369 get_cred_kdc(krb5_context context, 370 krb5_ccache id, 371 krb5_kdc_flags flags, 372 krb5_addresses *addresses, 373 krb5_creds *in_creds, 374 krb5_creds *krbtgt, 375 krb5_creds *out_creds) 376 { 377 TGS_REQ req; 378 krb5_data enc; 379 krb5_data resp; 380 krb5_kdc_rep rep; 381 KRB_ERROR error; 382 krb5_error_code ret; 383 unsigned nonce; 384 krb5_keyblock *subkey = NULL; 385 u_char *buf = NULL; 386 size_t buf_size; 387 size_t len; 388 Ticket second_ticket; 389 390 krb5_generate_random_block(&nonce, sizeof(nonce)); 391 nonce &= 0xffffffff; 392 393 if(flags.b.enc_tkt_in_skey){ 394 ret = decode_Ticket(in_creds->second_ticket.data, 395 in_creds->second_ticket.length, 396 &second_ticket, &len); 397 if(ret) 398 return ret; 399 } 400 401 ret = init_tgs_req (context, 402 id, 403 addresses, 404 flags, 405 flags.b.enc_tkt_in_skey ? &second_ticket : NULL, 406 in_creds, 407 krbtgt, 408 nonce, 409 &subkey, 410 &req); 411 if(flags.b.enc_tkt_in_skey) 412 free_Ticket(&second_ticket); 413 if (ret) 414 goto out; 415 416 buf_size = 1024; 417 buf = malloc (buf_size); 418 if (buf == NULL) { 419 ret = ENOMEM; 420 goto out; 421 } 422 423 do { 424 ret = encode_TGS_REQ (buf + buf_size - 1, buf_size, 425 &req, &enc.length); 426 if (ret) { 427 if (ret == ASN1_OVERFLOW) { 428 u_char *tmp; 429 430 buf_size *= 2; 431 tmp = realloc (buf, buf_size); 432 if (tmp == NULL) { 433 ret = ENOMEM; 434 goto out; 435 } 436 buf = tmp; 437 } else { 438 goto out; 439 } 440 } 441 } while (ret == ASN1_OVERFLOW); 442 443 /* don't free addresses */ 444 req.req_body.addresses = NULL; 445 free_TGS_REQ(&req); 446 447 enc.data = buf + buf_size - enc.length; 448 if (ret) 449 goto out; 450 451 /* 452 * Send and receive 453 */ 454 455 ret = krb5_sendto_kdc (context, &enc, 456 &krbtgt->server->name.name_string.val[1], &resp); 457 if(ret) 458 goto out; 459 460 memset(&rep, 0, sizeof(rep)); 461 if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){ 462 ret = krb5_copy_principal(context, 463 in_creds->client, 464 &out_creds->client); 465 if(ret) 466 goto out; 467 ret = krb5_copy_principal(context, 468 in_creds->server, 469 &out_creds->server); 470 if(ret) 471 goto out; 472 /* this should go someplace else */ 473 out_creds->times.endtime = in_creds->times.endtime; 474 475 ret = _krb5_extract_ticket(context, 476 &rep, 477 out_creds, 478 &krbtgt->session, 479 NULL, 480 KRB5_KU_TGS_REP_ENC_PART_SESSION, 481 &krbtgt->addresses, 482 nonce, 483 TRUE, 484 flags.b.request_anonymous, 485 decrypt_tkt_with_subkey, 486 subkey); 487 krb5_free_kdc_rep(context, &rep); 488 if (ret) 489 goto out; 490 }else if(krb5_rd_error(context, &resp, &error) == 0){ 491 ret = error.error_code; 492 free_KRB_ERROR(&error); 493 }else if(resp.data && ((char*)resp.data)[0] == 4) 494 ret = KRB5KRB_AP_ERR_V4_REPLY; 495 else 496 ret = KRB5KRB_AP_ERR_MSG_TYPE; 497 krb5_data_free(&resp); 498 out: 499 if(subkey){ 500 krb5_free_keyblock_contents(context, subkey); 501 free(subkey); 502 } 503 if (buf) 504 free (buf); 505 return ret; 506 507 } 508 509 /* same as above, just get local addresses first */ 510 511 static krb5_error_code 512 get_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, 513 krb5_creds *in_creds, krb5_creds *krbtgt, 514 krb5_creds *out_creds) 515 { 516 krb5_error_code ret; 517 krb5_addresses addresses; 518 519 krb5_get_all_client_addrs(context, &addresses); 520 ret = get_cred_kdc(context, id, flags, &addresses, 521 in_creds, krbtgt, out_creds); 522 krb5_free_addresses(context, &addresses); 523 return ret; 524 } 525 526 krb5_error_code 527 krb5_get_kdc_cred(krb5_context context, 528 krb5_ccache id, 529 krb5_kdc_flags flags, 530 krb5_addresses *addresses, 531 Ticket *second_ticket, 532 krb5_creds *in_creds, 533 krb5_creds **out_creds 534 ) 535 { 536 krb5_error_code ret; 537 krb5_creds *krbtgt; 538 *out_creds = calloc(1, sizeof(**out_creds)); 539 if(*out_creds == NULL) 540 return ENOMEM; 541 ret = get_krbtgt (context, 542 id, 543 in_creds->server->realm, 544 &krbtgt); 545 if(ret) { 546 free(*out_creds); 547 return ret; 548 } 549 ret = get_cred_kdc(context, id, flags, addresses, 550 in_creds, krbtgt, *out_creds); 551 krb5_free_creds (context, krbtgt); 552 if(ret) 553 free(*out_creds); 554 return ret; 555 } 556 557 558 static krb5_error_code 559 find_cred(krb5_context context, 560 krb5_ccache id, 561 krb5_principal server, 562 krb5_creds **tgts, 563 krb5_creds *out_creds) 564 { 565 krb5_error_code ret; 566 krb5_creds mcreds; 567 mcreds.server = server; 568 ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 569 &mcreds, out_creds); 570 if(ret == 0) 571 return 0; 572 while(tgts && *tgts){ 573 if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 574 &mcreds, *tgts)){ 575 ret = krb5_copy_creds_contents(context, *tgts, out_creds); 576 return ret; 577 } 578 tgts++; 579 } 580 return KRB5_CC_NOTFOUND; 581 } 582 583 static krb5_error_code 584 add_cred(krb5_context context, krb5_creds ***tgts, krb5_creds *tkt) 585 { 586 int i; 587 krb5_error_code ret; 588 krb5_creds **tmp = *tgts; 589 for(i = 0; tmp && tmp[i]; i++); /* XXX */ 590 tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 591 if(tmp == NULL) 592 return ENOMEM; 593 *tgts = tmp; 594 ret = krb5_copy_creds(context, tkt, &tmp[i]); 595 tmp[i+1] = NULL; 596 return ret; 597 } 598 599 /* 600 get_cred(server) 601 creds = cc_get_cred(server) 602 if(creds) return creds 603 tgt = cc_get_cred(krbtgt/server_realm@any_realm) 604 if(tgt) 605 return get_cred_tgt(server, tgt) 606 if(client_realm == server_realm) 607 return NULL 608 tgt = get_cred(krbtgt/server_realm@client_realm) 609 while(tgt_inst != server_realm) 610 tgt = get_cred(krbtgt/server_realm@tgt_inst) 611 return get_cred_tgt(server, tgt) 612 */ 613 614 static krb5_error_code 615 get_cred_from_kdc_flags(krb5_context context, 616 krb5_kdc_flags flags, 617 krb5_ccache ccache, 618 krb5_creds *in_creds, 619 krb5_creds **out_creds, 620 krb5_creds ***ret_tgts) 621 { 622 krb5_error_code ret; 623 krb5_creds *tgt, tmp_creds; 624 krb5_const_realm client_realm, server_realm, try_realm; 625 626 *out_creds = NULL; 627 628 client_realm = *krb5_princ_realm(context, in_creds->client); 629 server_realm = *krb5_princ_realm(context, in_creds->server); 630 memset(&tmp_creds, 0, sizeof(tmp_creds)); 631 ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 632 if(ret) 633 return ret; 634 635 try_realm = krb5_config_get_string(context, NULL, "libdefaults", 636 "capath", server_realm, NULL); 637 if (try_realm == NULL) 638 try_realm = client_realm; 639 640 ret = krb5_make_principal(context, 641 &tmp_creds.server, 642 try_realm, 643 KRB5_TGS_NAME, 644 server_realm, 645 NULL); 646 if(ret){ 647 krb5_free_principal(context, tmp_creds.client); 648 return ret; 649 } 650 { 651 krb5_creds tgts; 652 /* XXX try krb5_cc_retrieve_cred first? */ 653 ret = find_cred(context, ccache, tmp_creds.server, 654 *ret_tgts, &tgts); 655 if(ret == 0){ 656 *out_creds = calloc(1, sizeof(**out_creds)); 657 if(*out_creds == NULL) 658 ret = ENOMEM; 659 else { 660 ret = get_cred_kdc_la(context, ccache, flags, 661 in_creds, &tgts, *out_creds); 662 if (ret) { 663 free (*out_creds); 664 *out_creds = NULL; 665 } 666 } 667 krb5_free_creds_contents(context, &tgts); 668 krb5_free_principal(context, tmp_creds.server); 669 krb5_free_principal(context, tmp_creds.client); 670 return ret; 671 } 672 } 673 if(krb5_realm_compare(context, in_creds->client, in_creds->server)) 674 return KRB5_CC_NOTFOUND; 675 /* XXX this can loop forever */ 676 while(1){ 677 general_string tgt_inst; 678 679 ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, 680 &tgt, ret_tgts); 681 if(ret) { 682 krb5_free_principal(context, tmp_creds.server); 683 krb5_free_principal(context, tmp_creds.client); 684 return ret; 685 } 686 ret = add_cred(context, ret_tgts, tgt); 687 if(ret) { 688 krb5_free_principal(context, tmp_creds.server); 689 krb5_free_principal(context, tmp_creds.client); 690 return ret; 691 } 692 tgt_inst = tgt->server->name.name_string.val[1]; 693 if(strcmp(tgt_inst, server_realm) == 0) 694 break; 695 krb5_free_principal(context, tmp_creds.server); 696 ret = krb5_make_principal(context, &tmp_creds.server, 697 tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 698 if(ret) { 699 krb5_free_principal(context, tmp_creds.server); 700 krb5_free_principal(context, tmp_creds.client); 701 return ret; 702 } 703 ret = krb5_free_creds(context, tgt); 704 if(ret) { 705 krb5_free_principal(context, tmp_creds.server); 706 krb5_free_principal(context, tmp_creds.client); 707 return ret; 708 } 709 } 710 711 krb5_free_principal(context, tmp_creds.server); 712 krb5_free_principal(context, tmp_creds.client); 713 *out_creds = calloc(1, sizeof(**out_creds)); 714 if(*out_creds == NULL) 715 ret = ENOMEM; 716 else { 717 ret = get_cred_kdc_la(context, ccache, flags, 718 in_creds, tgt, *out_creds); 719 if (ret) { 720 free (*out_creds); 721 *out_creds = NULL; 722 } 723 } 724 krb5_free_creds(context, tgt); 725 return ret; 726 } 727 728 krb5_error_code 729 krb5_get_cred_from_kdc(krb5_context context, 730 krb5_ccache ccache, 731 krb5_creds *in_creds, 732 krb5_creds **out_creds, 733 krb5_creds ***ret_tgts) 734 { 735 krb5_kdc_flags f; 736 f.i = 0; 737 return get_cred_from_kdc_flags(context, f, ccache, 738 in_creds, out_creds, ret_tgts); 739 } 740 741 742 krb5_error_code 743 krb5_get_credentials_with_flags(krb5_context context, 744 krb5_flags options, 745 krb5_kdc_flags flags, 746 krb5_ccache ccache, 747 krb5_creds *in_creds, 748 krb5_creds **out_creds) 749 { 750 krb5_error_code ret; 751 krb5_creds **tgts; 752 krb5_creds *res_creds; 753 int i; 754 755 *out_creds = NULL; 756 res_creds = calloc(1, sizeof(*res_creds)); 757 if (res_creds == NULL) 758 return ENOMEM; 759 760 ret = krb5_cc_retrieve_cred(context, 761 ccache, 762 in_creds->session.keytype ? 763 KRB5_TC_MATCH_KEYTYPE : 0, 764 in_creds, res_creds); 765 if(ret == 0) { 766 *out_creds = res_creds; 767 return 0; 768 } 769 free(res_creds); 770 if(ret != KRB5_CC_END) 771 return ret; 772 if(options & KRB5_GC_CACHED) 773 return KRB5_CC_NOTFOUND; 774 if(options & KRB5_GC_USER_USER) 775 flags.b.enc_tkt_in_skey = 1; 776 tgts = NULL; 777 ret = get_cred_from_kdc_flags(context, flags, ccache, 778 in_creds, out_creds, &tgts); 779 for(i = 0; tgts && tgts[i]; i++) { 780 krb5_cc_store_cred(context, ccache, tgts[i]); 781 krb5_free_creds(context, tgts[i]); 782 } 783 free(tgts); 784 if(ret == 0 && flags.b.enc_tkt_in_skey == 0) 785 krb5_cc_store_cred(context, ccache, *out_creds); 786 return ret; 787 } 788 789 krb5_error_code 790 krb5_get_credentials(krb5_context context, 791 krb5_flags options, 792 krb5_ccache ccache, 793 krb5_creds *in_creds, 794 krb5_creds **out_creds) 795 { 796 krb5_kdc_flags flags; 797 flags.i = 0; 798 return krb5_get_credentials_with_flags(context, options, flags, 799 ccache, in_creds, out_creds); 800 } 801