1 /* 2 * Copyright (c) 1997-2002 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 #include "store-int.h" 36 37 RCSID("$Id: store.c,v 1.38.4.1 2004/03/09 19:32:14 lha Exp $"); 38 39 #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V)) 40 #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE) 41 #define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE) 42 #define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \ 43 krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER)) 44 45 void 46 krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags) 47 { 48 sp->flags |= flags; 49 } 50 51 void 52 krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags) 53 { 54 sp->flags &= ~flags; 55 } 56 57 krb5_boolean 58 krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags) 59 { 60 return (sp->flags & flags) == flags; 61 } 62 63 void 64 krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder) 65 { 66 sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK; 67 sp->flags |= byteorder; 68 } 69 70 krb5_flags 71 krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder) 72 { 73 return sp->flags & KRB5_STORAGE_BYTEORDER_MASK; 74 } 75 76 off_t 77 krb5_storage_seek(krb5_storage *sp, off_t offset, int whence) 78 { 79 return (*sp->seek)(sp, offset, whence); 80 } 81 82 krb5_ssize_t 83 krb5_storage_read(krb5_storage *sp, void *buf, size_t len) 84 { 85 return sp->fetch(sp, buf, len); 86 } 87 88 krb5_ssize_t 89 krb5_storage_write(krb5_storage *sp, const void *buf, size_t len) 90 { 91 return sp->store(sp, buf, len); 92 } 93 94 void 95 krb5_storage_set_eof_code(krb5_storage *sp, int code) 96 { 97 sp->eof_code = code; 98 } 99 100 krb5_ssize_t 101 _krb5_put_int(void *buffer, unsigned long value, size_t size) 102 { 103 unsigned char *p = buffer; 104 int i; 105 for (i = size - 1; i >= 0; i--) { 106 p[i] = value & 0xff; 107 value >>= 8; 108 } 109 return size; 110 } 111 112 krb5_ssize_t 113 _krb5_get_int(void *buffer, unsigned long *value, size_t size) 114 { 115 unsigned char *p = buffer; 116 unsigned long v = 0; 117 int i; 118 for (i = 0; i < size; i++) 119 v = (v << 8) + p[i]; 120 *value = v; 121 return size; 122 } 123 124 krb5_error_code 125 krb5_storage_free(krb5_storage *sp) 126 { 127 if(sp->free) 128 (*sp->free)(sp); 129 free(sp->data); 130 free(sp); 131 return 0; 132 } 133 134 krb5_error_code 135 krb5_storage_to_data(krb5_storage *sp, krb5_data *data) 136 { 137 off_t pos; 138 size_t size; 139 krb5_error_code ret; 140 141 pos = sp->seek(sp, 0, SEEK_CUR); 142 size = (size_t)sp->seek(sp, 0, SEEK_END); 143 ret = krb5_data_alloc (data, size); 144 if (ret) { 145 sp->seek(sp, pos, SEEK_SET); 146 return ret; 147 } 148 if (size) { 149 sp->seek(sp, 0, SEEK_SET); 150 sp->fetch(sp, data->data, data->length); 151 sp->seek(sp, pos, SEEK_SET); 152 } 153 return 0; 154 } 155 156 static krb5_error_code 157 krb5_store_int(krb5_storage *sp, 158 int32_t value, 159 size_t len) 160 { 161 int ret; 162 unsigned char v[16]; 163 164 if(len > sizeof(v)) 165 return EINVAL; 166 _krb5_put_int(v, value, len); 167 ret = sp->store(sp, v, len); 168 if (ret != len) 169 return (ret<0)?errno:sp->eof_code; 170 return 0; 171 } 172 173 krb5_error_code 174 krb5_store_int32(krb5_storage *sp, 175 int32_t value) 176 { 177 if(BYTEORDER_IS_HOST(sp)) 178 value = htonl(value); 179 else if(BYTEORDER_IS_LE(sp)) 180 value = bswap32(value); 181 return krb5_store_int(sp, value, 4); 182 } 183 184 static krb5_error_code 185 krb5_ret_int(krb5_storage *sp, 186 int32_t *value, 187 size_t len) 188 { 189 int ret; 190 unsigned char v[4]; 191 unsigned long w; 192 ret = sp->fetch(sp, v, len); 193 if(ret != len) 194 return (ret<0)?errno:sp->eof_code; 195 _krb5_get_int(v, &w, len); 196 *value = w; 197 return 0; 198 } 199 200 krb5_error_code 201 krb5_ret_int32(krb5_storage *sp, 202 int32_t *value) 203 { 204 krb5_error_code ret = krb5_ret_int(sp, value, 4); 205 if(ret) 206 return ret; 207 if(BYTEORDER_IS_HOST(sp)) 208 *value = htonl(*value); 209 else if(BYTEORDER_IS_LE(sp)) 210 *value = bswap32(*value); 211 return 0; 212 } 213 214 krb5_error_code 215 krb5_store_int16(krb5_storage *sp, 216 int16_t value) 217 { 218 if(BYTEORDER_IS_HOST(sp)) 219 value = htons(value); 220 else if(BYTEORDER_IS_LE(sp)) 221 value = bswap16(value); 222 return krb5_store_int(sp, value, 2); 223 } 224 225 krb5_error_code 226 krb5_ret_int16(krb5_storage *sp, 227 int16_t *value) 228 { 229 int32_t v; 230 int ret; 231 ret = krb5_ret_int(sp, &v, 2); 232 if(ret) 233 return ret; 234 *value = v; 235 if(BYTEORDER_IS_HOST(sp)) 236 *value = htons(*value); 237 else if(BYTEORDER_IS_LE(sp)) 238 *value = bswap16(*value); 239 return 0; 240 } 241 242 krb5_error_code 243 krb5_store_int8(krb5_storage *sp, 244 int8_t value) 245 { 246 int ret; 247 248 ret = sp->store(sp, &value, sizeof(value)); 249 if (ret != sizeof(value)) 250 return (ret<0)?errno:sp->eof_code; 251 return 0; 252 } 253 254 krb5_error_code 255 krb5_ret_int8(krb5_storage *sp, 256 int8_t *value) 257 { 258 int ret; 259 260 ret = sp->fetch(sp, value, sizeof(*value)); 261 if (ret != sizeof(*value)) 262 return (ret<0)?errno:sp->eof_code; 263 return 0; 264 } 265 266 krb5_error_code 267 krb5_store_data(krb5_storage *sp, 268 krb5_data data) 269 { 270 int ret; 271 ret = krb5_store_int32(sp, data.length); 272 if(ret < 0) 273 return ret; 274 ret = sp->store(sp, data.data, data.length); 275 if(ret != data.length){ 276 if(ret < 0) 277 return errno; 278 return sp->eof_code; 279 } 280 return 0; 281 } 282 283 krb5_error_code 284 krb5_ret_data(krb5_storage *sp, 285 krb5_data *data) 286 { 287 int ret; 288 int32_t size; 289 290 ret = krb5_ret_int32(sp, &size); 291 if(ret) 292 return ret; 293 ret = krb5_data_alloc (data, size); 294 if (ret) 295 return ret; 296 if (size) { 297 ret = sp->fetch(sp, data->data, size); 298 if(ret != size) 299 return (ret < 0)? errno : sp->eof_code; 300 } 301 return 0; 302 } 303 304 krb5_error_code 305 krb5_store_string(krb5_storage *sp, const char *s) 306 { 307 krb5_data data; 308 data.length = strlen(s); 309 data.data = (void*)s; 310 return krb5_store_data(sp, data); 311 } 312 313 krb5_error_code 314 krb5_ret_string(krb5_storage *sp, 315 char **string) 316 { 317 int ret; 318 krb5_data data; 319 ret = krb5_ret_data(sp, &data); 320 if(ret) 321 return ret; 322 *string = realloc(data.data, data.length + 1); 323 if(*string == NULL){ 324 free(data.data); 325 return ENOMEM; 326 } 327 (*string)[data.length] = 0; 328 return 0; 329 } 330 331 krb5_error_code 332 krb5_store_stringz(krb5_storage *sp, const char *s) 333 { 334 size_t len = strlen(s) + 1; 335 ssize_t ret; 336 337 ret = sp->store(sp, s, len); 338 if(ret != len) { 339 if(ret < 0) 340 return ret; 341 else 342 return sp->eof_code; 343 } 344 return 0; 345 } 346 347 krb5_error_code 348 krb5_ret_stringz(krb5_storage *sp, 349 char **string) 350 { 351 char c; 352 char *s = NULL; 353 size_t len = 0; 354 ssize_t ret; 355 356 while((ret = sp->fetch(sp, &c, 1)) == 1){ 357 char *tmp; 358 359 len++; 360 tmp = realloc (s, len); 361 if (tmp == NULL) { 362 free (s); 363 return ENOMEM; 364 } 365 s = tmp; 366 s[len - 1] = c; 367 if(c == 0) 368 break; 369 } 370 if(ret != 1){ 371 free(s); 372 if(ret == 0) 373 return sp->eof_code; 374 return ret; 375 } 376 *string = s; 377 return 0; 378 } 379 380 381 krb5_error_code 382 krb5_store_principal(krb5_storage *sp, 383 krb5_principal p) 384 { 385 int i; 386 int ret; 387 388 if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) { 389 ret = krb5_store_int32(sp, p->name.name_type); 390 if(ret) return ret; 391 } 392 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 393 ret = krb5_store_int32(sp, p->name.name_string.len + 1); 394 else 395 ret = krb5_store_int32(sp, p->name.name_string.len); 396 397 if(ret) return ret; 398 ret = krb5_store_string(sp, p->realm); 399 if(ret) return ret; 400 for(i = 0; i < p->name.name_string.len; i++){ 401 ret = krb5_store_string(sp, p->name.name_string.val[i]); 402 if(ret) return ret; 403 } 404 return 0; 405 } 406 407 krb5_error_code 408 krb5_ret_principal(krb5_storage *sp, 409 krb5_principal *princ) 410 { 411 int i; 412 int ret; 413 krb5_principal p; 414 int32_t type; 415 int32_t ncomp; 416 417 p = calloc(1, sizeof(*p)); 418 if(p == NULL) 419 return ENOMEM; 420 421 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) 422 type = KRB5_NT_UNKNOWN; 423 else if((ret = krb5_ret_int32(sp, &type))){ 424 free(p); 425 return ret; 426 } 427 if((ret = krb5_ret_int32(sp, &ncomp))){ 428 free(p); 429 return ret; 430 } 431 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 432 ncomp--; 433 p->name.name_type = type; 434 p->name.name_string.len = ncomp; 435 ret = krb5_ret_string(sp, &p->realm); 436 if(ret) return ret; 437 p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val)); 438 if(p->name.name_string.val == NULL){ 439 free(p->realm); 440 return ENOMEM; 441 } 442 for(i = 0; i < ncomp; i++){ 443 ret = krb5_ret_string(sp, &p->name.name_string.val[i]); 444 if(ret) return ret; /* XXX */ 445 } 446 *princ = p; 447 return 0; 448 } 449 450 krb5_error_code 451 krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p) 452 { 453 int ret; 454 ret = krb5_store_int16(sp, p.keytype); 455 if(ret) return ret; 456 457 if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){ 458 /* this should really be enctype, but it is the same as 459 keytype nowadays */ 460 ret = krb5_store_int16(sp, p.keytype); 461 if(ret) return ret; 462 } 463 464 ret = krb5_store_data(sp, p.keyvalue); 465 return ret; 466 } 467 468 krb5_error_code 469 krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p) 470 { 471 int ret; 472 int16_t tmp; 473 474 ret = krb5_ret_int16(sp, &tmp); 475 if(ret) return ret; 476 p->keytype = tmp; 477 478 if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){ 479 ret = krb5_ret_int16(sp, &tmp); 480 if(ret) return ret; 481 } 482 483 ret = krb5_ret_data(sp, &p->keyvalue); 484 return ret; 485 } 486 487 krb5_error_code 488 krb5_store_times(krb5_storage *sp, krb5_times times) 489 { 490 int ret; 491 ret = krb5_store_int32(sp, times.authtime); 492 if(ret) return ret; 493 ret = krb5_store_int32(sp, times.starttime); 494 if(ret) return ret; 495 ret = krb5_store_int32(sp, times.endtime); 496 if(ret) return ret; 497 ret = krb5_store_int32(sp, times.renew_till); 498 return ret; 499 } 500 501 krb5_error_code 502 krb5_ret_times(krb5_storage *sp, krb5_times *times) 503 { 504 int ret; 505 int32_t tmp; 506 ret = krb5_ret_int32(sp, &tmp); 507 times->authtime = tmp; 508 if(ret) return ret; 509 ret = krb5_ret_int32(sp, &tmp); 510 times->starttime = tmp; 511 if(ret) return ret; 512 ret = krb5_ret_int32(sp, &tmp); 513 times->endtime = tmp; 514 if(ret) return ret; 515 ret = krb5_ret_int32(sp, &tmp); 516 times->renew_till = tmp; 517 return ret; 518 } 519 520 krb5_error_code 521 krb5_store_address(krb5_storage *sp, krb5_address p) 522 { 523 int ret; 524 ret = krb5_store_int16(sp, p.addr_type); 525 if(ret) return ret; 526 ret = krb5_store_data(sp, p.address); 527 return ret; 528 } 529 530 krb5_error_code 531 krb5_ret_address(krb5_storage *sp, krb5_address *adr) 532 { 533 int16_t t; 534 int ret; 535 ret = krb5_ret_int16(sp, &t); 536 if(ret) return ret; 537 adr->addr_type = t; 538 ret = krb5_ret_data(sp, &adr->address); 539 return ret; 540 } 541 542 krb5_error_code 543 krb5_store_addrs(krb5_storage *sp, krb5_addresses p) 544 { 545 int i; 546 int ret; 547 ret = krb5_store_int32(sp, p.len); 548 if(ret) return ret; 549 for(i = 0; i<p.len; i++){ 550 ret = krb5_store_address(sp, p.val[i]); 551 if(ret) break; 552 } 553 return ret; 554 } 555 556 krb5_error_code 557 krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr) 558 { 559 int i; 560 int ret; 561 int32_t tmp; 562 563 ret = krb5_ret_int32(sp, &tmp); 564 if(ret) return ret; 565 adr->len = tmp; 566 ALLOC(adr->val, adr->len); 567 for(i = 0; i < adr->len; i++){ 568 ret = krb5_ret_address(sp, &adr->val[i]); 569 if(ret) break; 570 } 571 return ret; 572 } 573 574 krb5_error_code 575 krb5_store_authdata(krb5_storage *sp, krb5_authdata auth) 576 { 577 krb5_error_code ret; 578 int i; 579 ret = krb5_store_int32(sp, auth.len); 580 if(ret) return ret; 581 for(i = 0; i < auth.len; i++){ 582 ret = krb5_store_int16(sp, auth.val[i].ad_type); 583 if(ret) break; 584 ret = krb5_store_data(sp, auth.val[i].ad_data); 585 if(ret) break; 586 } 587 return 0; 588 } 589 590 krb5_error_code 591 krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth) 592 { 593 krb5_error_code ret; 594 int32_t tmp; 595 int16_t tmp2; 596 int i; 597 ret = krb5_ret_int32(sp, &tmp); 598 if(ret) return ret; 599 ALLOC_SEQ(auth, tmp); 600 for(i = 0; i < tmp; i++){ 601 ret = krb5_ret_int16(sp, &tmp2); 602 if(ret) break; 603 auth->val[i].ad_type = tmp2; 604 ret = krb5_ret_data(sp, &auth->val[i].ad_data); 605 if(ret) break; 606 } 607 return ret; 608 } 609 610 static int32_t 611 bitswap32(int32_t b) 612 { 613 int32_t r = 0; 614 int i; 615 for (i = 0; i < 32; i++) { 616 r = r << 1 | (b & 1); 617 b = b >> 1; 618 } 619 return r; 620 } 621 622 623 /* 624 * 625 */ 626 627 krb5_error_code 628 _krb5_store_creds_internal(krb5_storage *sp, krb5_creds *creds, int v0_6) 629 { 630 int ret; 631 632 ret = krb5_store_principal(sp, creds->client); 633 if(ret) 634 return ret; 635 ret = krb5_store_principal(sp, creds->server); 636 if(ret) 637 return ret; 638 ret = krb5_store_keyblock(sp, creds->session); 639 if(ret) 640 return ret; 641 ret = krb5_store_times(sp, creds->times); 642 if(ret) 643 return ret; 644 ret = krb5_store_int8(sp, 0); /* this is probably the 645 enc-tkt-in-skey bit from KDCOptions */ 646 if(ret) 647 return ret; 648 if (v0_6) { 649 ret = krb5_store_int32(sp, creds->flags.i); 650 if(ret) 651 return ret; 652 } else { 653 ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b))); 654 if(ret) 655 return ret; 656 } 657 ret = krb5_store_addrs(sp, creds->addresses); 658 if(ret) 659 return ret; 660 ret = krb5_store_authdata(sp, creds->authdata); 661 if(ret) 662 return ret; 663 ret = krb5_store_data(sp, creds->ticket); 664 if(ret) 665 return ret; 666 ret = krb5_store_data(sp, creds->second_ticket); 667 return ret; 668 } 669 670 /* 671 * store `creds' on `sp' returning error or zero 672 */ 673 674 krb5_error_code 675 krb5_store_creds(krb5_storage *sp, krb5_creds *creds) 676 { 677 return _krb5_store_creds_internal(sp, creds, 1); 678 } 679 680 krb5_error_code 681 _krb5_store_creds_heimdal_0_7(krb5_storage *sp, krb5_creds *creds) 682 { 683 return _krb5_store_creds_internal(sp, creds, 0); 684 } 685 686 krb5_error_code 687 _krb5_store_creds_heimdal_pre_0_7(krb5_storage *sp, krb5_creds *creds) 688 { 689 return _krb5_store_creds_internal(sp, creds, 1); 690 } 691 692 krb5_error_code 693 krb5_ret_creds(krb5_storage *sp, krb5_creds *creds) 694 { 695 krb5_error_code ret; 696 int8_t dummy8; 697 int32_t dummy32; 698 699 memset(creds, 0, sizeof(*creds)); 700 ret = krb5_ret_principal (sp, &creds->client); 701 if(ret) goto cleanup; 702 ret = krb5_ret_principal (sp, &creds->server); 703 if(ret) goto cleanup; 704 ret = krb5_ret_keyblock (sp, &creds->session); 705 if(ret) goto cleanup; 706 ret = krb5_ret_times (sp, &creds->times); 707 if(ret) goto cleanup; 708 ret = krb5_ret_int8 (sp, &dummy8); 709 if(ret) goto cleanup; 710 ret = krb5_ret_int32 (sp, &dummy32); 711 if(ret) goto cleanup; 712 /* 713 * Runtime detect the what is the higher bits of the bitfield. If 714 * any of the higher bits are set in the input data, its either a 715 * new ticket flag (and this code need to be removed), or its a 716 * MIT cache (or new Heimdal cache), lets change it to our current 717 * format. 718 */ 719 { 720 u_int32_t mask = 0xffff0000; 721 creds->flags.i = 0; 722 creds->flags.b.anonymous = 1; 723 if (creds->flags.i & mask) 724 mask = ~mask; 725 if (dummy32 & mask) 726 dummy32 = bitswap32(dummy32); 727 } 728 creds->flags.i = dummy32; 729 ret = krb5_ret_addrs (sp, &creds->addresses); 730 if(ret) goto cleanup; 731 ret = krb5_ret_authdata (sp, &creds->authdata); 732 if(ret) goto cleanup; 733 ret = krb5_ret_data (sp, &creds->ticket); 734 if(ret) goto cleanup; 735 ret = krb5_ret_data (sp, &creds->second_ticket); 736 cleanup: 737 if(ret) { 738 #if 0 739 krb5_free_creds_contents(context, creds); /* XXX */ 740 #endif 741 } 742 return ret; 743 } 744