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