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