1 /* 2 * Copyright (c) 1997 - 2002 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 2002/09/04 21:12:46 joda 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; 229 230 ret = krb5_auth_con_init(context, &ac); 231 if(ret) 232 goto fail; 233 ret = krb5_generate_subkey (context, &krbtgt->session, &key); 234 if (ret) { 235 krb5_auth_con_free (context, ac); 236 goto fail; 237 } 238 ret = krb5_auth_con_setlocalsubkey(context, ac, key); 239 if (ret) { 240 krb5_free_keyblock (context, key); 241 krb5_auth_con_free (context, ac); 242 goto fail; 243 } 244 245 ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key); 246 if (ret) { 247 krb5_free_keyblock (context, key); 248 krb5_auth_con_free (context, ac); 249 goto fail; 250 } 251 252 ret = make_pa_tgs_req(context, 253 ac, 254 &t->req_body, 255 t->padata->val, 256 krbtgt, 257 usage); 258 if(ret) { 259 krb5_free_keyblock (context, key); 260 krb5_auth_con_free(context, ac); 261 goto fail; 262 } 263 *subkey = key; 264 265 krb5_auth_con_free(context, ac); 266 } 267 fail: 268 if (ret) 269 /* XXX - don't free addresses? */ 270 free_TGS_REQ (t); 271 return ret; 272 } 273 274 static krb5_error_code 275 get_krbtgt(krb5_context context, 276 krb5_ccache id, 277 krb5_realm realm, 278 krb5_creds **cred) 279 { 280 krb5_error_code ret; 281 krb5_creds tmp_cred; 282 283 memset(&tmp_cred, 0, sizeof(tmp_cred)); 284 285 ret = krb5_make_principal(context, 286 &tmp_cred.server, 287 realm, 288 KRB5_TGS_NAME, 289 realm, 290 NULL); 291 if(ret) 292 return ret; 293 ret = krb5_get_credentials(context, 294 KRB5_GC_CACHED, 295 id, 296 &tmp_cred, 297 cred); 298 krb5_free_principal(context, tmp_cred.server); 299 if(ret) 300 return ret; 301 return 0; 302 } 303 304 /* DCE compatible decrypt proc */ 305 static krb5_error_code 306 decrypt_tkt_with_subkey (krb5_context context, 307 krb5_keyblock *key, 308 krb5_key_usage usage, 309 krb5_const_pointer subkey, 310 krb5_kdc_rep *dec_rep) 311 { 312 krb5_error_code ret; 313 krb5_data data; 314 size_t size; 315 krb5_crypto crypto; 316 317 ret = krb5_crypto_init(context, key, 0, &crypto); 318 if (ret) 319 return ret; 320 ret = krb5_decrypt_EncryptedData (context, 321 crypto, 322 usage, 323 &dec_rep->kdc_rep.enc_part, 324 &data); 325 krb5_crypto_destroy(context, crypto); 326 if(ret && subkey){ 327 /* DCE compat -- try to decrypt with subkey */ 328 ret = krb5_crypto_init(context, (krb5_keyblock*)subkey, 0, &crypto); 329 if (ret) 330 return ret; 331 ret = krb5_decrypt_EncryptedData (context, 332 crypto, 333 KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, 334 &dec_rep->kdc_rep.enc_part, 335 &data); 336 krb5_crypto_destroy(context, crypto); 337 } 338 if (ret) 339 return ret; 340 341 ret = krb5_decode_EncASRepPart(context, 342 data.data, 343 data.length, 344 &dec_rep->enc_part, 345 &size); 346 if (ret) 347 ret = krb5_decode_EncTGSRepPart(context, 348 data.data, 349 data.length, 350 &dec_rep->enc_part, 351 &size); 352 krb5_data_free (&data); 353 return ret; 354 } 355 356 static krb5_error_code 357 get_cred_kdc_usage(krb5_context context, 358 krb5_ccache id, 359 krb5_kdc_flags flags, 360 krb5_addresses *addresses, 361 krb5_creds *in_creds, 362 krb5_creds *krbtgt, 363 krb5_creds *out_creds, 364 krb5_key_usage usage) 365 { 366 TGS_REQ req; 367 krb5_data enc; 368 krb5_data resp; 369 krb5_kdc_rep rep; 370 KRB_ERROR error; 371 krb5_error_code ret; 372 unsigned nonce; 373 krb5_keyblock *subkey = NULL; 374 u_char *buf = NULL; 375 size_t buf_size; 376 size_t len; 377 Ticket second_ticket; 378 379 krb5_generate_random_block(&nonce, sizeof(nonce)); 380 nonce &= 0xffffffff; 381 382 if(flags.b.enc_tkt_in_skey){ 383 ret = decode_Ticket(in_creds->second_ticket.data, 384 in_creds->second_ticket.length, 385 &second_ticket, &len); 386 if(ret) 387 return ret; 388 } 389 390 ret = init_tgs_req (context, 391 id, 392 addresses, 393 flags, 394 flags.b.enc_tkt_in_skey ? &second_ticket : NULL, 395 in_creds, 396 krbtgt, 397 nonce, 398 &subkey, 399 &req, 400 usage); 401 if(flags.b.enc_tkt_in_skey) 402 free_Ticket(&second_ticket); 403 if (ret) 404 goto out; 405 406 ASN1_MALLOC_ENCODE(TGS_REQ, buf, buf_size, &req, &enc.length, ret); 407 if (ret) 408 goto out; 409 if(enc.length != buf_size) 410 krb5_abortx(context, "internal error in ASN.1 encoder"); 411 412 /* don't free addresses */ 413 req.req_body.addresses = NULL; 414 free_TGS_REQ(&req); 415 416 enc.data = buf + buf_size - enc.length; 417 if (ret) 418 goto out; 419 420 /* 421 * Send and receive 422 */ 423 424 ret = krb5_sendto_kdc (context, &enc, 425 &krbtgt->server->name.name_string.val[1], &resp); 426 if(ret) 427 goto out; 428 429 memset(&rep, 0, sizeof(rep)); 430 if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){ 431 ret = krb5_copy_principal(context, 432 in_creds->client, 433 &out_creds->client); 434 if(ret) 435 goto out; 436 ret = krb5_copy_principal(context, 437 in_creds->server, 438 &out_creds->server); 439 if(ret) 440 goto out; 441 /* this should go someplace else */ 442 out_creds->times.endtime = in_creds->times.endtime; 443 444 ret = _krb5_extract_ticket(context, 445 &rep, 446 out_creds, 447 &krbtgt->session, 448 NULL, 449 KRB5_KU_TGS_REP_ENC_PART_SESSION, 450 &krbtgt->addresses, 451 nonce, 452 TRUE, 453 flags.b.request_anonymous, 454 decrypt_tkt_with_subkey, 455 subkey); 456 krb5_free_kdc_rep(context, &rep); 457 if (ret) 458 goto out; 459 } else if(krb5_rd_error(context, &resp, &error) == 0) { 460 ret = krb5_error_from_rd_error(context, &error, in_creds); 461 krb5_free_error_contents(context, &error); 462 } else if(resp.data && ((char*)resp.data)[0] == 4) { 463 ret = KRB5KRB_AP_ERR_V4_REPLY; 464 krb5_clear_error_string(context); 465 } else { 466 ret = KRB5KRB_AP_ERR_MSG_TYPE; 467 krb5_clear_error_string(context); 468 } 469 krb5_data_free(&resp); 470 out: 471 if(subkey){ 472 krb5_free_keyblock_contents(context, subkey); 473 free(subkey); 474 } 475 if (buf) 476 free (buf); 477 return ret; 478 479 } 480 481 static krb5_error_code 482 get_cred_kdc(krb5_context context, 483 krb5_ccache id, 484 krb5_kdc_flags flags, 485 krb5_addresses *addresses, 486 krb5_creds *in_creds, 487 krb5_creds *krbtgt, 488 krb5_creds *out_creds) 489 { 490 krb5_error_code ret; 491 492 ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, 493 krbtgt, out_creds, KRB5_KU_TGS_REQ_AUTH); 494 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { 495 krb5_clear_error_string (context); 496 ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, 497 krbtgt, out_creds, KRB5_KU_AP_REQ_AUTH); 498 } 499 return ret; 500 } 501 502 /* same as above, just get local addresses first */ 503 504 static krb5_error_code 505 get_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, 506 krb5_creds *in_creds, krb5_creds *krbtgt, 507 krb5_creds *out_creds) 508 { 509 krb5_error_code ret; 510 krb5_addresses addresses, *addrs = &addresses; 511 512 krb5_get_all_client_addrs(context, &addresses); 513 /* XXX this sucks. */ 514 if(addresses.len == 0) 515 addrs = NULL; 516 ret = get_cred_kdc(context, id, flags, addrs, 517 in_creds, krbtgt, out_creds); 518 krb5_free_addresses(context, &addresses); 519 return ret; 520 } 521 522 krb5_error_code 523 krb5_get_kdc_cred(krb5_context context, 524 krb5_ccache id, 525 krb5_kdc_flags flags, 526 krb5_addresses *addresses, 527 Ticket *second_ticket, 528 krb5_creds *in_creds, 529 krb5_creds **out_creds 530 ) 531 { 532 krb5_error_code ret; 533 krb5_creds *krbtgt; 534 535 *out_creds = calloc(1, sizeof(**out_creds)); 536 if(*out_creds == NULL) { 537 krb5_set_error_string(context, "malloc: out of memory"); 538 return ENOMEM; 539 } 540 ret = get_krbtgt (context, 541 id, 542 in_creds->server->realm, 543 &krbtgt); 544 if(ret) { 545 free(*out_creds); 546 return ret; 547 } 548 ret = get_cred_kdc(context, id, flags, addresses, 549 in_creds, krbtgt, *out_creds); 550 krb5_free_creds (context, krbtgt); 551 if(ret) 552 free(*out_creds); 553 return ret; 554 } 555 556 557 static krb5_error_code 558 find_cred(krb5_context context, 559 krb5_ccache id, 560 krb5_principal server, 561 krb5_creds **tgts, 562 krb5_creds *out_creds) 563 { 564 krb5_error_code ret; 565 krb5_creds mcreds; 566 mcreds.server = server; 567 ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 568 &mcreds, out_creds); 569 if(ret == 0) 570 return 0; 571 while(tgts && *tgts){ 572 if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 573 &mcreds, *tgts)){ 574 ret = krb5_copy_creds_contents(context, *tgts, out_creds); 575 return ret; 576 } 577 tgts++; 578 } 579 krb5_clear_error_string(context); 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 590 for(i = 0; tmp && tmp[i]; i++); /* XXX */ 591 tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 592 if(tmp == NULL) { 593 krb5_set_error_string(context, "malloc: out of memory"); 594 return ENOMEM; 595 } 596 *tgts = tmp; 597 ret = krb5_copy_creds(context, tkt, &tmp[i]); 598 tmp[i+1] = NULL; 599 return ret; 600 } 601 602 /* 603 get_cred(server) 604 creds = cc_get_cred(server) 605 if(creds) return creds 606 tgt = cc_get_cred(krbtgt/server_realm@any_realm) 607 if(tgt) 608 return get_cred_tgt(server, tgt) 609 if(client_realm == server_realm) 610 return NULL 611 tgt = get_cred(krbtgt/server_realm@client_realm) 612 while(tgt_inst != server_realm) 613 tgt = get_cred(krbtgt/server_realm@tgt_inst) 614 return get_cred_tgt(server, tgt) 615 */ 616 617 static krb5_error_code 618 get_cred_from_kdc_flags(krb5_context context, 619 krb5_kdc_flags flags, 620 krb5_ccache ccache, 621 krb5_creds *in_creds, 622 krb5_creds **out_creds, 623 krb5_creds ***ret_tgts) 624 { 625 krb5_error_code ret; 626 krb5_creds *tgt, tmp_creds; 627 krb5_const_realm client_realm, server_realm, try_realm; 628 629 *out_creds = NULL; 630 631 client_realm = *krb5_princ_realm(context, in_creds->client); 632 server_realm = *krb5_princ_realm(context, in_creds->server); 633 memset(&tmp_creds, 0, sizeof(tmp_creds)); 634 ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 635 if(ret) 636 return ret; 637 638 try_realm = krb5_config_get_string(context, NULL, "libdefaults", 639 "capath", server_realm, NULL); 640 if (try_realm == NULL) 641 try_realm = client_realm; 642 643 ret = krb5_make_principal(context, 644 &tmp_creds.server, 645 try_realm, 646 KRB5_TGS_NAME, 647 server_realm, 648 NULL); 649 if(ret){ 650 krb5_free_principal(context, tmp_creds.client); 651 return ret; 652 } 653 { 654 krb5_creds tgts; 655 /* XXX try krb5_cc_retrieve_cred first? */ 656 ret = find_cred(context, ccache, tmp_creds.server, 657 *ret_tgts, &tgts); 658 if(ret == 0){ 659 *out_creds = calloc(1, sizeof(**out_creds)); 660 if(*out_creds == NULL) { 661 krb5_set_error_string(context, "malloc: out of memory"); 662 ret = ENOMEM; 663 } else { 664 krb5_boolean noaddr; 665 666 krb5_appdefault_boolean(context, NULL, tgts.server->realm, 667 "no-addresses", FALSE, &noaddr); 668 669 if (noaddr) 670 ret = get_cred_kdc(context, ccache, flags, NULL, 671 in_creds, &tgts, *out_creds); 672 else 673 ret = get_cred_kdc_la(context, ccache, flags, 674 in_creds, &tgts, *out_creds); 675 if (ret) { 676 free (*out_creds); 677 *out_creds = NULL; 678 } 679 } 680 krb5_free_creds_contents(context, &tgts); 681 krb5_free_principal(context, tmp_creds.server); 682 krb5_free_principal(context, tmp_creds.client); 683 return ret; 684 } 685 } 686 if(krb5_realm_compare(context, in_creds->client, in_creds->server)) { 687 krb5_clear_error_string (context); 688 return KRB5_CC_NOTFOUND; 689 } 690 /* XXX this can loop forever */ 691 while(1){ 692 general_string tgt_inst; 693 694 ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, 695 &tgt, ret_tgts); 696 if(ret) { 697 krb5_free_principal(context, tmp_creds.server); 698 krb5_free_principal(context, tmp_creds.client); 699 return ret; 700 } 701 ret = add_cred(context, ret_tgts, tgt); 702 if(ret) { 703 krb5_free_principal(context, tmp_creds.server); 704 krb5_free_principal(context, tmp_creds.client); 705 return ret; 706 } 707 tgt_inst = tgt->server->name.name_string.val[1]; 708 if(strcmp(tgt_inst, server_realm) == 0) 709 break; 710 krb5_free_principal(context, tmp_creds.server); 711 ret = krb5_make_principal(context, &tmp_creds.server, 712 tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 713 if(ret) { 714 krb5_free_principal(context, tmp_creds.server); 715 krb5_free_principal(context, tmp_creds.client); 716 return ret; 717 } 718 ret = krb5_free_creds(context, tgt); 719 if(ret) { 720 krb5_free_principal(context, tmp_creds.server); 721 krb5_free_principal(context, tmp_creds.client); 722 return ret; 723 } 724 } 725 726 krb5_free_principal(context, tmp_creds.server); 727 krb5_free_principal(context, tmp_creds.client); 728 *out_creds = calloc(1, sizeof(**out_creds)); 729 if(*out_creds == NULL) { 730 krb5_set_error_string(context, "malloc: out of memory"); 731 ret = ENOMEM; 732 } else { 733 krb5_boolean noaddr; 734 735 krb5_appdefault_boolean(context, NULL, tgt->server->realm, 736 "no-addresses", FALSE, &noaddr); 737 if (noaddr) 738 ret = get_cred_kdc (context, ccache, flags, NULL, 739 in_creds, tgt, *out_creds); 740 else 741 ret = get_cred_kdc_la(context, ccache, flags, 742 in_creds, tgt, *out_creds); 743 if (ret) { 744 free (*out_creds); 745 *out_creds = NULL; 746 } 747 } 748 krb5_free_creds(context, tgt); 749 return ret; 750 } 751 752 krb5_error_code 753 krb5_get_cred_from_kdc_opt(krb5_context context, 754 krb5_ccache ccache, 755 krb5_creds *in_creds, 756 krb5_creds **out_creds, 757 krb5_creds ***ret_tgts, 758 krb5_flags flags) 759 { 760 krb5_kdc_flags f; 761 f.i = flags; 762 return get_cred_from_kdc_flags(context, f, ccache, 763 in_creds, out_creds, ret_tgts); 764 } 765 766 krb5_error_code 767 krb5_get_cred_from_kdc(krb5_context context, 768 krb5_ccache ccache, 769 krb5_creds *in_creds, 770 krb5_creds **out_creds, 771 krb5_creds ***ret_tgts) 772 { 773 return krb5_get_cred_from_kdc_opt(context, ccache, 774 in_creds, out_creds, ret_tgts, 0); 775 } 776 777 778 krb5_error_code 779 krb5_get_credentials_with_flags(krb5_context context, 780 krb5_flags options, 781 krb5_kdc_flags flags, 782 krb5_ccache ccache, 783 krb5_creds *in_creds, 784 krb5_creds **out_creds) 785 { 786 krb5_error_code ret; 787 krb5_creds **tgts; 788 krb5_creds *res_creds; 789 int i; 790 791 *out_creds = NULL; 792 res_creds = calloc(1, sizeof(*res_creds)); 793 if (res_creds == NULL) { 794 krb5_set_error_string(context, "malloc: out of memory"); 795 return ENOMEM; 796 } 797 798 ret = krb5_cc_retrieve_cred(context, 799 ccache, 800 in_creds->session.keytype ? 801 KRB5_TC_MATCH_KEYTYPE : 0, 802 in_creds, res_creds); 803 if(ret == 0) { 804 *out_creds = res_creds; 805 return 0; 806 } 807 free(res_creds); 808 if(ret != KRB5_CC_END) 809 return ret; 810 if(options & KRB5_GC_CACHED) { 811 krb5_clear_error_string (context); 812 return KRB5_CC_NOTFOUND; 813 } 814 if(options & KRB5_GC_USER_USER) 815 flags.b.enc_tkt_in_skey = 1; 816 tgts = NULL; 817 ret = get_cred_from_kdc_flags(context, flags, ccache, 818 in_creds, out_creds, &tgts); 819 for(i = 0; tgts && tgts[i]; i++) { 820 krb5_cc_store_cred(context, ccache, tgts[i]); 821 krb5_free_creds(context, tgts[i]); 822 } 823 free(tgts); 824 if(ret == 0 && flags.b.enc_tkt_in_skey == 0) 825 krb5_cc_store_cred(context, ccache, *out_creds); 826 return ret; 827 } 828 829 krb5_error_code 830 krb5_get_credentials(krb5_context context, 831 krb5_flags options, 832 krb5_ccache ccache, 833 krb5_creds *in_creds, 834 krb5_creds **out_creds) 835 { 836 krb5_kdc_flags flags; 837 flags.i = 0; 838 return krb5_get_credentials_with_flags(context, options, flags, 839 ccache, in_creds, out_creds); 840 } 841