1/* 2 * Copyright (c) 1997 - 2005 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" 35RCSID("$Id: v4_glue.c 22071 2007-11-14 20:04:50Z lha $"); 36 37#include "krb5-v4compat.h" 38 39/* 40 * 41 */ 42 43#define RCHECK(r,func,label) \ 44 do { (r) = func ; if (r) goto label; } while(0); 45 46 47/* include this here, to avoid dependencies on libkrb */ 48 49static const int _tkt_lifetimes[TKTLIFENUMFIXED] = { 50 38400, 41055, 43894, 46929, 50174, 53643, 57352, 61318, 51 65558, 70091, 74937, 80119, 85658, 91581, 97914, 104684, 52 111922, 119661, 127935, 136781, 146239, 156350, 167161, 178720, 53 191077, 204289, 218415, 233517, 249664, 266926, 285383, 305116, 54 326213, 348769, 372885, 398668, 426234, 455705, 487215, 520904, 55 556921, 595430, 636601, 680618, 727680, 777995, 831789, 889303, 56 950794, 1016537, 1086825, 1161973, 1242318, 1328218, 1420057, 1518247, 57 1623226, 1735464, 1855462, 1983758, 2120925, 2267576, 2424367, 2592000 58}; 59 60int KRB5_LIB_FUNCTION 61_krb5_krb_time_to_life(time_t start, time_t end) 62{ 63 int i; 64 time_t life = end - start; 65 66 if (life > MAXTKTLIFETIME || life <= 0) 67 return 0; 68#if 0 69 if (krb_no_long_lifetimes) 70 return (life + 5*60 - 1)/(5*60); 71#endif 72 73 if (end >= NEVERDATE) 74 return TKTLIFENOEXPIRE; 75 if (life < _tkt_lifetimes[0]) 76 return (life + 5*60 - 1)/(5*60); 77 for (i=0; i<TKTLIFENUMFIXED; i++) 78 if (life <= _tkt_lifetimes[i]) 79 return i + TKTLIFEMINFIXED; 80 return 0; 81 82} 83 84time_t KRB5_LIB_FUNCTION 85_krb5_krb_life_to_time(int start, int life_) 86{ 87 unsigned char life = (unsigned char) life_; 88 89#if 0 90 if (krb_no_long_lifetimes) 91 return start + life*5*60; 92#endif 93 94 if (life == TKTLIFENOEXPIRE) 95 return NEVERDATE; 96 if (life < TKTLIFEMINFIXED) 97 return start + life*5*60; 98 if (life > TKTLIFEMAXFIXED) 99 return start + MAXTKTLIFETIME; 100 return start + _tkt_lifetimes[life - TKTLIFEMINFIXED]; 101} 102 103/* 104 * Get the name of the krb4 credentials cache, will use `tkfile' as 105 * the name if that is passed in. `cc' must be free()ed by caller, 106 */ 107 108static krb5_error_code 109get_krb4_cc_name(const char *tkfile, char **cc) 110{ 111 112 *cc = NULL; 113 if(tkfile == NULL) { 114 char *path; 115 if(!issuid()) { 116 path = getenv("KRBTKFILE"); 117 if (path) 118 *cc = strdup(path); 119 } 120 if(*cc == NULL) 121 if (asprintf(cc, "%s%u", TKT_ROOT, (unsigned)getuid()) < 0) 122 return errno; 123 } else { 124 *cc = strdup(tkfile); 125 if (*cc == NULL) 126 return ENOMEM; 127 } 128 return 0; 129} 130 131/* 132 * Write a Kerberos 4 ticket file 133 */ 134 135#define KRB5_TF_LCK_RETRY_COUNT 50 136#define KRB5_TF_LCK_RETRY 1 137 138static krb5_error_code 139write_v4_cc(krb5_context context, const char *tkfile, 140 krb5_storage *sp, int append) 141{ 142 krb5_error_code ret; 143 struct stat sb; 144 krb5_data data; 145 char *path; 146 int fd, i; 147 148 ret = get_krb4_cc_name(tkfile, &path); 149 if (ret) { 150 krb5_set_error_string(context, 151 "krb5_krb_tf_setup: failed getting " 152 "the krb4 credentials cache name"); 153 return ret; 154 } 155 156 fd = open(path, O_WRONLY|O_CREAT, 0600); 157 if (fd < 0) { 158 ret = errno; 159 krb5_set_error_string(context, 160 "krb5_krb_tf_setup: error opening file %s", 161 path); 162 free(path); 163 return ret; 164 } 165 166 if (fstat(fd, &sb) != 0 || !S_ISREG(sb.st_mode)) { 167 krb5_set_error_string(context, 168 "krb5_krb_tf_setup: tktfile %s is not a file", 169 path); 170 free(path); 171 close(fd); 172 return KRB5_FCC_PERM; 173 } 174 175 for (i = 0; i < KRB5_TF_LCK_RETRY_COUNT; i++) { 176 if (flock(fd, LOCK_EX | LOCK_NB) < 0) { 177 sleep(KRB5_TF_LCK_RETRY); 178 } else 179 break; 180 } 181 if (i == KRB5_TF_LCK_RETRY_COUNT) { 182 krb5_set_error_string(context, 183 "krb5_krb_tf_setup: failed to lock %s", 184 path); 185 free(path); 186 close(fd); 187 return KRB5_FCC_PERM; 188 } 189 190 if (!append) { 191 ret = ftruncate(fd, 0); 192 if (ret < 0) { 193 flock(fd, LOCK_UN); 194 krb5_set_error_string(context, 195 "krb5_krb_tf_setup: failed to truncate %s", 196 path); 197 free(path); 198 close(fd); 199 return KRB5_FCC_PERM; 200 } 201 } 202 ret = lseek(fd, 0L, SEEK_END); 203 if (ret < 0) { 204 ret = errno; 205 flock(fd, LOCK_UN); 206 free(path); 207 close(fd); 208 return ret; 209 } 210 211 krb5_storage_to_data(sp, &data); 212 213 ret = write(fd, data.data, data.length); 214 if (ret != data.length) 215 ret = KRB5_CC_IO; 216 217 krb5_free_data_contents(context, &data); 218 219 flock(fd, LOCK_UN); 220 free(path); 221 close(fd); 222 223 return 0; 224} 225 226/* 227 * 228 */ 229 230krb5_error_code KRB5_LIB_FUNCTION 231_krb5_krb_tf_setup(krb5_context context, 232 struct credentials *v4creds, 233 const char *tkfile, 234 int append) 235{ 236 krb5_error_code ret; 237 krb5_storage *sp; 238 239 sp = krb5_storage_emem(); 240 if (sp == NULL) 241 return ENOMEM; 242 243 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST); 244 krb5_storage_set_eof_code(sp, KRB5_CC_IO); 245 246 krb5_clear_error_string(context); 247 248 if (!append) { 249 RCHECK(ret, krb5_store_stringz(sp, v4creds->pname), error); 250 RCHECK(ret, krb5_store_stringz(sp, v4creds->pinst), error); 251 } 252 253 /* cred */ 254 RCHECK(ret, krb5_store_stringz(sp, v4creds->service), error); 255 RCHECK(ret, krb5_store_stringz(sp, v4creds->instance), error); 256 RCHECK(ret, krb5_store_stringz(sp, v4creds->realm), error); 257 ret = krb5_storage_write(sp, v4creds->session, 8); 258 if (ret != 8) { 259 ret = KRB5_CC_IO; 260 goto error; 261 } 262 RCHECK(ret, krb5_store_int32(sp, v4creds->lifetime), error); 263 RCHECK(ret, krb5_store_int32(sp, v4creds->kvno), error); 264 RCHECK(ret, krb5_store_int32(sp, v4creds->ticket_st.length), error); 265 266 ret = krb5_storage_write(sp, v4creds->ticket_st.dat, 267 v4creds->ticket_st.length); 268 if (ret != v4creds->ticket_st.length) { 269 ret = KRB5_CC_IO; 270 goto error; 271 } 272 RCHECK(ret, krb5_store_int32(sp, v4creds->issue_date), error); 273 274 ret = write_v4_cc(context, tkfile, sp, append); 275 276 error: 277 krb5_storage_free(sp); 278 279 return ret; 280} 281 282/* 283 * 284 */ 285 286krb5_error_code KRB5_LIB_FUNCTION 287_krb5_krb_dest_tkt(krb5_context context, const char *tkfile) 288{ 289 krb5_error_code ret; 290 char *path; 291 292 ret = get_krb4_cc_name(tkfile, &path); 293 if (ret) { 294 krb5_set_error_string(context, 295 "krb5_krb_tf_setup: failed getting " 296 "the krb4 credentials cache name"); 297 return ret; 298 } 299 300 if (unlink(path) < 0) { 301 ret = errno; 302 krb5_set_error_string(context, 303 "krb5_krb_dest_tkt failed removing the cache " 304 "with error %s", strerror(ret)); 305 } 306 free(path); 307 308 return ret; 309} 310 311/* 312 * 313 */ 314 315static krb5_error_code 316decrypt_etext(krb5_context context, const krb5_keyblock *key, 317 const krb5_data *cdata, krb5_data *data) 318{ 319 krb5_error_code ret; 320 krb5_crypto crypto; 321 322 ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto); 323 if (ret) 324 return ret; 325 326 ret = krb5_decrypt(context, crypto, 0, cdata->data, cdata->length, data); 327 krb5_crypto_destroy(context, crypto); 328 329 return ret; 330} 331 332 333/* 334 * 335 */ 336 337static const char eightzeros[8] = "\x00\x00\x00\x00\x00\x00\x00\x00"; 338 339static krb5_error_code 340storage_to_etext(krb5_context context, 341 krb5_storage *sp, 342 const krb5_keyblock *key, 343 krb5_data *enc_data) 344{ 345 krb5_error_code ret; 346 krb5_crypto crypto; 347 krb5_ssize_t size; 348 krb5_data data; 349 350 /* multiple of eight bytes */ 351 352 size = krb5_storage_seek(sp, 0, SEEK_END); 353 if (size < 0) 354 return KRB4ET_RD_AP_UNDEC; 355 size = 8 - (size & 7); 356 357 ret = krb5_storage_write(sp, eightzeros, size); 358 if (ret != size) 359 return KRB4ET_RD_AP_UNDEC; 360 361 ret = krb5_storage_to_data(sp, &data); 362 if (ret) 363 return ret; 364 365 ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto); 366 if (ret) { 367 krb5_data_free(&data); 368 return ret; 369 } 370 371 ret = krb5_encrypt(context, crypto, 0, data.data, data.length, enc_data); 372 373 krb5_data_free(&data); 374 krb5_crypto_destroy(context, crypto); 375 376 return ret; 377} 378 379/* 380 * 381 */ 382 383static krb5_error_code 384put_nir(krb5_storage *sp, const char *name, 385 const char *instance, const char *realm) 386{ 387 krb5_error_code ret; 388 389 RCHECK(ret, krb5_store_stringz(sp, name), error); 390 RCHECK(ret, krb5_store_stringz(sp, instance), error); 391 if (realm) { 392 RCHECK(ret, krb5_store_stringz(sp, realm), error); 393 } 394 error: 395 return ret; 396} 397 398/* 399 * 400 */ 401 402krb5_error_code KRB5_LIB_FUNCTION 403_krb5_krb_create_ticket(krb5_context context, 404 unsigned char flags, 405 const char *pname, 406 const char *pinstance, 407 const char *prealm, 408 int32_t paddress, 409 const krb5_keyblock *session, 410 int16_t life, 411 int32_t life_sec, 412 const char *sname, 413 const char *sinstance, 414 const krb5_keyblock *key, 415 krb5_data *enc_data) 416{ 417 krb5_error_code ret; 418 krb5_storage *sp; 419 420 krb5_data_zero(enc_data); 421 422 sp = krb5_storage_emem(); 423 if (sp == NULL) { 424 krb5_set_error_string(context, "malloc: out of memory"); 425 return ENOMEM; 426 } 427 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); 428 429 RCHECK(ret, krb5_store_int8(sp, flags), error); 430 RCHECK(ret, put_nir(sp, pname, pinstance, prealm), error); 431 RCHECK(ret, krb5_store_int32(sp, ntohl(paddress)), error); 432 433 /* session key */ 434 ret = krb5_storage_write(sp, 435 session->keyvalue.data, 436 session->keyvalue.length); 437 if (ret != session->keyvalue.length) { 438 ret = KRB4ET_INTK_PROT; 439 goto error; 440 } 441 442 RCHECK(ret, krb5_store_int8(sp, life), error); 443 RCHECK(ret, krb5_store_int32(sp, life_sec), error); 444 RCHECK(ret, put_nir(sp, sname, sinstance, NULL), error); 445 446 ret = storage_to_etext(context, sp, key, enc_data); 447 448 error: 449 krb5_storage_free(sp); 450 if (ret) 451 krb5_set_error_string(context, "Failed to encode kerberos 4 ticket"); 452 453 return ret; 454} 455 456/* 457 * 458 */ 459 460krb5_error_code KRB5_LIB_FUNCTION 461_krb5_krb_create_ciph(krb5_context context, 462 const krb5_keyblock *session, 463 const char *service, 464 const char *instance, 465 const char *realm, 466 uint32_t life, 467 unsigned char kvno, 468 const krb5_data *ticket, 469 uint32_t kdc_time, 470 const krb5_keyblock *key, 471 krb5_data *enc_data) 472{ 473 krb5_error_code ret; 474 krb5_storage *sp; 475 476 krb5_data_zero(enc_data); 477 478 sp = krb5_storage_emem(); 479 if (sp == NULL) { 480 krb5_set_error_string(context, "malloc: out of memory"); 481 return ENOMEM; 482 } 483 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); 484 485 /* session key */ 486 ret = krb5_storage_write(sp, 487 session->keyvalue.data, 488 session->keyvalue.length); 489 if (ret != session->keyvalue.length) { 490 ret = KRB4ET_INTK_PROT; 491 goto error; 492 } 493 494 RCHECK(ret, put_nir(sp, service, instance, realm), error); 495 RCHECK(ret, krb5_store_int8(sp, life), error); 496 RCHECK(ret, krb5_store_int8(sp, kvno), error); 497 RCHECK(ret, krb5_store_int8(sp, ticket->length), error); 498 ret = krb5_storage_write(sp, ticket->data, ticket->length); 499 if (ret != ticket->length) { 500 ret = KRB4ET_INTK_PROT; 501 goto error; 502 } 503 RCHECK(ret, krb5_store_int32(sp, kdc_time), error); 504 505 ret = storage_to_etext(context, sp, key, enc_data); 506 507 error: 508 krb5_storage_free(sp); 509 if (ret) 510 krb5_set_error_string(context, "Failed to encode kerberos 4 ticket"); 511 512 return ret; 513} 514 515/* 516 * 517 */ 518 519krb5_error_code KRB5_LIB_FUNCTION 520_krb5_krb_create_auth_reply(krb5_context context, 521 const char *pname, 522 const char *pinst, 523 const char *prealm, 524 int32_t time_ws, 525 int n, 526 uint32_t x_date, 527 unsigned char kvno, 528 const krb5_data *cipher, 529 krb5_data *data) 530{ 531 krb5_error_code ret; 532 krb5_storage *sp; 533 534 krb5_data_zero(data); 535 536 sp = krb5_storage_emem(); 537 if (sp == NULL) { 538 krb5_set_error_string(context, "malloc: out of memory"); 539 return ENOMEM; 540 } 541 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); 542 543 RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error); 544 RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_KDC_REPLY), error); 545 RCHECK(ret, put_nir(sp, pname, pinst, prealm), error); 546 RCHECK(ret, krb5_store_int32(sp, time_ws), error); 547 RCHECK(ret, krb5_store_int8(sp, n), error); 548 RCHECK(ret, krb5_store_int32(sp, x_date), error); 549 RCHECK(ret, krb5_store_int8(sp, kvno), error); 550 RCHECK(ret, krb5_store_int16(sp, cipher->length), error); 551 ret = krb5_storage_write(sp, cipher->data, cipher->length); 552 if (ret != cipher->length) { 553 ret = KRB4ET_INTK_PROT; 554 goto error; 555 } 556 557 ret = krb5_storage_to_data(sp, data); 558 559 error: 560 krb5_storage_free(sp); 561 if (ret) 562 krb5_set_error_string(context, "Failed to encode kerberos 4 ticket"); 563 564 return ret; 565} 566 567/* 568 * 569 */ 570 571krb5_error_code KRB5_LIB_FUNCTION 572_krb5_krb_cr_err_reply(krb5_context context, 573 const char *name, 574 const char *inst, 575 const char *realm, 576 uint32_t time_ws, 577 uint32_t e, 578 const char *e_string, 579 krb5_data *data) 580{ 581 krb5_error_code ret; 582 krb5_storage *sp; 583 584 krb5_data_zero(data); 585 586 if (name == NULL) name = ""; 587 if (inst == NULL) inst = ""; 588 if (realm == NULL) realm = ""; 589 if (e_string == NULL) e_string = ""; 590 591 sp = krb5_storage_emem(); 592 if (sp == NULL) { 593 krb5_set_error_string(context, "malloc: out of memory"); 594 return ENOMEM; 595 } 596 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); 597 598 RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error); 599 RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_ERR_REPLY), error); 600 RCHECK(ret, put_nir(sp, name, inst, realm), error); 601 RCHECK(ret, krb5_store_int32(sp, time_ws), error); 602 /* If it is a Kerberos 4 error-code, remove the et BASE */ 603 if (e >= ERROR_TABLE_BASE_krb && e <= ERROR_TABLE_BASE_krb + 255) 604 e -= ERROR_TABLE_BASE_krb; 605 RCHECK(ret, krb5_store_int32(sp, e), error); 606 RCHECK(ret, krb5_store_stringz(sp, e_string), error); 607 608 ret = krb5_storage_to_data(sp, data); 609 610 error: 611 krb5_storage_free(sp); 612 if (ret) 613 krb5_set_error_string(context, "Failed to encode kerberos 4 error"); 614 615 return 0; 616} 617 618static krb5_error_code 619get_v4_stringz(krb5_storage *sp, char **str, size_t max_len) 620{ 621 krb5_error_code ret; 622 623 ret = krb5_ret_stringz(sp, str); 624 if (ret) 625 return ret; 626 if (strlen(*str) > max_len) { 627 free(*str); 628 *str = NULL; 629 return KRB4ET_INTK_PROT; 630 } 631 return 0; 632} 633 634/* 635 * 636 */ 637 638krb5_error_code KRB5_LIB_FUNCTION 639_krb5_krb_decomp_ticket(krb5_context context, 640 const krb5_data *enc_ticket, 641 const krb5_keyblock *key, 642 const char *local_realm, 643 char **sname, 644 char **sinstance, 645 struct _krb5_krb_auth_data *ad) 646{ 647 krb5_error_code ret; 648 krb5_ssize_t size; 649 krb5_storage *sp = NULL; 650 krb5_data ticket; 651 unsigned char des_key[8]; 652 653 memset(ad, 0, sizeof(*ad)); 654 krb5_data_zero(&ticket); 655 656 *sname = NULL; 657 *sinstance = NULL; 658 659 RCHECK(ret, decrypt_etext(context, key, enc_ticket, &ticket), error); 660 661 sp = krb5_storage_from_data(&ticket); 662 if (sp == NULL) { 663 krb5_data_free(&ticket); 664 krb5_set_error_string(context, "alloc: out of memory"); 665 return ENOMEM; 666 } 667 668 krb5_storage_set_eof_code(sp, KRB4ET_INTK_PROT); 669 670 RCHECK(ret, krb5_ret_int8(sp, &ad->k_flags), error); 671 RCHECK(ret, get_v4_stringz(sp, &ad->pname, ANAME_SZ), error); 672 RCHECK(ret, get_v4_stringz(sp, &ad->pinst, INST_SZ), error); 673 RCHECK(ret, get_v4_stringz(sp, &ad->prealm, REALM_SZ), error); 674 RCHECK(ret, krb5_ret_uint32(sp, &ad->address), error); 675 676 size = krb5_storage_read(sp, des_key, sizeof(des_key)); 677 if (size != sizeof(des_key)) { 678 ret = KRB4ET_INTK_PROT; 679 goto error; 680 } 681 682 RCHECK(ret, krb5_ret_uint8(sp, &ad->life), error); 683 684 if (ad->k_flags & 1) 685 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 686 else 687 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); 688 689 RCHECK(ret, krb5_ret_uint32(sp, &ad->time_sec), error); 690 691 RCHECK(ret, get_v4_stringz(sp, sname, ANAME_SZ), error); 692 RCHECK(ret, get_v4_stringz(sp, sinstance, INST_SZ), error); 693 694 ret = krb5_keyblock_init(context, ETYPE_DES_PCBC_NONE, 695 des_key, sizeof(des_key), &ad->session); 696 if (ret) 697 goto error; 698 699 if (strlen(ad->prealm) == 0) { 700 free(ad->prealm); 701 ad->prealm = strdup(local_realm); 702 if (ad->prealm == NULL) { 703 ret = ENOMEM; 704 goto error; 705 } 706 } 707 708 error: 709 memset(des_key, 0, sizeof(des_key)); 710 if (sp) 711 krb5_storage_free(sp); 712 krb5_data_free(&ticket); 713 if (ret) { 714 if (*sname) { 715 free(*sname); 716 *sname = NULL; 717 } 718 if (*sinstance) { 719 free(*sinstance); 720 *sinstance = NULL; 721 } 722 _krb5_krb_free_auth_data(context, ad); 723 krb5_set_error_string(context, "Failed to decode v4 ticket"); 724 } 725 return ret; 726} 727 728/* 729 * 730 */ 731 732krb5_error_code KRB5_LIB_FUNCTION 733_krb5_krb_rd_req(krb5_context context, 734 krb5_data *authent, 735 const char *service, 736 const char *instance, 737 const char *local_realm, 738 int32_t from_addr, 739 const krb5_keyblock *key, 740 struct _krb5_krb_auth_data *ad) 741{ 742 krb5_error_code ret; 743 krb5_storage *sp; 744 krb5_data ticket, eaut, aut; 745 krb5_ssize_t size; 746 int little_endian; 747 int8_t pvno; 748 int8_t type; 749 int8_t s_kvno; 750 uint8_t ticket_length; 751 uint8_t eaut_length; 752 uint8_t time_5ms; 753 char *realm = NULL; 754 char *sname = NULL; 755 char *sinstance = NULL; 756 char *r_realm = NULL; 757 char *r_name = NULL; 758 char *r_instance = NULL; 759 760 uint32_t r_time_sec; /* Coarse time from authenticator */ 761 unsigned long delta_t; /* Time in authenticator - local time */ 762 long tkt_age; /* Age of ticket */ 763 764 struct timeval tv; 765 766 krb5_data_zero(&ticket); 767 krb5_data_zero(&eaut); 768 krb5_data_zero(&aut); 769 770 sp = krb5_storage_from_data(authent); 771 if (sp == NULL) { 772 krb5_set_error_string(context, "alloc: out of memory"); 773 return ENOMEM; 774 } 775 776 krb5_storage_set_eof_code(sp, KRB4ET_INTK_PROT); 777 778 ret = krb5_ret_int8(sp, &pvno); 779 if (ret) { 780 krb5_set_error_string(context, "Failed reading v4 pvno"); 781 goto error; 782 } 783 784 if (pvno != KRB_PROT_VERSION) { 785 ret = KRB4ET_RD_AP_VERSION; 786 krb5_set_error_string(context, "Failed v4 pvno not 4"); 787 goto error; 788 } 789 790 ret = krb5_ret_int8(sp, &type); 791 if (ret) { 792 krb5_set_error_string(context, "Failed readin v4 type"); 793 goto error; 794 } 795 796 little_endian = type & 1; 797 type &= ~1; 798 799 if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL) { 800 ret = KRB4ET_RD_AP_MSG_TYPE; 801 krb5_set_error_string(context, "Not a valid v4 request type"); 802 goto error; 803 } 804 805 RCHECK(ret, krb5_ret_int8(sp, &s_kvno), error); 806 RCHECK(ret, get_v4_stringz(sp, &realm, REALM_SZ), error); 807 RCHECK(ret, krb5_ret_uint8(sp, &ticket_length), error); 808 RCHECK(ret, krb5_ret_uint8(sp, &eaut_length), error); 809 RCHECK(ret, krb5_data_alloc(&ticket, ticket_length), error); 810 811 size = krb5_storage_read(sp, ticket.data, ticket.length); 812 if (size != ticket.length) { 813 ret = KRB4ET_INTK_PROT; 814 krb5_set_error_string(context, "Failed reading v4 ticket"); 815 goto error; 816 } 817 818 /* Decrypt and take apart ticket */ 819 ret = _krb5_krb_decomp_ticket(context, &ticket, key, local_realm, 820 &sname, &sinstance, ad); 821 if (ret) 822 goto error; 823 824 RCHECK(ret, krb5_data_alloc(&eaut, eaut_length), error); 825 826 size = krb5_storage_read(sp, eaut.data, eaut.length); 827 if (size != eaut.length) { 828 ret = KRB4ET_INTK_PROT; 829 krb5_set_error_string(context, "Failed reading v4 authenticator"); 830 goto error; 831 } 832 833 krb5_storage_free(sp); 834 sp = NULL; 835 836 ret = decrypt_etext(context, &ad->session, &eaut, &aut); 837 if (ret) 838 goto error; 839 840 sp = krb5_storage_from_data(&aut); 841 if (sp == NULL) { 842 ret = ENOMEM; 843 krb5_set_error_string(context, "alloc: out of memory"); 844 goto error; 845 } 846 847 if (little_endian) 848 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 849 else 850 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); 851 852 RCHECK(ret, get_v4_stringz(sp, &r_name, ANAME_SZ), error); 853 RCHECK(ret, get_v4_stringz(sp, &r_instance, INST_SZ), error); 854 RCHECK(ret, get_v4_stringz(sp, &r_realm, REALM_SZ), error); 855 856 RCHECK(ret, krb5_ret_uint32(sp, &ad->checksum), error); 857 RCHECK(ret, krb5_ret_uint8(sp, &time_5ms), error); 858 RCHECK(ret, krb5_ret_uint32(sp, &r_time_sec), error); 859 860 if (strcmp(ad->pname, r_name) != 0 || 861 strcmp(ad->pinst, r_instance) != 0 || 862 strcmp(ad->prealm, r_realm) != 0) { 863 krb5_set_error_string(context, "v4 principal mismatch"); 864 ret = KRB4ET_RD_AP_INCON; 865 goto error; 866 } 867 868 if (from_addr && ad->address && from_addr != ad->address) { 869 krb5_set_error_string(context, "v4 bad address in ticket"); 870 ret = KRB4ET_RD_AP_BADD; 871 goto error; 872 } 873 874 gettimeofday(&tv, NULL); 875 delta_t = abs((int)(tv.tv_sec - r_time_sec)); 876 if (delta_t > CLOCK_SKEW) { 877 ret = KRB4ET_RD_AP_TIME; 878 krb5_set_error_string(context, "v4 clock skew"); 879 goto error; 880 } 881 882 /* Now check for expiration of ticket */ 883 884 tkt_age = tv.tv_sec - ad->time_sec; 885 886 if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW)) { 887 ret = KRB4ET_RD_AP_NYV; 888 krb5_set_error_string(context, "v4 clock skew for expiration"); 889 goto error; 890 } 891 892 if (tv.tv_sec > _krb5_krb_life_to_time(ad->time_sec, ad->life)) { 893 ret = KRB4ET_RD_AP_EXP; 894 krb5_set_error_string(context, "v4 ticket expired"); 895 goto error; 896 } 897 898 ret = 0; 899 error: 900 krb5_data_free(&ticket); 901 krb5_data_free(&eaut); 902 krb5_data_free(&aut); 903 if (realm) 904 free(realm); 905 if (sname) 906 free(sname); 907 if (sinstance) 908 free(sinstance); 909 if (r_name) 910 free(r_name); 911 if (r_instance) 912 free(r_instance); 913 if (r_realm) 914 free(r_realm); 915 if (sp) 916 krb5_storage_free(sp); 917 918 if (ret) 919 krb5_clear_error_string(context); 920 921 return ret; 922} 923 924/* 925 * 926 */ 927 928void KRB5_LIB_FUNCTION 929_krb5_krb_free_auth_data(krb5_context context, struct _krb5_krb_auth_data *ad) 930{ 931 if (ad->pname) 932 free(ad->pname); 933 if (ad->pinst) 934 free(ad->pinst); 935 if (ad->prealm) 936 free(ad->prealm); 937 krb5_free_keyblock_contents(context, &ad->session); 938 memset(ad, 0, sizeof(*ad)); 939} 940