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