1 /* 2 * Copyright (c) 1997-2001 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: store.c,v 1.35 2001/05/11 13:01:43 joda Exp $"); 37 38 #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V)) 39 #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE) 40 #define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE) 41 #define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \ 42 krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER)) 43 44 void 45 krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags) 46 { 47 sp->flags |= flags; 48 } 49 50 void 51 krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags) 52 { 53 sp->flags &= ~flags; 54 } 55 56 krb5_boolean 57 krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags) 58 { 59 return (sp->flags & flags) == flags; 60 } 61 62 void 63 krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder) 64 { 65 sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK; 66 sp->flags |= byteorder; 67 } 68 69 krb5_flags 70 krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder) 71 { 72 return sp->flags & KRB5_STORAGE_BYTEORDER_MASK; 73 } 74 75 76 ssize_t 77 _krb5_put_int(void *buffer, unsigned long value, size_t size) 78 { 79 unsigned char *p = buffer; 80 int i; 81 for (i = size - 1; i >= 0; i--) { 82 p[i] = value & 0xff; 83 value >>= 8; 84 } 85 return size; 86 } 87 88 ssize_t 89 _krb5_get_int(void *buffer, unsigned long *value, size_t size) 90 { 91 unsigned char *p = buffer; 92 unsigned long v = 0; 93 int i; 94 for (i = 0; i < size; i++) 95 v = (v << 8) + p[i]; 96 *value = v; 97 return size; 98 } 99 100 krb5_error_code 101 krb5_storage_free(krb5_storage *sp) 102 { 103 if(sp->free) 104 (*sp->free)(sp); 105 free(sp->data); 106 free(sp); 107 return 0; 108 } 109 110 krb5_error_code 111 krb5_storage_to_data(krb5_storage *sp, krb5_data *data) 112 { 113 off_t pos; 114 size_t size; 115 krb5_error_code ret; 116 117 pos = sp->seek(sp, 0, SEEK_CUR); 118 size = (size_t)sp->seek(sp, 0, SEEK_END); 119 ret = krb5_data_alloc (data, size); 120 if (ret) { 121 sp->seek(sp, pos, SEEK_SET); 122 return ret; 123 } 124 if (size) { 125 sp->seek(sp, 0, SEEK_SET); 126 sp->fetch(sp, data->data, data->length); 127 sp->seek(sp, pos, SEEK_SET); 128 } 129 return 0; 130 } 131 132 static krb5_error_code 133 krb5_store_int(krb5_storage *sp, 134 int32_t value, 135 size_t len) 136 { 137 int ret; 138 unsigned char v[16]; 139 140 if(len > sizeof(v)) 141 return EINVAL; 142 _krb5_put_int(v, value, len); 143 ret = sp->store(sp, v, len); 144 if (ret != len) 145 return (ret<0)?errno:KRB5_CC_END; 146 return 0; 147 } 148 149 krb5_error_code 150 krb5_store_int32(krb5_storage *sp, 151 int32_t value) 152 { 153 if(BYTEORDER_IS_HOST(sp)) 154 value = htonl(value); 155 else if(BYTEORDER_IS_LE(sp)) 156 value = bswap32(value); 157 return krb5_store_int(sp, value, 4); 158 } 159 160 static krb5_error_code 161 krb5_ret_int(krb5_storage *sp, 162 int32_t *value, 163 size_t len) 164 { 165 int ret; 166 unsigned char v[4]; 167 unsigned long w; 168 ret = sp->fetch(sp, v, len); 169 if(ret != len) 170 return (ret<0)?errno:KRB5_CC_END; 171 _krb5_get_int(v, &w, len); 172 *value = w; 173 return 0; 174 } 175 176 krb5_error_code 177 krb5_ret_int32(krb5_storage *sp, 178 int32_t *value) 179 { 180 krb5_error_code ret = krb5_ret_int(sp, value, 4); 181 if(ret) 182 return ret; 183 if(BYTEORDER_IS_HOST(sp)) 184 *value = htonl(*value); 185 else if(BYTEORDER_IS_LE(sp)) 186 *value = bswap32(*value); 187 return 0; 188 } 189 190 krb5_error_code 191 krb5_store_int16(krb5_storage *sp, 192 int16_t value) 193 { 194 if(BYTEORDER_IS_HOST(sp)) 195 value = htons(value); 196 else if(BYTEORDER_IS_LE(sp)) 197 value = bswap16(value); 198 return krb5_store_int(sp, value, 2); 199 } 200 201 krb5_error_code 202 krb5_ret_int16(krb5_storage *sp, 203 int16_t *value) 204 { 205 int32_t v; 206 int ret; 207 ret = krb5_ret_int(sp, &v, 2); 208 if(ret) 209 return ret; 210 *value = v; 211 if(BYTEORDER_IS_HOST(sp)) 212 *value = htons(*value); 213 else if(BYTEORDER_IS_LE(sp)) 214 *value = bswap16(*value); 215 return 0; 216 } 217 218 krb5_error_code 219 krb5_store_int8(krb5_storage *sp, 220 int8_t value) 221 { 222 int ret; 223 224 ret = sp->store(sp, &value, sizeof(value)); 225 if (ret != sizeof(value)) 226 return (ret<0)?errno:KRB5_CC_END; 227 return 0; 228 } 229 230 krb5_error_code 231 krb5_ret_int8(krb5_storage *sp, 232 int8_t *value) 233 { 234 int ret; 235 236 ret = sp->fetch(sp, value, sizeof(*value)); 237 if (ret != sizeof(*value)) 238 return (ret<0)?errno:KRB5_CC_END; 239 return 0; 240 } 241 242 krb5_error_code 243 krb5_store_data(krb5_storage *sp, 244 krb5_data data) 245 { 246 int ret; 247 ret = krb5_store_int32(sp, data.length); 248 if(ret < 0) 249 return ret; 250 ret = sp->store(sp, data.data, data.length); 251 if(ret != data.length){ 252 if(ret < 0) 253 return errno; 254 return KRB5_CC_END; 255 } 256 return 0; 257 } 258 259 krb5_error_code 260 krb5_ret_data(krb5_storage *sp, 261 krb5_data *data) 262 { 263 int ret; 264 int32_t size; 265 266 ret = krb5_ret_int32(sp, &size); 267 if(ret) 268 return ret; 269 ret = krb5_data_alloc (data, size); 270 if (ret) 271 return ret; 272 if (size) { 273 ret = sp->fetch(sp, data->data, size); 274 if(ret != size) 275 return (ret < 0)? errno : KRB5_CC_END; 276 } 277 return 0; 278 } 279 280 krb5_error_code 281 krb5_store_string(krb5_storage *sp, const char *s) 282 { 283 krb5_data data; 284 data.length = strlen(s); 285 data.data = (void*)s; 286 return krb5_store_data(sp, data); 287 } 288 289 krb5_error_code 290 krb5_ret_string(krb5_storage *sp, 291 char **string) 292 { 293 int ret; 294 krb5_data data; 295 ret = krb5_ret_data(sp, &data); 296 if(ret) 297 return ret; 298 *string = realloc(data.data, data.length + 1); 299 if(*string == NULL){ 300 free(data.data); 301 return ENOMEM; 302 } 303 (*string)[data.length] = 0; 304 return 0; 305 } 306 307 krb5_error_code 308 krb5_store_stringz(krb5_storage *sp, const char *s) 309 { 310 size_t len = strlen(s) + 1; 311 ssize_t ret; 312 313 ret = sp->store(sp, s, len); 314 if(ret != len) { 315 if(ret < 0) 316 return ret; 317 else 318 return KRB5_CC_END; 319 } 320 return 0; 321 } 322 323 krb5_error_code 324 krb5_ret_stringz(krb5_storage *sp, 325 char **string) 326 { 327 char c; 328 char *s = NULL; 329 size_t len = 0; 330 ssize_t ret; 331 332 while((ret = sp->fetch(sp, &c, 1)) == 1){ 333 char *tmp; 334 335 len++; 336 tmp = realloc (s, len); 337 if (tmp == NULL) { 338 free (s); 339 return ENOMEM; 340 } 341 s = tmp; 342 s[len - 1] = c; 343 if(c == 0) 344 break; 345 } 346 if(ret != 1){ 347 free(s); 348 if(ret == 0) 349 return KRB5_CC_END; 350 return ret; 351 } 352 *string = s; 353 return 0; 354 } 355 356 357 krb5_error_code 358 krb5_store_principal(krb5_storage *sp, 359 krb5_principal p) 360 { 361 int i; 362 int ret; 363 364 if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) { 365 ret = krb5_store_int32(sp, p->name.name_type); 366 if(ret) return ret; 367 } 368 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 369 ret = krb5_store_int32(sp, p->name.name_string.len + 1); 370 else 371 ret = krb5_store_int32(sp, p->name.name_string.len); 372 373 if(ret) return ret; 374 ret = krb5_store_string(sp, p->realm); 375 if(ret) return ret; 376 for(i = 0; i < p->name.name_string.len; i++){ 377 ret = krb5_store_string(sp, p->name.name_string.val[i]); 378 if(ret) return ret; 379 } 380 return 0; 381 } 382 383 krb5_error_code 384 krb5_ret_principal(krb5_storage *sp, 385 krb5_principal *princ) 386 { 387 int i; 388 int ret; 389 krb5_principal p; 390 int32_t type; 391 int32_t ncomp; 392 393 p = calloc(1, sizeof(*p)); 394 if(p == NULL) 395 return ENOMEM; 396 397 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) 398 type = KRB5_NT_UNKNOWN; 399 else if((ret = krb5_ret_int32(sp, &type))){ 400 free(p); 401 return ret; 402 } 403 if((ret = krb5_ret_int32(sp, &ncomp))){ 404 free(p); 405 return ret; 406 } 407 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 408 ncomp--; 409 p->name.name_type = type; 410 p->name.name_string.len = ncomp; 411 ret = krb5_ret_string(sp, &p->realm); 412 if(ret) return ret; 413 p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val)); 414 if(p->name.name_string.val == NULL){ 415 free(p->realm); 416 return ENOMEM; 417 } 418 for(i = 0; i < ncomp; i++){ 419 ret = krb5_ret_string(sp, &p->name.name_string.val[i]); 420 if(ret) return ret; /* XXX */ 421 } 422 *princ = p; 423 return 0; 424 } 425 426 krb5_error_code 427 krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p) 428 { 429 int ret; 430 ret = krb5_store_int16(sp, p.keytype); 431 if(ret) return ret; 432 433 if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){ 434 /* this should really be enctype, but it is the same as 435 keytype nowadays */ 436 ret = krb5_store_int16(sp, p.keytype); 437 if(ret) return ret; 438 } 439 440 ret = krb5_store_data(sp, p.keyvalue); 441 return ret; 442 } 443 444 krb5_error_code 445 krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p) 446 { 447 int ret; 448 int16_t tmp; 449 450 ret = krb5_ret_int16(sp, &tmp); 451 if(ret) return ret; 452 p->keytype = tmp; 453 454 if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){ 455 ret = krb5_ret_int16(sp, &tmp); 456 if(ret) return ret; 457 } 458 459 ret = krb5_ret_data(sp, &p->keyvalue); 460 return ret; 461 } 462 463 krb5_error_code 464 krb5_store_times(krb5_storage *sp, krb5_times times) 465 { 466 int ret; 467 ret = krb5_store_int32(sp, times.authtime); 468 if(ret) return ret; 469 ret = krb5_store_int32(sp, times.starttime); 470 if(ret) return ret; 471 ret = krb5_store_int32(sp, times.endtime); 472 if(ret) return ret; 473 ret = krb5_store_int32(sp, times.renew_till); 474 return ret; 475 } 476 477 krb5_error_code 478 krb5_ret_times(krb5_storage *sp, krb5_times *times) 479 { 480 int ret; 481 int32_t tmp; 482 ret = krb5_ret_int32(sp, &tmp); 483 times->authtime = tmp; 484 if(ret) return ret; 485 ret = krb5_ret_int32(sp, &tmp); 486 times->starttime = tmp; 487 if(ret) return ret; 488 ret = krb5_ret_int32(sp, &tmp); 489 times->endtime = tmp; 490 if(ret) return ret; 491 ret = krb5_ret_int32(sp, &tmp); 492 times->renew_till = tmp; 493 return ret; 494 } 495 496 krb5_error_code 497 krb5_store_address(krb5_storage *sp, krb5_address p) 498 { 499 int ret; 500 ret = krb5_store_int16(sp, p.addr_type); 501 if(ret) return ret; 502 ret = krb5_store_data(sp, p.address); 503 return ret; 504 } 505 506 krb5_error_code 507 krb5_ret_address(krb5_storage *sp, krb5_address *adr) 508 { 509 int16_t t; 510 int ret; 511 ret = krb5_ret_int16(sp, &t); 512 if(ret) return ret; 513 adr->addr_type = t; 514 ret = krb5_ret_data(sp, &adr->address); 515 return ret; 516 } 517 518 krb5_error_code 519 krb5_store_addrs(krb5_storage *sp, krb5_addresses p) 520 { 521 int i; 522 int ret; 523 ret = krb5_store_int32(sp, p.len); 524 if(ret) return ret; 525 for(i = 0; i<p.len; i++){ 526 ret = krb5_store_address(sp, p.val[i]); 527 if(ret) break; 528 } 529 return ret; 530 } 531 532 krb5_error_code 533 krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr) 534 { 535 int i; 536 int ret; 537 int32_t tmp; 538 539 ret = krb5_ret_int32(sp, &tmp); 540 if(ret) return ret; 541 adr->len = tmp; 542 ALLOC(adr->val, adr->len); 543 for(i = 0; i < adr->len; i++){ 544 ret = krb5_ret_address(sp, &adr->val[i]); 545 if(ret) break; 546 } 547 return ret; 548 } 549 550 krb5_error_code 551 krb5_store_authdata(krb5_storage *sp, krb5_authdata auth) 552 { 553 krb5_error_code ret; 554 int i; 555 ret = krb5_store_int32(sp, auth.len); 556 if(ret) return ret; 557 for(i = 0; i < auth.len; i++){ 558 ret = krb5_store_int16(sp, auth.val[i].ad_type); 559 if(ret) break; 560 ret = krb5_store_data(sp, auth.val[i].ad_data); 561 if(ret) break; 562 } 563 return 0; 564 } 565 566 krb5_error_code 567 krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth) 568 { 569 krb5_error_code ret; 570 int32_t tmp; 571 int16_t tmp2; 572 int i; 573 ret = krb5_ret_int32(sp, &tmp); 574 if(ret) return ret; 575 ALLOC_SEQ(auth, tmp); 576 for(i = 0; i < tmp; i++){ 577 ret = krb5_ret_int16(sp, &tmp2); 578 if(ret) break; 579 auth->val[i].ad_type = tmp2; 580 ret = krb5_ret_data(sp, &auth->val[i].ad_data); 581 if(ret) break; 582 } 583 return ret; 584 } 585 586 /* 587 * store `creds' on `sp' returning error or zero 588 */ 589 590 krb5_error_code 591 krb5_store_creds(krb5_storage *sp, krb5_creds *creds) 592 { 593 int ret; 594 595 ret = krb5_store_principal(sp, creds->client); 596 if (ret) 597 return ret; 598 ret = krb5_store_principal(sp, creds->server); 599 if (ret) 600 return ret; 601 ret = krb5_store_keyblock(sp, creds->session); 602 if (ret) 603 return ret; 604 ret = krb5_store_times(sp, creds->times); 605 if (ret) 606 return ret; 607 ret = krb5_store_int8(sp, 0); /* this is probably the 608 enc-tkt-in-skey bit from KDCOptions */ 609 if (ret) 610 return ret; 611 ret = krb5_store_int32(sp, creds->flags.i); 612 if (ret) 613 return ret; 614 ret = krb5_store_addrs(sp, creds->addresses); 615 if (ret) 616 return ret; 617 ret = krb5_store_authdata(sp, creds->authdata); 618 if (ret) 619 return ret; 620 ret = krb5_store_data(sp, creds->ticket); 621 if (ret) 622 return ret; 623 ret = krb5_store_data(sp, creds->second_ticket); 624 if (ret) 625 return ret; 626 return 0; 627 } 628 629 krb5_error_code 630 krb5_ret_creds(krb5_storage *sp, krb5_creds *creds) 631 { 632 krb5_error_code ret; 633 int8_t dummy8; 634 int32_t dummy32; 635 636 memset(creds, 0, sizeof(*creds)); 637 ret = krb5_ret_principal (sp, &creds->client); 638 if(ret) goto cleanup; 639 ret = krb5_ret_principal (sp, &creds->server); 640 if(ret) goto cleanup; 641 ret = krb5_ret_keyblock (sp, &creds->session); 642 if(ret) goto cleanup; 643 ret = krb5_ret_times (sp, &creds->times); 644 if(ret) goto cleanup; 645 ret = krb5_ret_int8 (sp, &dummy8); 646 if(ret) goto cleanup; 647 ret = krb5_ret_int32 (sp, &dummy32); 648 if(ret) goto cleanup; 649 creds->flags.i = dummy32; 650 ret = krb5_ret_addrs (sp, &creds->addresses); 651 if(ret) goto cleanup; 652 ret = krb5_ret_authdata (sp, &creds->authdata); 653 if(ret) goto cleanup; 654 ret = krb5_ret_data (sp, &creds->ticket); 655 if(ret) goto cleanup; 656 ret = krb5_ret_data (sp, &creds->second_ticket); 657 cleanup: 658 if(ret) 659 #if 0 660 krb5_free_creds_contents(context, creds) /* XXX */ 661 #endif 662 ; 663 return ret; 664 } 665