1 /* 2 * Copyright (c) 1997 - 2000 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_in_tkt.c,v 1.94 2000/02/06 05:18:20 assar Exp $"); 37 38 krb5_error_code 39 krb5_init_etype (krb5_context context, 40 unsigned *len, 41 int **val, 42 const krb5_enctype *etypes) 43 { 44 int i; 45 krb5_error_code ret; 46 krb5_enctype *tmp; 47 48 ret = 0; 49 if (etypes) 50 tmp = (krb5_enctype*)etypes; 51 else { 52 ret = krb5_get_default_in_tkt_etypes(context, 53 &tmp); 54 if (ret) 55 return ret; 56 } 57 58 for (i = 0; tmp[i]; ++i) 59 ; 60 *len = i; 61 *val = malloc(i * sizeof(int)); 62 if (i != 0 && *val == NULL) { 63 ret = ENOMEM; 64 goto cleanup; 65 } 66 memmove (*val, 67 tmp, 68 i * sizeof(*tmp)); 69 cleanup: 70 if (etypes == NULL) 71 free (tmp); 72 return ret; 73 } 74 75 76 static krb5_error_code 77 decrypt_tkt (krb5_context context, 78 krb5_keyblock *key, 79 krb5_key_usage usage, 80 krb5_const_pointer decrypt_arg, 81 krb5_kdc_rep *dec_rep) 82 { 83 krb5_error_code ret; 84 krb5_data data; 85 size_t size; 86 krb5_crypto crypto; 87 88 krb5_crypto_init(context, key, 0, &crypto); 89 90 ret = krb5_decrypt_EncryptedData (context, 91 crypto, 92 usage, 93 &dec_rep->kdc_rep.enc_part, 94 &data); 95 krb5_crypto_destroy(context, crypto); 96 97 if (ret) 98 return ret; 99 100 ret = krb5_decode_EncASRepPart(context, 101 data.data, 102 data.length, 103 &dec_rep->enc_part, 104 &size); 105 if (ret) 106 ret = krb5_decode_EncTGSRepPart(context, 107 data.data, 108 data.length, 109 &dec_rep->enc_part, 110 &size); 111 krb5_data_free (&data); 112 if (ret) 113 return ret; 114 return 0; 115 } 116 117 int 118 _krb5_extract_ticket(krb5_context context, 119 krb5_kdc_rep *rep, 120 krb5_creds *creds, 121 krb5_keyblock *key, 122 krb5_const_pointer keyseed, 123 krb5_key_usage key_usage, 124 krb5_addresses *addrs, 125 unsigned nonce, 126 krb5_boolean allow_server_mismatch, 127 krb5_decrypt_proc decrypt_proc, 128 krb5_const_pointer decryptarg) 129 { 130 krb5_error_code ret; 131 krb5_principal tmp_principal; 132 int tmp; 133 time_t tmp_time; 134 krb5_timestamp sec_now; 135 136 /* compare client */ 137 138 ret = principalname2krb5_principal (&tmp_principal, 139 rep->kdc_rep.cname, 140 rep->kdc_rep.crealm); 141 if (ret) 142 goto out; 143 tmp = krb5_principal_compare (context, tmp_principal, creds->client); 144 krb5_free_principal (context, tmp_principal); 145 if (!tmp) { 146 ret = KRB5KRB_AP_ERR_MODIFIED; 147 goto out; 148 } 149 150 /* extract ticket */ 151 { 152 unsigned char *buf; 153 size_t len; 154 len = length_Ticket(&rep->kdc_rep.ticket); 155 buf = malloc(len); 156 if(buf == NULL) { 157 ret = ENOMEM; 158 goto out; 159 } 160 encode_Ticket(buf + len - 1, len, &rep->kdc_rep.ticket, &len); 161 creds->ticket.data = buf; 162 creds->ticket.length = len; 163 creds->second_ticket.length = 0; 164 creds->second_ticket.data = NULL; 165 } 166 167 /* compare server */ 168 169 ret = principalname2krb5_principal (&tmp_principal, 170 rep->kdc_rep.ticket.sname, 171 rep->kdc_rep.ticket.realm); 172 if (ret) 173 goto out; 174 if(allow_server_mismatch){ 175 krb5_free_principal(context, creds->server); 176 creds->server = tmp_principal; 177 tmp_principal = NULL; 178 }else{ 179 tmp = krb5_principal_compare (context, tmp_principal, creds->server); 180 krb5_free_principal (context, tmp_principal); 181 if (!tmp) { 182 ret = KRB5KRB_AP_ERR_MODIFIED; 183 goto out; 184 } 185 } 186 187 /* decrypt */ 188 189 if (decrypt_proc == NULL) 190 decrypt_proc = decrypt_tkt; 191 192 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); 193 if (ret) 194 goto out; 195 196 #if 0 197 /* XXX should this decode be here, or in the decrypt_proc? */ 198 ret = krb5_decode_keyblock(context, &rep->enc_part.key, 1); 199 if(ret) 200 goto out; 201 #endif 202 203 /* compare nonces */ 204 205 if (nonce != rep->enc_part.nonce) { 206 ret = KRB5KRB_AP_ERR_MODIFIED; 207 goto out; 208 } 209 210 /* set kdc-offset */ 211 212 krb5_timeofday (context, &sec_now); 213 if (context->kdc_sec_offset == 0 214 && krb5_config_get_bool (context, NULL, 215 "libdefaults", 216 "kdc_timesync", 217 NULL)) { 218 context->kdc_sec_offset = rep->enc_part.authtime - sec_now; 219 krb5_timeofday (context, &sec_now); 220 } 221 222 /* check all times */ 223 224 if (rep->enc_part.starttime) { 225 tmp_time = *rep->enc_part.starttime; 226 } else 227 tmp_time = rep->enc_part.authtime; 228 229 if (creds->times.starttime == 0 230 && abs(tmp_time - sec_now) > context->max_skew) { 231 ret = KRB5KRB_AP_ERR_SKEW; 232 goto out; 233 } 234 235 if (creds->times.starttime != 0 236 && tmp_time != creds->times.starttime) { 237 ret = KRB5KRB_AP_ERR_MODIFIED; 238 goto out; 239 } 240 241 creds->times.starttime = tmp_time; 242 243 if (rep->enc_part.renew_till) { 244 tmp_time = *rep->enc_part.renew_till; 245 } else 246 tmp_time = 0; 247 248 if (creds->times.renew_till != 0 249 && tmp_time > creds->times.renew_till) { 250 ret = KRB5KRB_AP_ERR_MODIFIED; 251 goto out; 252 } 253 254 creds->times.renew_till = tmp_time; 255 256 creds->times.authtime = rep->enc_part.authtime; 257 258 if (creds->times.endtime != 0 259 && rep->enc_part.endtime > creds->times.endtime) { 260 ret = KRB5KRB_AP_ERR_MODIFIED; 261 goto out; 262 } 263 264 creds->times.endtime = rep->enc_part.endtime; 265 266 if(rep->enc_part.caddr) 267 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); 268 else if(addrs) 269 krb5_copy_addresses (context, addrs, &creds->addresses); 270 else { 271 creds->addresses.len = 0; 272 creds->addresses.val = NULL; 273 } 274 creds->flags.b = rep->enc_part.flags; 275 276 creds->authdata.len = 0; 277 creds->authdata.val = NULL; 278 creds->session.keyvalue.length = 0; 279 creds->session.keyvalue.data = NULL; 280 creds->session.keytype = rep->enc_part.key.keytype; 281 ret = krb5_data_copy (&creds->session.keyvalue, 282 rep->enc_part.key.keyvalue.data, 283 rep->enc_part.key.keyvalue.length); 284 285 out: 286 memset (rep->enc_part.key.keyvalue.data, 0, 287 rep->enc_part.key.keyvalue.length); 288 return ret; 289 } 290 291 292 static krb5_error_code 293 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, 294 krb5_enctype etype, krb5_keyblock *key) 295 { 296 PA_ENC_TS_ENC p; 297 u_char buf[1024]; 298 size_t len; 299 EncryptedData encdata; 300 krb5_error_code ret; 301 int32_t sec, usec; 302 int usec2; 303 krb5_crypto crypto; 304 305 krb5_us_timeofday (context, &sec, &usec); 306 p.patimestamp = sec; 307 usec2 = usec; 308 p.pausec = &usec2; 309 310 ret = encode_PA_ENC_TS_ENC(buf + sizeof(buf) - 1, 311 sizeof(buf), 312 &p, 313 &len); 314 if (ret) 315 return ret; 316 317 krb5_crypto_init(context, key, 0, &crypto); 318 ret = krb5_encrypt_EncryptedData(context, 319 crypto, 320 KRB5_KU_PA_ENC_TIMESTAMP, 321 buf + sizeof(buf) - len, 322 len, 323 0, 324 &encdata); 325 krb5_crypto_destroy(context, crypto); 326 if (ret) 327 return ret; 328 329 ret = encode_EncryptedData(buf + sizeof(buf) - 1, 330 sizeof(buf), 331 &encdata, 332 &len); 333 free_EncryptedData(&encdata); 334 if (ret) 335 return ret; 336 pa->padata_type = pa_enc_timestamp; 337 pa->padata_value.length = 0; 338 krb5_data_copy(&pa->padata_value, 339 buf + sizeof(buf) - len, 340 len); 341 return 0; 342 } 343 344 static krb5_error_code 345 add_padata(krb5_context context, 346 METHOD_DATA *md, 347 krb5_principal client, 348 krb5_key_proc key_proc, 349 krb5_const_pointer keyseed, 350 int *enctypes, 351 unsigned netypes, 352 krb5_salt *salt) 353 { 354 krb5_error_code ret; 355 PA_DATA *pa2; 356 krb5_salt salt2; 357 int *ep; 358 int i; 359 360 if(salt == NULL) { 361 /* default to standard salt */ 362 ret = krb5_get_pw_salt (context, client, &salt2); 363 salt = &salt2; 364 } 365 if (!enctypes) { 366 enctypes = (int *)context->etypes; /* XXX */ 367 netypes = 0; 368 for (ep = enctypes; *ep != ETYPE_NULL; ep++) 369 netypes++; 370 } 371 pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val)); 372 if (pa2 == NULL) 373 return ENOMEM; 374 md->val = pa2; 375 376 for (i = 0; i < netypes; ++i) { 377 krb5_keyblock *key; 378 379 ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key); 380 if (ret) 381 continue; 382 ret = make_pa_enc_timestamp (context, &md->val[md->len], 383 enctypes[i], key); 384 krb5_free_keyblock (context, key); 385 if (ret) 386 return ret; 387 ++md->len; 388 } 389 if(salt == &salt2) 390 krb5_free_salt(context, salt2); 391 return 0; 392 } 393 394 static krb5_error_code 395 init_as_req (krb5_context context, 396 krb5_kdc_flags opts, 397 krb5_creds *creds, 398 const krb5_addresses *addrs, 399 const krb5_enctype *etypes, 400 const krb5_preauthtype *ptypes, 401 const krb5_preauthdata *preauth, 402 krb5_key_proc key_proc, 403 krb5_const_pointer keyseed, 404 unsigned nonce, 405 AS_REQ *a) 406 { 407 krb5_error_code ret; 408 krb5_salt salt; 409 410 memset(a, 0, sizeof(*a)); 411 412 a->pvno = 5; 413 a->msg_type = krb_as_req; 414 a->req_body.kdc_options = opts.b; 415 a->req_body.cname = malloc(sizeof(*a->req_body.cname)); 416 if (a->req_body.cname == NULL) { 417 ret = ENOMEM; 418 goto fail; 419 } 420 a->req_body.sname = malloc(sizeof(*a->req_body.sname)); 421 if (a->req_body.sname == NULL) { 422 ret = ENOMEM; 423 goto fail; 424 } 425 ret = krb5_principal2principalname (a->req_body.cname, creds->client); 426 if (ret) 427 goto fail; 428 ret = krb5_principal2principalname (a->req_body.sname, creds->server); 429 if (ret) 430 goto fail; 431 ret = copy_Realm(&creds->client->realm, &a->req_body.realm); 432 if (ret) 433 goto fail; 434 435 if(creds->times.starttime) { 436 a->req_body.from = malloc(sizeof(*a->req_body.from)); 437 if (a->req_body.from == NULL) { 438 ret = ENOMEM; 439 goto fail; 440 } 441 *a->req_body.from = creds->times.starttime; 442 } 443 if(creds->times.endtime){ 444 ALLOC(a->req_body.till, 1); 445 *a->req_body.till = creds->times.endtime; 446 } 447 if(creds->times.renew_till){ 448 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime)); 449 if (a->req_body.rtime == NULL) { 450 ret = ENOMEM; 451 goto fail; 452 } 453 *a->req_body.rtime = creds->times.renew_till; 454 } 455 a->req_body.nonce = nonce; 456 ret = krb5_init_etype (context, 457 &a->req_body.etype.len, 458 &a->req_body.etype.val, 459 etypes); 460 if (ret) 461 goto fail; 462 463 /* 464 * This means no addresses 465 */ 466 467 if (addrs && addrs->len == 0) { 468 a->req_body.addresses = NULL; 469 } else { 470 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses)); 471 if (a->req_body.addresses == NULL) { 472 ret = ENOMEM; 473 goto fail; 474 } 475 476 if (addrs) 477 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses); 478 else 479 ret = krb5_get_all_client_addrs (context, a->req_body.addresses); 480 if (ret) 481 return ret; 482 } 483 484 a->req_body.enc_authorization_data = NULL; 485 a->req_body.additional_tickets = NULL; 486 487 if(preauth != NULL) { 488 int i; 489 ALLOC(a->padata, 1); 490 if(a->padata == NULL) { 491 ret = ENOMEM; 492 goto fail; 493 } 494 for(i = 0; i < preauth->len; i++) { 495 if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){ 496 int j; 497 PA_DATA *tmp = realloc(a->padata->val, 498 (a->padata->len + 499 preauth->val[i].info.len) * 500 sizeof(*a->padata->val)); 501 if(tmp == NULL) { 502 ret = ENOMEM; 503 goto fail; 504 } 505 a->padata->val = tmp; 506 for(j = 0; j < preauth->val[i].info.len; j++) { 507 krb5_salt *sp = &salt; 508 if(preauth->val[i].info.val[j].salttype) 509 salt.salttype = *preauth->val[i].info.val[j].salttype; 510 else 511 salt.salttype = KRB5_PW_SALT; 512 if(preauth->val[i].info.val[j].salt) 513 salt.saltvalue = *preauth->val[i].info.val[j].salt; 514 else 515 if(salt.salttype == KRB5_PW_SALT) 516 sp = NULL; 517 else 518 krb5_data_zero(&salt.saltvalue); 519 add_padata(context, a->padata, creds->client, 520 key_proc, keyseed, 521 &preauth->val[i].info.val[j].etype, 1, 522 sp); 523 } 524 } 525 } 526 } else 527 /* not sure this is the way to use `ptypes' */ 528 if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE) 529 a->padata = NULL; 530 else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) { 531 ALLOC(a->padata, 1); 532 if (a->padata == NULL) { 533 ret = ENOMEM; 534 goto fail; 535 } 536 a->padata->len = 0; 537 a->padata->val = NULL; 538 539 /* make a v5 salted pa-data */ 540 add_padata(context, a->padata, creds->client, 541 key_proc, keyseed, a->req_body.etype.val, 542 a->req_body.etype.len, NULL); 543 544 /* make a v4 salted pa-data */ 545 salt.salttype = KRB5_PW_SALT; 546 krb5_data_zero(&salt.saltvalue); 547 add_padata(context, a->padata, creds->client, 548 key_proc, keyseed, a->req_body.etype.val, 549 a->req_body.etype.len, &salt); 550 } else { 551 ret = KRB5_PREAUTH_BAD_TYPE; 552 goto fail; 553 } 554 return 0; 555 fail: 556 free_AS_REQ(a); 557 return ret; 558 } 559 560 static int 561 set_ptypes(krb5_context context, 562 KRB_ERROR *error, 563 krb5_preauthtype **ptypes, 564 krb5_preauthdata **preauth) 565 { 566 static krb5_preauthdata preauth2; 567 static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE }; 568 569 if(error->e_data) { 570 METHOD_DATA md; 571 int i; 572 decode_METHOD_DATA(error->e_data->data, 573 error->e_data->length, 574 &md, 575 NULL); 576 for(i = 0; i < md.len; i++){ 577 switch(md.val[i].padata_type){ 578 case pa_enc_timestamp: 579 *ptypes = ptypes2; 580 break; 581 case pa_etype_info: 582 *preauth = &preauth2; 583 ALLOC_SEQ(*preauth, 1); 584 (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP; 585 krb5_decode_ETYPE_INFO(context, 586 md.val[i].padata_value.data, 587 md.val[i].padata_value.length, 588 &(*preauth)->val[0].info, 589 NULL); 590 break; 591 } 592 } 593 free_METHOD_DATA(&md); 594 } else { 595 *ptypes = ptypes2; 596 } 597 return(1); 598 } 599 600 krb5_error_code 601 krb5_get_in_cred(krb5_context context, 602 krb5_flags options, 603 const krb5_addresses *addrs, 604 const krb5_enctype *etypes, 605 const krb5_preauthtype *ptypes, 606 const krb5_preauthdata *preauth, 607 krb5_key_proc key_proc, 608 krb5_const_pointer keyseed, 609 krb5_decrypt_proc decrypt_proc, 610 krb5_const_pointer decryptarg, 611 krb5_creds *creds, 612 krb5_kdc_rep *ret_as_reply) 613 { 614 krb5_error_code ret; 615 AS_REQ a; 616 krb5_kdc_rep rep; 617 krb5_data req, resp; 618 char buf[BUFSIZ]; 619 krb5_salt salt; 620 krb5_keyblock *key; 621 size_t size; 622 krb5_kdc_flags opts; 623 PA_DATA *pa; 624 krb5_enctype etype; 625 krb5_preauthdata *my_preauth = NULL; 626 unsigned nonce; 627 int done; 628 629 opts.i = options; 630 631 krb5_generate_random_block (&nonce, sizeof(nonce)); 632 nonce &= 0xffffffff; 633 634 do { 635 done = 1; 636 ret = init_as_req (context, 637 opts, 638 creds, 639 addrs, 640 etypes, 641 ptypes, 642 preauth, 643 key_proc, 644 keyseed, 645 nonce, 646 &a); 647 if (my_preauth) { 648 free_ETYPE_INFO(&my_preauth->val[0].info); 649 free (my_preauth->val); 650 } 651 if (ret) 652 return ret; 653 654 ret = encode_AS_REQ ((unsigned char*)buf + sizeof(buf) - 1, 655 sizeof(buf), 656 &a, 657 &req.length); 658 free_AS_REQ(&a); 659 if (ret) 660 return ret; 661 662 req.data = buf + sizeof(buf) - req.length; 663 664 ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp); 665 if (ret) 666 return ret; 667 668 memset (&rep, 0, sizeof(rep)); 669 ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size); 670 if(ret) { 671 /* let's try to parse it as a KRB-ERROR */ 672 KRB_ERROR error; 673 int ret2; 674 675 ret2 = krb5_rd_error(context, &resp, &error); 676 if(ret2 && resp.data && ((char*)resp.data)[0] == 4) 677 ret = KRB5KRB_AP_ERR_V4_REPLY; 678 krb5_data_free(&resp); 679 if (ret2 == 0) { 680 ret = error.error_code; 681 /* if no preauth was set and KDC requires it, give it 682 one more try */ 683 if (!ptypes && !preauth 684 && ret == KRB5KDC_ERR_PREAUTH_REQUIRED 685 #if 0 686 || ret == KRB5KDC_ERR_BADOPTION 687 #endif 688 && set_ptypes(context, &error, &ptypes, &my_preauth)) { 689 done = 0; 690 preauth = my_preauth; 691 free_KRB_ERROR(&error); 692 continue; 693 } 694 if(ret_as_reply) 695 ret_as_reply->error = error; 696 else 697 free_KRB_ERROR (&error); 698 return ret; 699 } 700 return ret; 701 } 702 krb5_data_free(&resp); 703 } while(!done); 704 705 pa = NULL; 706 etype = rep.kdc_rep.enc_part.etype; 707 if(rep.kdc_rep.padata){ 708 int index = 0; 709 pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len, 710 pa_pw_salt, &index); 711 if(pa == NULL) { 712 index = 0; 713 pa = krb5_find_padata(rep.kdc_rep.padata->val, 714 rep.kdc_rep.padata->len, 715 pa_afs3_salt, &index); 716 } 717 } 718 if(pa) { 719 salt.salttype = pa->padata_type; 720 salt.saltvalue = pa->padata_value; 721 722 ret = (*key_proc)(context, etype, salt, keyseed, &key); 723 } else { 724 /* make a v5 salted pa-data */ 725 ret = krb5_get_pw_salt (context, creds->client, &salt); 726 727 if (ret) 728 goto out; 729 ret = (*key_proc)(context, etype, salt, keyseed, &key); 730 krb5_free_salt(context, salt); 731 } 732 if (ret) 733 goto out; 734 735 ret = _krb5_extract_ticket(context, 736 &rep, 737 creds, 738 key, 739 keyseed, 740 KRB5_KU_AS_REP_ENC_PART, 741 NULL, 742 nonce, 743 FALSE, 744 decrypt_proc, 745 decryptarg); 746 memset (key->keyvalue.data, 0, key->keyvalue.length); 747 krb5_free_keyblock_contents (context, key); 748 free (key); 749 750 out: 751 if (ret == 0 && ret_as_reply) 752 *ret_as_reply = rep; 753 else 754 krb5_free_kdc_rep (context, &rep); 755 return ret; 756 } 757 758 krb5_error_code 759 krb5_get_in_tkt(krb5_context context, 760 krb5_flags options, 761 const krb5_addresses *addrs, 762 const krb5_enctype *etypes, 763 const krb5_preauthtype *ptypes, 764 krb5_key_proc key_proc, 765 krb5_const_pointer keyseed, 766 krb5_decrypt_proc decrypt_proc, 767 krb5_const_pointer decryptarg, 768 krb5_creds *creds, 769 krb5_ccache ccache, 770 krb5_kdc_rep *ret_as_reply) 771 { 772 krb5_error_code ret; 773 krb5_kdc_flags opts; 774 opts.i = 0; 775 opts.b = int2KDCOptions(options); 776 777 ret = krb5_get_in_cred (context, 778 opts.i, 779 addrs, 780 etypes, 781 ptypes, 782 NULL, 783 key_proc, 784 keyseed, 785 decrypt_proc, 786 decryptarg, 787 creds, 788 ret_as_reply); 789 if(ret) 790 return ret; 791 ret = krb5_cc_store_cred (context, ccache, creds); 792 krb5_free_creds_contents (context, creds); 793 return ret; 794 } 795