store.c revision 127808
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 37RCSID("$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 45void 46krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags) 47{ 48 sp->flags |= flags; 49} 50 51void 52krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags) 53{ 54 sp->flags &= ~flags; 55} 56 57krb5_boolean 58krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags) 59{ 60 return (sp->flags & flags) == flags; 61} 62 63void 64krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder) 65{ 66 sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK; 67 sp->flags |= byteorder; 68} 69 70krb5_flags 71krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder) 72{ 73 return sp->flags & KRB5_STORAGE_BYTEORDER_MASK; 74} 75 76off_t 77krb5_storage_seek(krb5_storage *sp, off_t offset, int whence) 78{ 79 return (*sp->seek)(sp, offset, whence); 80} 81 82krb5_ssize_t 83krb5_storage_read(krb5_storage *sp, void *buf, size_t len) 84{ 85 return sp->fetch(sp, buf, len); 86} 87 88krb5_ssize_t 89krb5_storage_write(krb5_storage *sp, const void *buf, size_t len) 90{ 91 return sp->store(sp, buf, len); 92} 93 94void 95krb5_storage_set_eof_code(krb5_storage *sp, int code) 96{ 97 sp->eof_code = code; 98} 99 100krb5_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 112krb5_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 124krb5_error_code 125krb5_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 134krb5_error_code 135krb5_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 156static krb5_error_code 157krb5_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 173krb5_error_code 174krb5_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 184static krb5_error_code 185krb5_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 200krb5_error_code 201krb5_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 214krb5_error_code 215krb5_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 225krb5_error_code 226krb5_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 242krb5_error_code 243krb5_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 254krb5_error_code 255krb5_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 266krb5_error_code 267krb5_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 283krb5_error_code 284krb5_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 304krb5_error_code 305krb5_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 313krb5_error_code 314krb5_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 331krb5_error_code 332krb5_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 347krb5_error_code 348krb5_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 381krb5_error_code 382krb5_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 407krb5_error_code 408krb5_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 450krb5_error_code 451krb5_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 468krb5_error_code 469krb5_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 487krb5_error_code 488krb5_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 501krb5_error_code 502krb5_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 520krb5_error_code 521krb5_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 530krb5_error_code 531krb5_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 542krb5_error_code 543krb5_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 556krb5_error_code 557krb5_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 574krb5_error_code 575krb5_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 590krb5_error_code 591krb5_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 610static int32_t 611bitswap32(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 627krb5_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 674krb5_error_code 675krb5_store_creds(krb5_storage *sp, krb5_creds *creds) 676{ 677 return _krb5_store_creds_internal(sp, creds, 1); 678} 679 680krb5_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 686krb5_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 692krb5_error_code 693krb5_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); 736cleanup: 737 if(ret) { 738#if 0 739 krb5_free_creds_contents(context, creds); /* XXX */ 740#endif 741 } 742 return ret; 743} 744