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.85 2001/05/14 06:14:46 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; 562 563 krb5_get_all_client_addrs(context, &addresses); 564 ret = get_cred_kdc(context, id, flags, &addresses, 565 in_creds, krbtgt, out_creds); 566 krb5_free_addresses(context, &addresses); 567 return ret; 568 } 569 570 krb5_error_code 571 krb5_get_kdc_cred(krb5_context context, 572 krb5_ccache id, 573 krb5_kdc_flags flags, 574 krb5_addresses *addresses, 575 Ticket *second_ticket, 576 krb5_creds *in_creds, 577 krb5_creds **out_creds 578 ) 579 { 580 krb5_error_code ret; 581 krb5_creds *krbtgt; 582 583 *out_creds = calloc(1, sizeof(**out_creds)); 584 if(*out_creds == NULL) { 585 krb5_set_error_string(context, "malloc: out of memory"); 586 return ENOMEM; 587 } 588 ret = get_krbtgt (context, 589 id, 590 in_creds->server->realm, 591 &krbtgt); 592 if(ret) { 593 free(*out_creds); 594 return ret; 595 } 596 ret = get_cred_kdc(context, id, flags, addresses, 597 in_creds, krbtgt, *out_creds); 598 krb5_free_creds (context, krbtgt); 599 if(ret) 600 free(*out_creds); 601 return ret; 602 } 603 604 605 static krb5_error_code 606 find_cred(krb5_context context, 607 krb5_ccache id, 608 krb5_principal server, 609 krb5_creds **tgts, 610 krb5_creds *out_creds) 611 { 612 krb5_error_code ret; 613 krb5_creds mcreds; 614 mcreds.server = server; 615 ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 616 &mcreds, out_creds); 617 if(ret == 0) 618 return 0; 619 while(tgts && *tgts){ 620 if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 621 &mcreds, *tgts)){ 622 ret = krb5_copy_creds_contents(context, *tgts, out_creds); 623 return ret; 624 } 625 tgts++; 626 } 627 krb5_clear_error_string(context); 628 return KRB5_CC_NOTFOUND; 629 } 630 631 static krb5_error_code 632 add_cred(krb5_context context, krb5_creds ***tgts, krb5_creds *tkt) 633 { 634 int i; 635 krb5_error_code ret; 636 krb5_creds **tmp = *tgts; 637 638 for(i = 0; tmp && tmp[i]; i++); /* XXX */ 639 tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 640 if(tmp == NULL) { 641 krb5_set_error_string(context, "malloc: out of memory"); 642 return ENOMEM; 643 } 644 *tgts = tmp; 645 ret = krb5_copy_creds(context, tkt, &tmp[i]); 646 tmp[i+1] = NULL; 647 return ret; 648 } 649 650 /* 651 get_cred(server) 652 creds = cc_get_cred(server) 653 if(creds) return creds 654 tgt = cc_get_cred(krbtgt/server_realm@any_realm) 655 if(tgt) 656 return get_cred_tgt(server, tgt) 657 if(client_realm == server_realm) 658 return NULL 659 tgt = get_cred(krbtgt/server_realm@client_realm) 660 while(tgt_inst != server_realm) 661 tgt = get_cred(krbtgt/server_realm@tgt_inst) 662 return get_cred_tgt(server, tgt) 663 */ 664 665 static krb5_error_code 666 get_cred_from_kdc_flags(krb5_context context, 667 krb5_kdc_flags flags, 668 krb5_ccache ccache, 669 krb5_creds *in_creds, 670 krb5_creds **out_creds, 671 krb5_creds ***ret_tgts) 672 { 673 krb5_error_code ret; 674 krb5_creds *tgt, tmp_creds; 675 krb5_const_realm client_realm, server_realm, try_realm; 676 677 *out_creds = NULL; 678 679 client_realm = *krb5_princ_realm(context, in_creds->client); 680 server_realm = *krb5_princ_realm(context, in_creds->server); 681 memset(&tmp_creds, 0, sizeof(tmp_creds)); 682 ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 683 if(ret) 684 return ret; 685 686 try_realm = krb5_config_get_string(context, NULL, "libdefaults", 687 "capath", server_realm, NULL); 688 if (try_realm == NULL) 689 try_realm = client_realm; 690 691 ret = krb5_make_principal(context, 692 &tmp_creds.server, 693 try_realm, 694 KRB5_TGS_NAME, 695 server_realm, 696 NULL); 697 if(ret){ 698 krb5_free_principal(context, tmp_creds.client); 699 return ret; 700 } 701 { 702 krb5_creds tgts; 703 /* XXX try krb5_cc_retrieve_cred first? */ 704 ret = find_cred(context, ccache, tmp_creds.server, 705 *ret_tgts, &tgts); 706 if(ret == 0){ 707 *out_creds = calloc(1, sizeof(**out_creds)); 708 if(*out_creds == NULL) { 709 krb5_set_error_string(context, "malloc: out of memory"); 710 ret = ENOMEM; 711 } else { 712 ret = get_cred_kdc_la(context, ccache, flags, 713 in_creds, &tgts, *out_creds); 714 if (ret) { 715 free (*out_creds); 716 *out_creds = NULL; 717 } 718 } 719 krb5_free_creds_contents(context, &tgts); 720 krb5_free_principal(context, tmp_creds.server); 721 krb5_free_principal(context, tmp_creds.client); 722 return ret; 723 } 724 } 725 if(krb5_realm_compare(context, in_creds->client, in_creds->server)) { 726 krb5_clear_error_string (context); 727 return KRB5_CC_NOTFOUND; 728 } 729 /* XXX this can loop forever */ 730 while(1){ 731 general_string tgt_inst; 732 733 ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, 734 &tgt, ret_tgts); 735 if(ret) { 736 krb5_free_principal(context, tmp_creds.server); 737 krb5_free_principal(context, tmp_creds.client); 738 return ret; 739 } 740 ret = add_cred(context, ret_tgts, tgt); 741 if(ret) { 742 krb5_free_principal(context, tmp_creds.server); 743 krb5_free_principal(context, tmp_creds.client); 744 return ret; 745 } 746 tgt_inst = tgt->server->name.name_string.val[1]; 747 if(strcmp(tgt_inst, server_realm) == 0) 748 break; 749 krb5_free_principal(context, tmp_creds.server); 750 ret = krb5_make_principal(context, &tmp_creds.server, 751 tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 752 if(ret) { 753 krb5_free_principal(context, tmp_creds.server); 754 krb5_free_principal(context, tmp_creds.client); 755 return ret; 756 } 757 ret = krb5_free_creds(context, tgt); 758 if(ret) { 759 krb5_free_principal(context, tmp_creds.server); 760 krb5_free_principal(context, tmp_creds.client); 761 return ret; 762 } 763 } 764 765 krb5_free_principal(context, tmp_creds.server); 766 krb5_free_principal(context, tmp_creds.client); 767 *out_creds = calloc(1, sizeof(**out_creds)); 768 if(*out_creds == NULL) { 769 krb5_set_error_string(context, "malloc: out of memory"); 770 ret = ENOMEM; 771 } else { 772 ret = get_cred_kdc_la(context, ccache, flags, 773 in_creds, tgt, *out_creds); 774 if (ret) { 775 free (*out_creds); 776 *out_creds = NULL; 777 } 778 } 779 krb5_free_creds(context, tgt); 780 return ret; 781 } 782 783 krb5_error_code 784 krb5_get_cred_from_kdc_opt(krb5_context context, 785 krb5_ccache ccache, 786 krb5_creds *in_creds, 787 krb5_creds **out_creds, 788 krb5_creds ***ret_tgts, 789 krb5_flags flags) 790 { 791 krb5_kdc_flags f; 792 f.i = flags; 793 return get_cred_from_kdc_flags(context, f, ccache, 794 in_creds, out_creds, ret_tgts); 795 } 796 797 krb5_error_code 798 krb5_get_cred_from_kdc(krb5_context context, 799 krb5_ccache ccache, 800 krb5_creds *in_creds, 801 krb5_creds **out_creds, 802 krb5_creds ***ret_tgts) 803 { 804 return krb5_get_cred_from_kdc_opt(context, ccache, 805 in_creds, out_creds, ret_tgts, 0); 806 } 807 808 809 krb5_error_code 810 krb5_get_credentials_with_flags(krb5_context context, 811 krb5_flags options, 812 krb5_kdc_flags flags, 813 krb5_ccache ccache, 814 krb5_creds *in_creds, 815 krb5_creds **out_creds) 816 { 817 krb5_error_code ret; 818 krb5_creds **tgts; 819 krb5_creds *res_creds; 820 int i; 821 822 *out_creds = NULL; 823 res_creds = calloc(1, sizeof(*res_creds)); 824 if (res_creds == NULL) { 825 krb5_set_error_string(context, "malloc: out of memory"); 826 return ENOMEM; 827 } 828 829 ret = krb5_cc_retrieve_cred(context, 830 ccache, 831 in_creds->session.keytype ? 832 KRB5_TC_MATCH_KEYTYPE : 0, 833 in_creds, res_creds); 834 if(ret == 0) { 835 *out_creds = res_creds; 836 return 0; 837 } 838 free(res_creds); 839 if(ret != KRB5_CC_END) 840 return ret; 841 if(options & KRB5_GC_CACHED) { 842 krb5_clear_error_string (context); 843 return KRB5_CC_NOTFOUND; 844 } 845 if(options & KRB5_GC_USER_USER) 846 flags.b.enc_tkt_in_skey = 1; 847 tgts = NULL; 848 ret = get_cred_from_kdc_flags(context, flags, ccache, 849 in_creds, out_creds, &tgts); 850 for(i = 0; tgts && tgts[i]; i++) { 851 krb5_cc_store_cred(context, ccache, tgts[i]); 852 krb5_free_creds(context, tgts[i]); 853 } 854 free(tgts); 855 if(ret == 0 && flags.b.enc_tkt_in_skey == 0) 856 krb5_cc_store_cred(context, ccache, *out_creds); 857 return ret; 858 } 859 860 krb5_error_code 861 krb5_get_credentials(krb5_context context, 862 krb5_flags options, 863 krb5_ccache ccache, 864 krb5_creds *in_creds, 865 krb5_creds **out_creds) 866 { 867 krb5_kdc_flags flags; 868 flags.i = 0; 869 return krb5_get_credentials_with_flags(context, options, flags, 870 ccache, in_creds, out_creds); 871 } 872