1 /* 2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "krb5_locl.h" 37 #include <assert.h> 38 39 static krb5_error_code 40 get_cred_kdc_capath(krb5_context, krb5_kdc_flags, 41 krb5_ccache, krb5_creds *, krb5_principal, 42 Ticket *, krb5_creds **, krb5_creds ***); 43 44 /* 45 * Take the `body' and encode it into `padata' using the credentials 46 * in `creds'. 47 */ 48 49 static krb5_error_code 50 make_pa_tgs_req(krb5_context context, 51 krb5_auth_context ac, 52 KDC_REQ_BODY *body, 53 PA_DATA *padata, 54 krb5_creds *creds) 55 { 56 u_char *buf; 57 size_t buf_size; 58 size_t len = 0; 59 krb5_data in_data; 60 krb5_error_code ret; 61 62 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); 63 if (ret) 64 goto out; 65 if(buf_size != len) 66 krb5_abortx(context, "internal error in ASN.1 encoder"); 67 68 in_data.length = len; 69 in_data.data = buf; 70 ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, creds, 71 &padata->padata_value, 72 KRB5_KU_TGS_REQ_AUTH_CKSUM, 73 KRB5_KU_TGS_REQ_AUTH); 74 out: 75 free (buf); 76 if(ret) 77 return ret; 78 padata->padata_type = KRB5_PADATA_TGS_REQ; 79 return 0; 80 } 81 82 /* 83 * Set the `enc-authorization-data' in `req_body' based on `authdata' 84 */ 85 86 static krb5_error_code 87 set_auth_data (krb5_context context, 88 KDC_REQ_BODY *req_body, 89 krb5_authdata *authdata, 90 krb5_keyblock *subkey) 91 { 92 if(authdata->len) { 93 size_t len = 0, buf_size; 94 unsigned char *buf; 95 krb5_crypto crypto; 96 krb5_error_code ret; 97 98 ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, 99 &len, ret); 100 if (ret) 101 return ret; 102 if (buf_size != len) 103 krb5_abortx(context, "internal error in ASN.1 encoder"); 104 105 ALLOC(req_body->enc_authorization_data, 1); 106 if (req_body->enc_authorization_data == NULL) { 107 free (buf); 108 krb5_set_error_message(context, ENOMEM, 109 N_("malloc: out of memory", "")); 110 return ENOMEM; 111 } 112 ret = krb5_crypto_init(context, subkey, 0, &crypto); 113 if (ret) { 114 free (buf); 115 free (req_body->enc_authorization_data); 116 req_body->enc_authorization_data = NULL; 117 return ret; 118 } 119 krb5_encrypt_EncryptedData(context, 120 crypto, 121 KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, 122 buf, 123 len, 124 0, 125 req_body->enc_authorization_data); 126 free (buf); 127 krb5_crypto_destroy(context, crypto); 128 } else { 129 req_body->enc_authorization_data = NULL; 130 } 131 return 0; 132 } 133 134 /* 135 * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' 136 * (if not-NULL), `in_creds', `krbtgt', and returning the generated 137 * subkey in `subkey'. 138 */ 139 140 static krb5_error_code 141 init_tgs_req (krb5_context context, 142 krb5_ccache ccache, 143 krb5_addresses *addresses, 144 krb5_kdc_flags flags, 145 Ticket *second_ticket, 146 krb5_creds *in_creds, 147 krb5_creds *krbtgt, 148 unsigned nonce, 149 const METHOD_DATA *padata, 150 krb5_keyblock **subkey, 151 TGS_REQ *t) 152 { 153 krb5_auth_context ac = NULL; 154 krb5_error_code ret = 0; 155 156 memset(t, 0, sizeof(*t)); 157 t->pvno = 5; 158 t->msg_type = krb_tgs_req; 159 if (in_creds->session.keytype) { 160 ALLOC_SEQ(&t->req_body.etype, 1); 161 if(t->req_body.etype.val == NULL) { 162 ret = ENOMEM; 163 krb5_set_error_message(context, ret, 164 N_("malloc: out of memory", "")); 165 goto fail; 166 } 167 t->req_body.etype.val[0] = in_creds->session.keytype; 168 } else { 169 ret = _krb5_init_etype(context, 170 KRB5_PDU_TGS_REQUEST, 171 &t->req_body.etype.len, 172 &t->req_body.etype.val, 173 NULL); 174 } 175 if (ret) 176 goto fail; 177 t->req_body.addresses = addresses; 178 t->req_body.kdc_options = flags.b; 179 ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); 180 if (ret) 181 goto fail; 182 ALLOC(t->req_body.sname, 1); 183 if (t->req_body.sname == NULL) { 184 ret = ENOMEM; 185 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 186 goto fail; 187 } 188 189 /* some versions of some code might require that the client be 190 present in TGS-REQs, but this is clearly against the spec */ 191 192 ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); 193 if (ret) 194 goto fail; 195 196 /* req_body.till should be NULL if there is no endtime specified, 197 but old MIT code (like DCE secd) doesn't like that */ 198 ALLOC(t->req_body.till, 1); 199 if(t->req_body.till == NULL){ 200 ret = ENOMEM; 201 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 202 goto fail; 203 } 204 *t->req_body.till = in_creds->times.endtime; 205 206 t->req_body.nonce = nonce; 207 if(second_ticket){ 208 ALLOC(t->req_body.additional_tickets, 1); 209 if (t->req_body.additional_tickets == NULL) { 210 ret = ENOMEM; 211 krb5_set_error_message(context, ret, 212 N_("malloc: out of memory", "")); 213 goto fail; 214 } 215 ALLOC_SEQ(t->req_body.additional_tickets, 1); 216 if (t->req_body.additional_tickets->val == NULL) { 217 ret = ENOMEM; 218 krb5_set_error_message(context, ret, 219 N_("malloc: out of memory", "")); 220 goto fail; 221 } 222 ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); 223 if (ret) 224 goto fail; 225 } 226 ALLOC(t->padata, 1); 227 if (t->padata == NULL) { 228 ret = ENOMEM; 229 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 230 goto fail; 231 } 232 ALLOC_SEQ(t->padata, 1 + padata->len); 233 if (t->padata->val == NULL) { 234 ret = ENOMEM; 235 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 236 goto fail; 237 } 238 { 239 size_t i; 240 for (i = 0; i < padata->len; i++) { 241 ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); 242 if (ret) { 243 krb5_set_error_message(context, ret, 244 N_("malloc: out of memory", "")); 245 goto fail; 246 } 247 } 248 } 249 250 ret = krb5_auth_con_init(context, &ac); 251 if(ret) 252 goto fail; 253 254 ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session); 255 if (ret) 256 goto fail; 257 258 ret = set_auth_data (context, &t->req_body, &in_creds->authdata, 259 ac->local_subkey); 260 if (ret) 261 goto fail; 262 263 ret = make_pa_tgs_req(context, 264 ac, 265 &t->req_body, 266 &t->padata->val[0], 267 krbtgt); 268 if(ret) 269 goto fail; 270 271 ret = krb5_auth_con_getlocalsubkey(context, ac, subkey); 272 if (ret) 273 goto fail; 274 275 fail: 276 if (ac) 277 krb5_auth_con_free(context, ac); 278 if (ret) { 279 t->req_body.addresses = NULL; 280 free_TGS_REQ (t); 281 } 282 return ret; 283 } 284 285 krb5_error_code 286 _krb5_get_krbtgt(krb5_context context, 287 krb5_ccache id, 288 krb5_realm realm, 289 krb5_creds **cred) 290 { 291 krb5_error_code ret; 292 krb5_creds tmp_cred; 293 294 memset(&tmp_cred, 0, sizeof(tmp_cred)); 295 296 ret = krb5_cc_get_principal(context, id, &tmp_cred.client); 297 if (ret) 298 return ret; 299 300 ret = krb5_make_principal(context, 301 &tmp_cred.server, 302 realm, 303 KRB5_TGS_NAME, 304 realm, 305 NULL); 306 if(ret) { 307 krb5_free_principal(context, tmp_cred.client); 308 return ret; 309 } 310 ret = krb5_get_credentials(context, 311 KRB5_GC_CACHED, 312 id, 313 &tmp_cred, 314 cred); 315 krb5_free_principal(context, tmp_cred.client); 316 krb5_free_principal(context, tmp_cred.server); 317 if(ret) 318 return ret; 319 return 0; 320 } 321 322 /* DCE compatible decrypt proc */ 323 static krb5_error_code KRB5_CALLCONV 324 decrypt_tkt_with_subkey (krb5_context context, 325 krb5_keyblock *key, 326 krb5_key_usage usage, 327 krb5_const_pointer skey, 328 krb5_kdc_rep *dec_rep) 329 { 330 const krb5_keyblock *subkey = skey; 331 krb5_error_code ret = 0; 332 krb5_data data; 333 size_t size; 334 krb5_crypto crypto; 335 336 assert(usage == 0); 337 338 krb5_data_zero(&data); 339 340 /* 341 * start out with trying with subkey if we have one 342 */ 343 if (subkey) { 344 ret = krb5_crypto_init(context, subkey, 0, &crypto); 345 if (ret) 346 return ret; 347 ret = krb5_decrypt_EncryptedData (context, 348 crypto, 349 KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, 350 &dec_rep->kdc_rep.enc_part, 351 &data); 352 /* 353 * If the is Windows 2000 DC, we need to retry with key usage 354 * 8 when doing ARCFOUR. 355 */ 356 if (ret && subkey->keytype == ETYPE_ARCFOUR_HMAC_MD5) { 357 ret = krb5_decrypt_EncryptedData(context, 358 crypto, 359 8, 360 &dec_rep->kdc_rep.enc_part, 361 &data); 362 } 363 krb5_crypto_destroy(context, crypto); 364 } 365 if (subkey == NULL || ret) { 366 ret = krb5_crypto_init(context, key, 0, &crypto); 367 if (ret) 368 return ret; 369 ret = krb5_decrypt_EncryptedData (context, 370 crypto, 371 KRB5_KU_TGS_REP_ENC_PART_SESSION, 372 &dec_rep->kdc_rep.enc_part, 373 &data); 374 krb5_crypto_destroy(context, crypto); 375 } 376 if (ret) 377 return ret; 378 379 ret = decode_EncASRepPart(data.data, 380 data.length, 381 &dec_rep->enc_part, 382 &size); 383 if (ret) 384 ret = decode_EncTGSRepPart(data.data, 385 data.length, 386 &dec_rep->enc_part, 387 &size); 388 if (ret) 389 krb5_set_error_message(context, ret, 390 N_("Failed to decode encpart in ticket", "")); 391 krb5_data_free (&data); 392 return ret; 393 } 394 395 static krb5_error_code 396 get_cred_kdc(krb5_context context, 397 krb5_ccache id, 398 krb5_kdc_flags flags, 399 krb5_addresses *addresses, 400 krb5_creds *in_creds, 401 krb5_creds *krbtgt, 402 krb5_principal impersonate_principal, 403 Ticket *second_ticket, 404 krb5_creds *out_creds) 405 { 406 TGS_REQ req; 407 krb5_data enc; 408 krb5_data resp; 409 krb5_kdc_rep rep; 410 KRB_ERROR error; 411 krb5_error_code ret; 412 unsigned nonce; 413 krb5_keyblock *subkey = NULL; 414 size_t len = 0; 415 Ticket second_ticket_data; 416 METHOD_DATA padata; 417 418 krb5_data_zero(&resp); 419 krb5_data_zero(&enc); 420 padata.val = NULL; 421 padata.len = 0; 422 423 krb5_generate_random_block(&nonce, sizeof(nonce)); 424 nonce &= 0xffffffff; 425 426 if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ 427 ret = decode_Ticket(in_creds->second_ticket.data, 428 in_creds->second_ticket.length, 429 &second_ticket_data, &len); 430 if(ret) 431 return ret; 432 second_ticket = &second_ticket_data; 433 } 434 435 436 if (impersonate_principal) { 437 krb5_crypto crypto; 438 PA_S4U2Self self; 439 krb5_data data; 440 void *buf; 441 size_t size = 0; 442 443 self.name = impersonate_principal->name; 444 self.realm = impersonate_principal->realm; 445 self.auth = estrdup("Kerberos"); 446 447 ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); 448 if (ret) { 449 free(self.auth); 450 goto out; 451 } 452 453 ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); 454 if (ret) { 455 free(self.auth); 456 krb5_data_free(&data); 457 goto out; 458 } 459 460 ret = krb5_create_checksum(context, 461 crypto, 462 KRB5_KU_OTHER_CKSUM, 463 0, 464 data.data, 465 data.length, 466 &self.cksum); 467 krb5_crypto_destroy(context, crypto); 468 krb5_data_free(&data); 469 if (ret) { 470 free(self.auth); 471 goto out; 472 } 473 474 ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); 475 free(self.auth); 476 free_Checksum(&self.cksum); 477 if (ret) 478 goto out; 479 if (len != size) 480 krb5_abortx(context, "internal asn1 error"); 481 482 ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); 483 if (ret) 484 goto out; 485 } 486 487 ret = init_tgs_req (context, 488 id, 489 addresses, 490 flags, 491 second_ticket, 492 in_creds, 493 krbtgt, 494 nonce, 495 &padata, 496 &subkey, 497 &req); 498 if (ret) 499 goto out; 500 501 ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); 502 if (ret) 503 goto out; 504 if(enc.length != len) 505 krb5_abortx(context, "internal error in ASN.1 encoder"); 506 507 /* don't free addresses */ 508 req.req_body.addresses = NULL; 509 free_TGS_REQ(&req); 510 511 /* 512 * Send and receive 513 */ 514 { 515 krb5_sendto_ctx stctx; 516 ret = krb5_sendto_ctx_alloc(context, &stctx); 517 if (ret) 518 return ret; 519 krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); 520 521 ret = krb5_sendto_context (context, stctx, &enc, 522 krbtgt->server->name.name_string.val[1], 523 &resp); 524 krb5_sendto_ctx_free(context, stctx); 525 } 526 if(ret) 527 goto out; 528 529 memset(&rep, 0, sizeof(rep)); 530 if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) { 531 unsigned eflags = 0; 532 533 ret = krb5_copy_principal(context, 534 in_creds->client, 535 &out_creds->client); 536 if(ret) 537 goto out2; 538 ret = krb5_copy_principal(context, 539 in_creds->server, 540 &out_creds->server); 541 if(ret) 542 goto out2; 543 /* this should go someplace else */ 544 out_creds->times.endtime = in_creds->times.endtime; 545 546 /* XXX should do better testing */ 547 if (flags.b.constrained_delegation || impersonate_principal) 548 eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; 549 550 ret = _krb5_extract_ticket(context, 551 &rep, 552 out_creds, 553 &krbtgt->session, 554 NULL, 555 0, 556 &krbtgt->addresses, 557 nonce, 558 eflags, 559 decrypt_tkt_with_subkey, 560 subkey); 561 out2: 562 krb5_free_kdc_rep(context, &rep); 563 } else if(krb5_rd_error(context, &resp, &error) == 0) { 564 ret = krb5_error_from_rd_error(context, &error, in_creds); 565 krb5_free_error_contents(context, &error); 566 } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { 567 ret = KRB5KRB_AP_ERR_V4_REPLY; 568 krb5_clear_error_message(context); 569 } else { 570 ret = KRB5KRB_AP_ERR_MSG_TYPE; 571 krb5_clear_error_message(context); 572 } 573 574 out: 575 if (second_ticket == &second_ticket_data) 576 free_Ticket(&second_ticket_data); 577 free_METHOD_DATA(&padata); 578 krb5_data_free(&resp); 579 krb5_data_free(&enc); 580 if(subkey) 581 krb5_free_keyblock(context, subkey); 582 return ret; 583 584 } 585 586 /* 587 * same as above, just get local addresses first if the krbtgt have 588 * them and the realm is not addressless 589 */ 590 591 static krb5_error_code 592 get_cred_kdc_address(krb5_context context, 593 krb5_ccache id, 594 krb5_kdc_flags flags, 595 krb5_addresses *addrs, 596 krb5_creds *in_creds, 597 krb5_creds *krbtgt, 598 krb5_principal impersonate_principal, 599 Ticket *second_ticket, 600 krb5_creds *out_creds) 601 { 602 krb5_error_code ret; 603 krb5_addresses addresses = { 0, NULL }; 604 605 /* 606 * Inherit the address-ness of the krbtgt if the address is not 607 * specified. 608 */ 609 610 if (addrs == NULL && krbtgt->addresses.len != 0) { 611 krb5_boolean noaddr; 612 613 krb5_appdefault_boolean(context, NULL, krbtgt->server->realm, 614 "no-addresses", FALSE, &noaddr); 615 616 if (!noaddr) { 617 krb5_get_all_client_addrs(context, &addresses); 618 /* XXX this sucks. */ 619 addrs = &addresses; 620 if(addresses.len == 0) 621 addrs = NULL; 622 } 623 } 624 ret = get_cred_kdc(context, id, flags, addrs, in_creds, 625 krbtgt, impersonate_principal, 626 second_ticket, out_creds); 627 krb5_free_addresses(context, &addresses); 628 return ret; 629 } 630 631 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 632 krb5_get_kdc_cred(krb5_context context, 633 krb5_ccache id, 634 krb5_kdc_flags flags, 635 krb5_addresses *addresses, 636 Ticket *second_ticket, 637 krb5_creds *in_creds, 638 krb5_creds **out_creds 639 ) 640 { 641 krb5_error_code ret; 642 krb5_creds *krbtgt; 643 644 *out_creds = calloc(1, sizeof(**out_creds)); 645 if(*out_creds == NULL) { 646 krb5_set_error_message(context, ENOMEM, 647 N_("malloc: out of memory", "")); 648 return ENOMEM; 649 } 650 ret = _krb5_get_krbtgt (context, 651 id, 652 in_creds->server->realm, 653 &krbtgt); 654 if(ret) { 655 free(*out_creds); 656 *out_creds = NULL; 657 return ret; 658 } 659 ret = get_cred_kdc(context, id, flags, addresses, 660 in_creds, krbtgt, NULL, NULL, *out_creds); 661 krb5_free_creds (context, krbtgt); 662 if(ret) { 663 free(*out_creds); 664 *out_creds = NULL; 665 } 666 return ret; 667 } 668 669 static int 670 not_found(krb5_context context, krb5_const_principal p, krb5_error_code code) 671 { 672 krb5_error_code ret; 673 char *str; 674 675 ret = krb5_unparse_name(context, p, &str); 676 if(ret) { 677 krb5_clear_error_message(context); 678 return code; 679 } 680 krb5_set_error_message(context, code, 681 N_("Matching credential (%s) not found", ""), str); 682 free(str); 683 return code; 684 } 685 686 static krb5_error_code 687 find_cred(krb5_context context, 688 krb5_ccache id, 689 krb5_principal server, 690 krb5_creds **tgts, 691 krb5_creds *out_creds) 692 { 693 krb5_error_code ret; 694 krb5_creds mcreds; 695 696 krb5_cc_clear_mcred(&mcreds); 697 mcreds.server = server; 698 ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 699 &mcreds, out_creds); 700 if(ret == 0) 701 return 0; 702 while(tgts && *tgts){ 703 if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 704 &mcreds, *tgts)){ 705 ret = krb5_copy_creds_contents(context, *tgts, out_creds); 706 return ret; 707 } 708 tgts++; 709 } 710 return not_found(context, server, KRB5_CC_NOTFOUND); 711 } 712 713 static krb5_error_code 714 add_cred(krb5_context context, krb5_creds const *tkt, krb5_creds ***tgts) 715 { 716 int i; 717 krb5_error_code ret; 718 krb5_creds **tmp = *tgts; 719 720 for(i = 0; tmp && tmp[i]; i++); /* XXX */ 721 tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 722 if(tmp == NULL) { 723 krb5_set_error_message(context, ENOMEM, 724 N_("malloc: out of memory", "")); 725 return ENOMEM; 726 } 727 *tgts = tmp; 728 ret = krb5_copy_creds(context, tkt, &tmp[i]); 729 tmp[i+1] = NULL; 730 return ret; 731 } 732 733 static krb5_error_code 734 get_cred_kdc_capath_worker(krb5_context context, 735 krb5_kdc_flags flags, 736 krb5_ccache ccache, 737 krb5_creds *in_creds, 738 krb5_const_realm try_realm, 739 krb5_principal impersonate_principal, 740 Ticket *second_ticket, 741 krb5_creds **out_creds, 742 krb5_creds ***ret_tgts) 743 { 744 krb5_error_code ret; 745 krb5_creds *tgt, tmp_creds; 746 krb5_const_realm client_realm, server_realm; 747 int ok_as_delegate = 1; 748 749 *out_creds = NULL; 750 751 client_realm = krb5_principal_get_realm(context, in_creds->client); 752 server_realm = krb5_principal_get_realm(context, in_creds->server); 753 memset(&tmp_creds, 0, sizeof(tmp_creds)); 754 ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 755 if(ret) 756 return ret; 757 758 ret = krb5_make_principal(context, 759 &tmp_creds.server, 760 try_realm, 761 KRB5_TGS_NAME, 762 server_realm, 763 NULL); 764 if(ret){ 765 krb5_free_principal(context, tmp_creds.client); 766 return ret; 767 } 768 { 769 krb5_creds tgts; 770 771 ret = find_cred(context, ccache, tmp_creds.server, 772 *ret_tgts, &tgts); 773 if(ret == 0){ 774 /* only allow implicit ok_as_delegate if the realm is the clients realm */ 775 if (strcmp(try_realm, client_realm) != 0 || strcmp(try_realm, server_realm) != 0) 776 ok_as_delegate = tgts.flags.b.ok_as_delegate; 777 778 *out_creds = calloc(1, sizeof(**out_creds)); 779 if(*out_creds == NULL) { 780 ret = ENOMEM; 781 krb5_set_error_message(context, ret, 782 N_("malloc: out of memory", "")); 783 } else { 784 ret = get_cred_kdc_address(context, ccache, flags, NULL, 785 in_creds, &tgts, 786 impersonate_principal, 787 second_ticket, 788 *out_creds); 789 if (ret) { 790 free (*out_creds); 791 *out_creds = NULL; 792 } else if (ok_as_delegate == 0) 793 (*out_creds)->flags.b.ok_as_delegate = 0; 794 } 795 krb5_free_cred_contents(context, &tgts); 796 krb5_free_principal(context, tmp_creds.server); 797 krb5_free_principal(context, tmp_creds.client); 798 return ret; 799 } 800 } 801 if(krb5_realm_compare(context, in_creds->client, in_creds->server)) 802 return not_found(context, in_creds->server, KRB5_CC_NOTFOUND); 803 804 /* XXX this can loop forever */ 805 while(1){ 806 heim_general_string tgt_inst; 807 808 ret = get_cred_kdc_capath(context, flags, ccache, &tmp_creds, 809 NULL, NULL, &tgt, ret_tgts); 810 if(ret) { 811 krb5_free_principal(context, tmp_creds.server); 812 krb5_free_principal(context, tmp_creds.client); 813 return ret; 814 } 815 /* 816 * if either of the chain or the ok_as_delegate was stripped 817 * by the kdc, make sure we strip it too. 818 */ 819 if (ok_as_delegate == 0 || tgt->flags.b.ok_as_delegate == 0) { 820 ok_as_delegate = 0; 821 tgt->flags.b.ok_as_delegate = 0; 822 } 823 824 ret = add_cred(context, tgt, ret_tgts); 825 if(ret) { 826 krb5_free_principal(context, tmp_creds.server); 827 krb5_free_principal(context, tmp_creds.client); 828 return ret; 829 } 830 tgt_inst = tgt->server->name.name_string.val[1]; 831 if(strcmp(tgt_inst, server_realm) == 0) 832 break; 833 krb5_free_principal(context, tmp_creds.server); 834 tmp_creds.server = NULL; 835 ret = krb5_make_principal(context, &tmp_creds.server, 836 tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 837 if(ret) { 838 krb5_free_principal(context, tmp_creds.server); 839 krb5_free_principal(context, tmp_creds.client); 840 return ret; 841 } 842 ret = krb5_free_creds(context, tgt); 843 if(ret) { 844 krb5_free_principal(context, tmp_creds.server); 845 krb5_free_principal(context, tmp_creds.client); 846 return ret; 847 } 848 } 849 850 krb5_free_principal(context, tmp_creds.server); 851 krb5_free_principal(context, tmp_creds.client); 852 *out_creds = calloc(1, sizeof(**out_creds)); 853 if(*out_creds == NULL) { 854 ret = ENOMEM; 855 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 856 } else { 857 ret = get_cred_kdc_address (context, ccache, flags, NULL, 858 in_creds, tgt, impersonate_principal, 859 second_ticket, *out_creds); 860 if (ret) { 861 free (*out_creds); 862 *out_creds = NULL; 863 } 864 } 865 krb5_free_creds(context, tgt); 866 return ret; 867 } 868 869 /* 870 get_cred(server) 871 creds = cc_get_cred(server) 872 if(creds) return creds 873 tgt = cc_get_cred(krbtgt/server_realm@any_realm) 874 if(tgt) 875 return get_cred_tgt(server, tgt) 876 if(client_realm == server_realm) 877 return NULL 878 tgt = get_cred(krbtgt/server_realm@client_realm) 879 while(tgt_inst != server_realm) 880 tgt = get_cred(krbtgt/server_realm@tgt_inst) 881 return get_cred_tgt(server, tgt) 882 */ 883 884 static krb5_error_code 885 get_cred_kdc_capath(krb5_context context, 886 krb5_kdc_flags flags, 887 krb5_ccache ccache, 888 krb5_creds *in_creds, 889 krb5_principal impersonate_principal, 890 Ticket *second_ticket, 891 krb5_creds **out_creds, 892 krb5_creds ***ret_tgts) 893 { 894 krb5_error_code ret; 895 krb5_const_realm client_realm, server_realm, try_realm; 896 897 client_realm = krb5_principal_get_realm(context, in_creds->client); 898 server_realm = krb5_principal_get_realm(context, in_creds->server); 899 900 try_realm = client_realm; 901 ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, try_realm, 902 impersonate_principal, second_ticket, out_creds, 903 ret_tgts); 904 905 if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) { 906 try_realm = krb5_config_get_string(context, NULL, "capaths", 907 client_realm, server_realm, NULL); 908 909 if (try_realm != NULL && strcmp(try_realm, client_realm)) { 910 ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, 911 try_realm, impersonate_principal, 912 second_ticket, out_creds, ret_tgts); 913 } 914 } 915 916 return ret; 917 } 918 919 static krb5_error_code 920 get_cred_kdc_referral(krb5_context context, 921 krb5_kdc_flags flags, 922 krb5_ccache ccache, 923 krb5_creds *in_creds, 924 krb5_principal impersonate_principal, 925 Ticket *second_ticket, 926 krb5_creds **out_creds, 927 krb5_creds ***ret_tgts) 928 { 929 krb5_const_realm client_realm; 930 krb5_error_code ret; 931 krb5_creds tgt, referral, ticket; 932 int loop = 0; 933 int ok_as_delegate = 1; 934 935 if (in_creds->server->name.name_string.len < 2 && !flags.b.canonicalize) { 936 krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED, 937 N_("Name too short to do referals, skipping", "")); 938 return KRB5KDC_ERR_PATH_NOT_ACCEPTED; 939 } 940 941 memset(&tgt, 0, sizeof(tgt)); 942 memset(&ticket, 0, sizeof(ticket)); 943 944 flags.b.canonicalize = 1; 945 946 *out_creds = NULL; 947 948 client_realm = krb5_principal_get_realm(context, in_creds->client); 949 950 /* find tgt for the clients base realm */ 951 { 952 krb5_principal tgtname; 953 954 ret = krb5_make_principal(context, &tgtname, 955 client_realm, 956 KRB5_TGS_NAME, 957 client_realm, 958 NULL); 959 if(ret) 960 return ret; 961 962 ret = find_cred(context, ccache, tgtname, *ret_tgts, &tgt); 963 krb5_free_principal(context, tgtname); 964 if (ret) 965 return ret; 966 } 967 968 referral = *in_creds; 969 ret = krb5_copy_principal(context, in_creds->server, &referral.server); 970 if (ret) { 971 krb5_free_cred_contents(context, &tgt); 972 return ret; 973 } 974 ret = krb5_principal_set_realm(context, referral.server, client_realm); 975 if (ret) { 976 krb5_free_cred_contents(context, &tgt); 977 krb5_free_principal(context, referral.server); 978 return ret; 979 } 980 981 while (loop++ < 17) { 982 krb5_creds **tickets; 983 krb5_creds mcreds; 984 char *referral_realm; 985 986 /* Use cache if we are not doing impersonation or contrainte deleg */ 987 if (impersonate_principal == NULL || flags.b.constrained_delegation) { 988 krb5_cc_clear_mcred(&mcreds); 989 mcreds.server = referral.server; 990 ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &ticket); 991 } else 992 ret = EINVAL; 993 994 if (ret) { 995 ret = get_cred_kdc_address(context, ccache, flags, NULL, 996 &referral, &tgt, impersonate_principal, 997 second_ticket, &ticket); 998 if (ret) 999 goto out; 1000 } 1001 1002 /* Did we get the right ticket ? */ 1003 if (krb5_principal_compare_any_realm(context, 1004 referral.server, 1005 ticket.server)) 1006 break; 1007 1008 if (!krb5_principal_is_krbtgt(context, ticket.server)) { 1009 krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US, 1010 N_("Got back an non krbtgt " 1011 "ticket referrals", "")); 1012 ret = KRB5KRB_AP_ERR_NOT_US; 1013 goto out; 1014 } 1015 1016 referral_realm = ticket.server->name.name_string.val[1]; 1017 1018 /* check that there are no referrals loops */ 1019 tickets = *ret_tgts; 1020 1021 krb5_cc_clear_mcred(&mcreds); 1022 mcreds.server = ticket.server; 1023 1024 while(tickets && *tickets){ 1025 if(krb5_compare_creds(context, 1026 KRB5_TC_DONT_MATCH_REALM, 1027 &mcreds, 1028 *tickets)) 1029 { 1030 krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 1031 N_("Referral from %s " 1032 "loops back to realm %s", ""), 1033 tgt.server->realm, 1034 referral_realm); 1035 ret = KRB5_GET_IN_TKT_LOOP; 1036 goto out; 1037 } 1038 tickets++; 1039 } 1040 1041 /* 1042 * if either of the chain or the ok_as_delegate was stripped 1043 * by the kdc, make sure we strip it too. 1044 */ 1045 1046 if (ok_as_delegate == 0 || ticket.flags.b.ok_as_delegate == 0) { 1047 ok_as_delegate = 0; 1048 ticket.flags.b.ok_as_delegate = 0; 1049 } 1050 1051 ret = add_cred(context, &ticket, ret_tgts); 1052 if (ret) 1053 goto out; 1054 1055 /* try realm in the referral */ 1056 ret = krb5_principal_set_realm(context, 1057 referral.server, 1058 referral_realm); 1059 krb5_free_cred_contents(context, &tgt); 1060 tgt = ticket; 1061 memset(&ticket, 0, sizeof(ticket)); 1062 if (ret) 1063 goto out; 1064 } 1065 1066 ret = krb5_copy_creds(context, &ticket, out_creds); 1067 1068 out: 1069 krb5_free_principal(context, referral.server); 1070 krb5_free_cred_contents(context, &tgt); 1071 krb5_free_cred_contents(context, &ticket); 1072 return ret; 1073 } 1074 1075 1076 /* 1077 * Glue function between referrals version and old client chasing 1078 * codebase. 1079 */ 1080 1081 krb5_error_code 1082 _krb5_get_cred_kdc_any(krb5_context context, 1083 krb5_kdc_flags flags, 1084 krb5_ccache ccache, 1085 krb5_creds *in_creds, 1086 krb5_principal impersonate_principal, 1087 Ticket *second_ticket, 1088 krb5_creds **out_creds, 1089 krb5_creds ***ret_tgts) 1090 { 1091 krb5_error_code ret; 1092 krb5_deltat offset; 1093 1094 ret = krb5_cc_get_kdc_offset(context, ccache, &offset); 1095 if (ret) { 1096 context->kdc_sec_offset = offset; 1097 context->kdc_usec_offset = 0; 1098 } 1099 1100 ret = get_cred_kdc_referral(context, 1101 flags, 1102 ccache, 1103 in_creds, 1104 impersonate_principal, 1105 second_ticket, 1106 out_creds, 1107 ret_tgts); 1108 if (ret == 0 || flags.b.canonicalize) 1109 return ret; 1110 return get_cred_kdc_capath(context, 1111 flags, 1112 ccache, 1113 in_creds, 1114 impersonate_principal, 1115 second_ticket, 1116 out_creds, 1117 ret_tgts); 1118 } 1119 1120 1121 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1122 krb5_get_credentials_with_flags(krb5_context context, 1123 krb5_flags options, 1124 krb5_kdc_flags flags, 1125 krb5_ccache ccache, 1126 krb5_creds *in_creds, 1127 krb5_creds **out_creds) 1128 { 1129 krb5_error_code ret; 1130 krb5_creds **tgts; 1131 krb5_creds *res_creds; 1132 int i; 1133 1134 if (in_creds->session.keytype) { 1135 ret = krb5_enctype_valid(context, in_creds->session.keytype); 1136 if (ret) 1137 return ret; 1138 } 1139 1140 *out_creds = NULL; 1141 res_creds = calloc(1, sizeof(*res_creds)); 1142 if (res_creds == NULL) { 1143 krb5_set_error_message(context, ENOMEM, 1144 N_("malloc: out of memory", "")); 1145 return ENOMEM; 1146 } 1147 1148 if (in_creds->session.keytype) 1149 options |= KRB5_TC_MATCH_KEYTYPE; 1150 1151 /* 1152 * If we got a credential, check if credential is expired before 1153 * returning it. 1154 */ 1155 ret = krb5_cc_retrieve_cred(context, 1156 ccache, 1157 in_creds->session.keytype ? 1158 KRB5_TC_MATCH_KEYTYPE : 0, 1159 in_creds, res_creds); 1160 /* 1161 * If we got a credential, check if credential is expired before 1162 * returning it, but only if KRB5_GC_EXPIRED_OK is not set. 1163 */ 1164 if (ret == 0) { 1165 krb5_timestamp timeret; 1166 1167 /* If expired ok, don't bother checking */ 1168 if(options & KRB5_GC_EXPIRED_OK) { 1169 *out_creds = res_creds; 1170 return 0; 1171 } 1172 1173 krb5_timeofday(context, &timeret); 1174 if(res_creds->times.endtime > timeret) { 1175 *out_creds = res_creds; 1176 return 0; 1177 } 1178 if(options & KRB5_GC_CACHED) 1179 krb5_cc_remove_cred(context, ccache, 0, res_creds); 1180 1181 } else if(ret != KRB5_CC_END) { 1182 free(res_creds); 1183 return ret; 1184 } 1185 free(res_creds); 1186 if(options & KRB5_GC_CACHED) 1187 return not_found(context, in_creds->server, KRB5_CC_NOTFOUND); 1188 1189 if(options & KRB5_GC_USER_USER) 1190 flags.b.enc_tkt_in_skey = 1; 1191 if (flags.b.enc_tkt_in_skey) 1192 options |= KRB5_GC_NO_STORE; 1193 1194 tgts = NULL; 1195 ret = _krb5_get_cred_kdc_any(context, flags, ccache, 1196 in_creds, NULL, NULL, out_creds, &tgts); 1197 for(i = 0; tgts && tgts[i]; i++) { 1198 krb5_cc_store_cred(context, ccache, tgts[i]); 1199 krb5_free_creds(context, tgts[i]); 1200 } 1201 free(tgts); 1202 if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) 1203 krb5_cc_store_cred(context, ccache, *out_creds); 1204 return ret; 1205 } 1206 1207 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1208 krb5_get_credentials(krb5_context context, 1209 krb5_flags options, 1210 krb5_ccache ccache, 1211 krb5_creds *in_creds, 1212 krb5_creds **out_creds) 1213 { 1214 krb5_kdc_flags flags; 1215 flags.i = 0; 1216 return krb5_get_credentials_with_flags(context, options, flags, 1217 ccache, in_creds, out_creds); 1218 } 1219 1220 struct krb5_get_creds_opt_data { 1221 krb5_principal self; 1222 krb5_flags options; 1223 krb5_enctype enctype; 1224 Ticket *ticket; 1225 }; 1226 1227 1228 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1229 krb5_get_creds_opt_alloc(krb5_context context, krb5_get_creds_opt *opt) 1230 { 1231 *opt = calloc(1, sizeof(**opt)); 1232 if (*opt == NULL) { 1233 krb5_set_error_message(context, ENOMEM, 1234 N_("malloc: out of memory", "")); 1235 return ENOMEM; 1236 } 1237 return 0; 1238 } 1239 1240 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1241 krb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt) 1242 { 1243 if (opt->self) 1244 krb5_free_principal(context, opt->self); 1245 if (opt->ticket) { 1246 free_Ticket(opt->ticket); 1247 free(opt->ticket); 1248 } 1249 memset(opt, 0, sizeof(*opt)); 1250 free(opt); 1251 } 1252 1253 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1254 krb5_get_creds_opt_set_options(krb5_context context, 1255 krb5_get_creds_opt opt, 1256 krb5_flags options) 1257 { 1258 opt->options = options; 1259 } 1260 1261 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1262 krb5_get_creds_opt_add_options(krb5_context context, 1263 krb5_get_creds_opt opt, 1264 krb5_flags options) 1265 { 1266 opt->options |= options; 1267 } 1268 1269 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1270 krb5_get_creds_opt_set_enctype(krb5_context context, 1271 krb5_get_creds_opt opt, 1272 krb5_enctype enctype) 1273 { 1274 opt->enctype = enctype; 1275 } 1276 1277 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1278 krb5_get_creds_opt_set_impersonate(krb5_context context, 1279 krb5_get_creds_opt opt, 1280 krb5_const_principal self) 1281 { 1282 if (opt->self) 1283 krb5_free_principal(context, opt->self); 1284 return krb5_copy_principal(context, self, &opt->self); 1285 } 1286 1287 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1288 krb5_get_creds_opt_set_ticket(krb5_context context, 1289 krb5_get_creds_opt opt, 1290 const Ticket *ticket) 1291 { 1292 if (opt->ticket) { 1293 free_Ticket(opt->ticket); 1294 free(opt->ticket); 1295 opt->ticket = NULL; 1296 } 1297 if (ticket) { 1298 krb5_error_code ret; 1299 1300 opt->ticket = malloc(sizeof(*ticket)); 1301 if (opt->ticket == NULL) { 1302 krb5_set_error_message(context, ENOMEM, 1303 N_("malloc: out of memory", "")); 1304 return ENOMEM; 1305 } 1306 ret = copy_Ticket(ticket, opt->ticket); 1307 if (ret) { 1308 free(opt->ticket); 1309 opt->ticket = NULL; 1310 krb5_set_error_message(context, ret, 1311 N_("malloc: out of memory", "")); 1312 return ret; 1313 } 1314 } 1315 return 0; 1316 } 1317 1318 1319 1320 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1321 krb5_get_creds(krb5_context context, 1322 krb5_get_creds_opt opt, 1323 krb5_ccache ccache, 1324 krb5_const_principal inprinc, 1325 krb5_creds **out_creds) 1326 { 1327 krb5_kdc_flags flags; 1328 krb5_flags options; 1329 krb5_creds in_creds; 1330 krb5_error_code ret; 1331 krb5_creds **tgts; 1332 krb5_creds *res_creds; 1333 int i; 1334 1335 if (opt && opt->enctype) { 1336 ret = krb5_enctype_valid(context, opt->enctype); 1337 if (ret) 1338 return ret; 1339 } 1340 1341 memset(&in_creds, 0, sizeof(in_creds)); 1342 in_creds.server = rk_UNCONST(inprinc); 1343 1344 ret = krb5_cc_get_principal(context, ccache, &in_creds.client); 1345 if (ret) 1346 return ret; 1347 1348 if (opt) 1349 options = opt->options; 1350 else 1351 options = 0; 1352 flags.i = 0; 1353 1354 *out_creds = NULL; 1355 res_creds = calloc(1, sizeof(*res_creds)); 1356 if (res_creds == NULL) { 1357 krb5_free_principal(context, in_creds.client); 1358 krb5_set_error_message(context, ENOMEM, 1359 N_("malloc: out of memory", "")); 1360 return ENOMEM; 1361 } 1362 1363 if (opt && opt->enctype) { 1364 in_creds.session.keytype = opt->enctype; 1365 options |= KRB5_TC_MATCH_KEYTYPE; 1366 } 1367 1368 /* 1369 * If we got a credential, check if credential is expired before 1370 * returning it. 1371 */ 1372 ret = krb5_cc_retrieve_cred(context, 1373 ccache, 1374 options & KRB5_TC_MATCH_KEYTYPE, 1375 &in_creds, res_creds); 1376 /* 1377 * If we got a credential, check if credential is expired before 1378 * returning it, but only if KRB5_GC_EXPIRED_OK is not set. 1379 */ 1380 if (ret == 0) { 1381 krb5_timestamp timeret; 1382 1383 /* If expired ok, don't bother checking */ 1384 if(options & KRB5_GC_EXPIRED_OK) { 1385 *out_creds = res_creds; 1386 krb5_free_principal(context, in_creds.client); 1387 goto out; 1388 } 1389 1390 krb5_timeofday(context, &timeret); 1391 if(res_creds->times.endtime > timeret) { 1392 *out_creds = res_creds; 1393 krb5_free_principal(context, in_creds.client); 1394 goto out; 1395 } 1396 if(options & KRB5_GC_CACHED) 1397 krb5_cc_remove_cred(context, ccache, 0, res_creds); 1398 1399 } else if(ret != KRB5_CC_END) { 1400 free(res_creds); 1401 krb5_free_principal(context, in_creds.client); 1402 goto out; 1403 } 1404 free(res_creds); 1405 if(options & KRB5_GC_CACHED) { 1406 krb5_free_principal(context, in_creds.client); 1407 ret = not_found(context, in_creds.server, KRB5_CC_NOTFOUND); 1408 goto out; 1409 } 1410 if(options & KRB5_GC_USER_USER) { 1411 flags.b.enc_tkt_in_skey = 1; 1412 options |= KRB5_GC_NO_STORE; 1413 } 1414 if (options & KRB5_GC_FORWARDABLE) 1415 flags.b.forwardable = 1; 1416 if (options & KRB5_GC_NO_TRANSIT_CHECK) 1417 flags.b.disable_transited_check = 1; 1418 if (options & KRB5_GC_CONSTRAINED_DELEGATION) { 1419 flags.b.request_anonymous = 1; /* XXX ARGH confusion */ 1420 flags.b.constrained_delegation = 1; 1421 } 1422 if (options & KRB5_GC_CANONICALIZE) 1423 flags.b.canonicalize = 1; 1424 1425 tgts = NULL; 1426 ret = _krb5_get_cred_kdc_any(context, flags, ccache, 1427 &in_creds, opt->self, opt->ticket, 1428 out_creds, &tgts); 1429 krb5_free_principal(context, in_creds.client); 1430 for(i = 0; tgts && tgts[i]; i++) { 1431 krb5_cc_store_cred(context, ccache, tgts[i]); 1432 krb5_free_creds(context, tgts[i]); 1433 } 1434 free(tgts); 1435 if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) 1436 krb5_cc_store_cred(context, ccache, *out_creds); 1437 1438 out: 1439 _krb5_debug(context, 5, "krb5_get_creds: ret = %d", ret); 1440 1441 return ret; 1442 } 1443 1444 /* 1445 * 1446 */ 1447 1448 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1449 krb5_get_renewed_creds(krb5_context context, 1450 krb5_creds *creds, 1451 krb5_const_principal client, 1452 krb5_ccache ccache, 1453 const char *in_tkt_service) 1454 { 1455 krb5_error_code ret; 1456 krb5_kdc_flags flags; 1457 krb5_creds in, *template, *out = NULL; 1458 1459 memset(&in, 0, sizeof(in)); 1460 memset(creds, 0, sizeof(*creds)); 1461 1462 ret = krb5_copy_principal(context, client, &in.client); 1463 if (ret) 1464 return ret; 1465 1466 if (in_tkt_service) { 1467 ret = krb5_parse_name(context, in_tkt_service, &in.server); 1468 if (ret) { 1469 krb5_free_principal(context, in.client); 1470 return ret; 1471 } 1472 } else { 1473 const char *realm = krb5_principal_get_realm(context, client); 1474 1475 ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, 1476 realm, NULL); 1477 if (ret) { 1478 krb5_free_principal(context, in.client); 1479 return ret; 1480 } 1481 } 1482 1483 flags.i = 0; 1484 flags.b.renewable = flags.b.renew = 1; 1485 1486 /* 1487 * Get template from old credential cache for the same entry, if 1488 * this failes, no worries. 1489 */ 1490 ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &in, &template); 1491 if (ret == 0) { 1492 flags.b.forwardable = template->flags.b.forwardable; 1493 flags.b.proxiable = template->flags.b.proxiable; 1494 krb5_free_creds (context, template); 1495 } 1496 1497 ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &in, &out); 1498 krb5_free_principal(context, in.client); 1499 krb5_free_principal(context, in.server); 1500 if (ret) 1501 return ret; 1502 1503 ret = krb5_copy_creds_contents(context, out, creds); 1504 krb5_free_creds(context, out); 1505 1506 return ret; 1507 } 1508