1/* 2 * Copyright (c) 1997 - 2008 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#define KRB5_KT_VNO_1 1 37#define KRB5_KT_VNO_2 2 38#define KRB5_KT_VNO KRB5_KT_VNO_2 39 40#define KRB5_KT_FL_JAVA 1 41 42 43/* file operations -------------------------------------------- */ 44 45struct fkt_data { 46 char *filename; 47 int flags; 48}; 49 50static krb5_error_code 51krb5_kt_ret_data(krb5_context context, 52 krb5_storage *sp, 53 krb5_data *data) 54{ 55 krb5_ssize_t sret; 56 int ret; 57 int16_t size; 58 ret = krb5_ret_int16(sp, &size); 59 if(ret) 60 return ret; 61 data->length = size; 62 data->data = malloc(size); 63 if (data->data == NULL) { 64 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 65 return ENOMEM; 66 } 67 sret = krb5_storage_read(sp, data->data, size); 68 if(sret != size) 69 return (sret < 0)? errno : KRB5_KT_END; 70 return 0; 71} 72 73static krb5_error_code 74krb5_kt_ret_string(krb5_context context, 75 krb5_storage *sp, 76 heim_general_string *data) 77{ 78 krb5_ssize_t sret; 79 int ret; 80 int16_t size; 81 ret = krb5_ret_int16(sp, &size); 82 if(ret) 83 return ret; 84 *data = malloc(size + 1); 85 if (*data == NULL) { 86 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 87 return ENOMEM; 88 } 89 sret = krb5_storage_read(sp, *data, size); 90 (*data)[size] = '\0'; 91 if(sret != size) 92 return (sret < 0)? errno : KRB5_KT_END; 93 return 0; 94} 95 96static krb5_error_code 97krb5_kt_store_data(krb5_context context, 98 krb5_storage *sp, 99 krb5_data data) 100{ 101 krb5_ssize_t sret; 102 int ret; 103 ret = krb5_store_int16(sp, data.length); 104 if(ret < 0) 105 return ret; 106 sret = krb5_storage_write(sp, data.data, data.length); 107 if(sret != (krb5_ssize_t)data.length){ 108 if(sret < 0) 109 return errno; 110 return KRB5_KT_END; 111 } 112 return 0; 113} 114 115static krb5_error_code 116krb5_kt_store_string(krb5_storage *sp, 117 heim_general_string data) 118{ 119 krb5_ssize_t sret; 120 int ret; 121 size_t len = strlen(data); 122 ret = krb5_store_int16(sp, len); 123 if(ret < 0) 124 return ret; 125 sret = krb5_storage_write(sp, data, len); 126 if(sret != (krb5_ssize_t)len){ 127 if(sret < 0) 128 return errno; 129 return KRB5_KT_END; 130 } 131 return 0; 132} 133 134static krb5_error_code 135krb5_kt_ret_keyblock(krb5_context context, 136 struct fkt_data *fkt, 137 krb5_storage *sp, 138 krb5_keyblock *p) 139{ 140 int ret; 141 int16_t tmp; 142 143 ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */ 144 if(ret) { 145 krb5_set_error_message(context, ret, 146 N_("Cant read keyblock from file %s", ""), 147 fkt->filename); 148 return ret; 149 } 150 p->keytype = tmp; 151 ret = krb5_kt_ret_data(context, sp, &p->keyvalue); 152 if (ret) 153 krb5_set_error_message(context, ret, 154 N_("Cant read keyblock from file %s", ""), 155 fkt->filename); 156 return ret; 157} 158 159static krb5_error_code 160krb5_kt_store_keyblock(krb5_context context, 161 struct fkt_data *fkt, 162 krb5_storage *sp, 163 krb5_keyblock *p) 164{ 165 int ret; 166 167 ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */ 168 if(ret) { 169 krb5_set_error_message(context, ret, 170 N_("Cant store keyblock to file %s", ""), 171 fkt->filename); 172 return ret; 173 } 174 ret = krb5_kt_store_data(context, sp, p->keyvalue); 175 if (ret) 176 krb5_set_error_message(context, ret, 177 N_("Cant store keyblock to file %s", ""), 178 fkt->filename); 179 return ret; 180} 181 182 183static krb5_error_code 184krb5_kt_ret_principal(krb5_context context, 185 struct fkt_data *fkt, 186 krb5_storage *sp, 187 krb5_principal *princ) 188{ 189 size_t i; 190 int ret; 191 krb5_principal p; 192 int16_t len; 193 194 ALLOC(p, 1); 195 if(p == NULL) { 196 krb5_set_error_message(context, ENOMEM, 197 N_("malloc: out of memory", "")); 198 return ENOMEM; 199 } 200 201 ret = krb5_ret_int16(sp, &len); 202 if(ret) { 203 krb5_set_error_message(context, ret, 204 N_("Failed decoding length of " 205 "keytab principal in keytab file %s", ""), 206 fkt->filename); 207 goto out; 208 } 209 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 210 len--; 211 if (len < 0) { 212 ret = KRB5_KT_END; 213 krb5_set_error_message(context, ret, 214 N_("Keytab principal contains " 215 "invalid length in keytab %s", ""), 216 fkt->filename); 217 goto out; 218 } 219 ret = krb5_kt_ret_string(context, sp, &p->realm); 220 if(ret) { 221 krb5_set_error_message(context, ret, 222 N_("Can't read realm from keytab: %s", ""), 223 fkt->filename); 224 goto out; 225 } 226 p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val)); 227 if(p->name.name_string.val == NULL) { 228 ret = ENOMEM; 229 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 230 goto out; 231 } 232 p->name.name_string.len = len; 233 for(i = 0; i < p->name.name_string.len; i++){ 234 ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i); 235 if(ret) { 236 krb5_set_error_message(context, ret, 237 N_("Can't read principal from " 238 "keytab: %s", ""), 239 fkt->filename); 240 goto out; 241 } 242 } 243 if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) 244 p->name.name_type = KRB5_NT_UNKNOWN; 245 else { 246 int32_t tmp32; 247 ret = krb5_ret_int32(sp, &tmp32); 248 p->name.name_type = tmp32; 249 if (ret) { 250 krb5_set_error_message(context, ret, 251 N_("Can't read name-type from " 252 "keytab: %s", ""), 253 fkt->filename); 254 goto out; 255 } 256 } 257 *princ = p; 258 return 0; 259out: 260 krb5_free_principal(context, p); 261 return ret; 262} 263 264static krb5_error_code 265krb5_kt_store_principal(krb5_context context, 266 krb5_storage *sp, 267 krb5_principal p) 268{ 269 size_t i; 270 int ret; 271 272 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 273 ret = krb5_store_int16(sp, p->name.name_string.len + 1); 274 else 275 ret = krb5_store_int16(sp, p->name.name_string.len); 276 if(ret) return ret; 277 ret = krb5_kt_store_string(sp, p->realm); 278 if(ret) return ret; 279 for(i = 0; i < p->name.name_string.len; i++){ 280 ret = krb5_kt_store_string(sp, p->name.name_string.val[i]); 281 if(ret) 282 return ret; 283 } 284 if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) { 285 ret = krb5_store_int32(sp, p->name.name_type); 286 if(ret) 287 return ret; 288 } 289 290 return 0; 291} 292 293static krb5_error_code KRB5_CALLCONV 294fkt_resolve(krb5_context context, const char *name, krb5_keytab id) 295{ 296 struct fkt_data *d; 297 298 d = malloc(sizeof(*d)); 299 if(d == NULL) { 300 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 301 return ENOMEM; 302 } 303 d->filename = strdup(name); 304 if(d->filename == NULL) { 305 free(d); 306 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 307 return ENOMEM; 308 } 309 d->flags = 0; 310 id->data = d; 311 return 0; 312} 313 314static krb5_error_code KRB5_CALLCONV 315fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id) 316{ 317 krb5_error_code ret; 318 319 ret = fkt_resolve(context, name, id); 320 if (ret == 0) { 321 struct fkt_data *d = id->data; 322 d->flags |= KRB5_KT_FL_JAVA; 323 } 324 return ret; 325} 326 327static krb5_error_code KRB5_CALLCONV 328fkt_close(krb5_context context, krb5_keytab id) 329{ 330 struct fkt_data *d = id->data; 331 free(d->filename); 332 free(d); 333 return 0; 334} 335 336static krb5_error_code KRB5_CALLCONV 337fkt_destroy(krb5_context context, krb5_keytab id) 338{ 339 struct fkt_data *d = id->data; 340 _krb5_erase_file(context, d->filename); 341 return 0; 342} 343 344static krb5_error_code KRB5_CALLCONV 345fkt_get_name(krb5_context context, 346 krb5_keytab id, 347 char *name, 348 size_t namesize) 349{ 350 /* This function is XXX */ 351 struct fkt_data *d = id->data; 352 strlcpy(name, d->filename, namesize); 353 return 0; 354} 355 356static void 357storage_set_flags(krb5_context context, krb5_storage *sp, int vno) 358{ 359 int flags = 0; 360 switch(vno) { 361 case KRB5_KT_VNO_1: 362 flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS; 363 flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE; 364 flags |= KRB5_STORAGE_HOST_BYTEORDER; 365 break; 366 case KRB5_KT_VNO_2: 367 break; 368 default: 369 krb5_warnx(context, 370 "storage_set_flags called with bad vno (%d)", vno); 371 } 372 krb5_storage_set_flags(sp, flags); 373} 374 375static int 376flags2mode(int flags) 377{ 378 if ((flags & O_RDWR) == O_RDWR) 379 return W_OK|R_OK; 380 else if ((flags & O_WRONLY) == O_WRONLY) 381 return W_OK; 382 return R_OK; 383} 384 385static krb5_error_code 386fkt_start_seq_get_int(krb5_context context, 387 krb5_keytab id, 388 int flags, 389 int exclusive, 390 krb5_kt_cursor *c) 391{ 392 int8_t pvno, tag; 393 krb5_error_code ret; 394 struct fkt_data *d = id->data; 395 396 if (access(d->filename, flags2mode(flags)) != 0) { 397 ret = (krb5_error_code)errno; 398 krb5_set_error_message(context, ret, 399 N_("keytab %s access failed: %s", ""), 400 d->filename, strerror(ret)); 401 return ret; 402 } 403 404 c->fd = open (d->filename, flags); 405 if (c->fd < 0) { 406 ret = errno; 407 krb5_set_error_message(context, ret, 408 N_("keytab %s open failed: %s", ""), 409 d->filename, strerror(ret)); 410 return ret; 411 } 412 rk_cloexec(c->fd); 413 ret = _krb5_xlock(context, c->fd, exclusive, d->filename); 414 if (ret) { 415 close(c->fd); 416 return ret; 417 } 418 c->sp = krb5_storage_from_fd(c->fd); 419 if (c->sp == NULL) { 420 _krb5_xunlock(context, c->fd); 421 close(c->fd); 422 krb5_set_error_message(context, ENOMEM, 423 N_("malloc: out of memory", "")); 424 return ENOMEM; 425 } 426 krb5_storage_set_eof_code(c->sp, KRB5_KT_END); 427 ret = krb5_ret_int8(c->sp, &pvno); 428 if(ret) { 429 krb5_storage_free(c->sp); 430 _krb5_xunlock(context, c->fd); 431 close(c->fd); 432 krb5_clear_error_message(context); 433 return ret; 434 } 435 if(pvno != 5) { 436 krb5_storage_free(c->sp); 437 _krb5_xunlock(context, c->fd); 438 close(c->fd); 439 krb5_clear_error_message (context); 440 return KRB5_KEYTAB_BADVNO; 441 } 442 ret = krb5_ret_int8(c->sp, &tag); 443 if (ret) { 444 krb5_storage_free(c->sp); 445 _krb5_xunlock(context, c->fd); 446 close(c->fd); 447 krb5_clear_error_message(context); 448 return ret; 449 } 450 id->version = tag; 451 storage_set_flags(context, c->sp, id->version); 452 return 0; 453} 454 455static krb5_error_code KRB5_CALLCONV 456fkt_start_seq_get(krb5_context context, 457 krb5_keytab id, 458 krb5_kt_cursor *c) 459{ 460 return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c); 461} 462 463static krb5_error_code 464fkt_next_entry_int(krb5_context context, 465 krb5_keytab id, 466 krb5_keytab_entry *entry, 467 krb5_kt_cursor *cursor, 468 off_t *start, 469 off_t *end) 470{ 471 struct fkt_data *d = id->data; 472 int32_t len; 473 int ret; 474 int8_t tmp8; 475 int32_t tmp32; 476 uint32_t utmp32; 477 off_t pos, curpos; 478 479 pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); 480loop: 481 ret = krb5_ret_int32(cursor->sp, &len); 482 if (ret) 483 return ret; 484 if(len < 0) { 485 pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR); 486 goto loop; 487 } 488 ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal); 489 if (ret) 490 goto out; 491 ret = krb5_ret_uint32(cursor->sp, &utmp32); 492 entry->timestamp = utmp32; 493 if (ret) 494 goto out; 495 ret = krb5_ret_int8(cursor->sp, &tmp8); 496 if (ret) 497 goto out; 498 entry->vno = tmp8; 499 ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock); 500 if (ret) 501 goto out; 502 /* there might be a 32 bit kvno here 503 * if it's zero, assume that the 8bit one was right, 504 * otherwise trust the new value */ 505 curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); 506 if(len + 4 + pos - curpos >= 4) { 507 ret = krb5_ret_int32(cursor->sp, &tmp32); 508 if (ret == 0 && tmp32 != 0) 509 entry->vno = tmp32; 510 } 511 /* there might be a flags field here */ 512 if(len + 4 + pos - curpos >= 8) { 513 ret = krb5_ret_uint32(cursor->sp, &utmp32); 514 if (ret == 0) 515 entry->flags = utmp32; 516 } else 517 entry->flags = 0; 518 519 entry->aliases = NULL; 520 521 if(start) *start = pos; 522 if(end) *end = pos + 4 + len; 523 out: 524 if (ret) 525 krb5_kt_free_entry(context, entry); 526 krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET); 527 return ret; 528} 529 530static krb5_error_code KRB5_CALLCONV 531fkt_next_entry(krb5_context context, 532 krb5_keytab id, 533 krb5_keytab_entry *entry, 534 krb5_kt_cursor *cursor) 535{ 536 return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL); 537} 538 539static krb5_error_code KRB5_CALLCONV 540fkt_end_seq_get(krb5_context context, 541 krb5_keytab id, 542 krb5_kt_cursor *cursor) 543{ 544 krb5_storage_free(cursor->sp); 545 _krb5_xunlock(context, cursor->fd); 546 close(cursor->fd); 547 return 0; 548} 549 550static krb5_error_code KRB5_CALLCONV 551fkt_setup_keytab(krb5_context context, 552 krb5_keytab id, 553 krb5_storage *sp) 554{ 555 krb5_error_code ret; 556 ret = krb5_store_int8(sp, 5); 557 if(ret) 558 return ret; 559 if(id->version == 0) 560 id->version = KRB5_KT_VNO; 561 return krb5_store_int8 (sp, id->version); 562} 563 564static krb5_error_code KRB5_CALLCONV 565fkt_add_entry(krb5_context context, 566 krb5_keytab id, 567 krb5_keytab_entry *entry) 568{ 569 int ret; 570 int fd; 571 krb5_storage *sp; 572 struct fkt_data *d = id->data; 573 krb5_data keytab; 574 int32_t len; 575 576 fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC); 577 if (fd < 0) { 578 fd = open (d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600); 579 if (fd < 0) { 580 ret = errno; 581 krb5_set_error_message(context, ret, 582 N_("open(%s): %s", ""), d->filename, 583 strerror(ret)); 584 return ret; 585 } 586 rk_cloexec(fd); 587 588 ret = _krb5_xlock(context, fd, 1, d->filename); 589 if (ret) { 590 close(fd); 591 return ret; 592 } 593 sp = krb5_storage_from_fd(fd); 594 krb5_storage_set_eof_code(sp, KRB5_KT_END); 595 ret = fkt_setup_keytab(context, id, sp); 596 if(ret) { 597 goto out; 598 } 599 storage_set_flags(context, sp, id->version); 600 } else { 601 int8_t pvno, tag; 602 603 rk_cloexec(fd); 604 605 ret = _krb5_xlock(context, fd, 1, d->filename); 606 if (ret) { 607 close(fd); 608 return ret; 609 } 610 sp = krb5_storage_from_fd(fd); 611 if (sp == NULL) { 612 ret = ENOMEM; 613 krb5_set_error_message(context, ret, N_("out of memory", "")); 614 goto out; 615 } 616 krb5_storage_set_eof_code(sp, KRB5_KT_END); 617 ret = krb5_ret_int8(sp, &pvno); 618 if(ret) { 619 /* we probably have a zero byte file, so try to set it up 620 properly */ 621 ret = fkt_setup_keytab(context, id, sp); 622 if(ret) { 623 krb5_set_error_message(context, ret, 624 N_("%s: keytab is corrupted: %s", ""), 625 d->filename, strerror(ret)); 626 goto out; 627 } 628 storage_set_flags(context, sp, id->version); 629 } else { 630 if(pvno != 5) { 631 ret = KRB5_KEYTAB_BADVNO; 632 krb5_set_error_message(context, ret, 633 N_("Bad version in keytab %s", ""), 634 d->filename); 635 goto out; 636 } 637 ret = krb5_ret_int8 (sp, &tag); 638 if (ret) { 639 krb5_set_error_message(context, ret, 640 N_("failed reading tag from " 641 "keytab %s", ""), 642 d->filename); 643 goto out; 644 } 645 id->version = tag; 646 storage_set_flags(context, sp, id->version); 647 } 648 } 649 650 { 651 krb5_storage *emem; 652 emem = krb5_storage_emem(); 653 if(emem == NULL) { 654 ret = ENOMEM; 655 krb5_set_error_message(context, ret, 656 N_("malloc: out of memory", "")); 657 goto out; 658 } 659 ret = krb5_kt_store_principal(context, emem, entry->principal); 660 if(ret) { 661 krb5_set_error_message(context, ret, 662 N_("Failed storing principal " 663 "in keytab %s", ""), 664 d->filename); 665 krb5_storage_free(emem); 666 goto out; 667 } 668 ret = krb5_store_int32 (emem, entry->timestamp); 669 if(ret) { 670 krb5_set_error_message(context, ret, 671 N_("Failed storing timpstamp " 672 "in keytab %s", ""), 673 d->filename); 674 krb5_storage_free(emem); 675 goto out; 676 } 677 ret = krb5_store_int8 (emem, entry->vno % 256); 678 if(ret) { 679 krb5_set_error_message(context, ret, 680 N_("Failed storing kvno " 681 "in keytab %s", ""), 682 d->filename); 683 krb5_storage_free(emem); 684 goto out; 685 } 686 ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock); 687 if(ret) { 688 krb5_storage_free(emem); 689 goto out; 690 } 691 if ((d->flags & KRB5_KT_FL_JAVA) == 0) { 692 ret = krb5_store_int32 (emem, entry->vno); 693 if (ret) { 694 krb5_set_error_message(context, ret, 695 N_("Failed storing extended kvno " 696 "in keytab %s", ""), 697 d->filename); 698 krb5_storage_free(emem); 699 goto out; 700 } 701 ret = krb5_store_uint32 (emem, entry->flags); 702 if (ret) { 703 krb5_set_error_message(context, ret, 704 N_("Failed storing extended kvno " 705 "in keytab %s", ""), 706 d->filename); 707 krb5_storage_free(emem); 708 goto out; 709 } 710 } 711 712 ret = krb5_storage_to_data(emem, &keytab); 713 krb5_storage_free(emem); 714 if(ret) { 715 krb5_set_error_message(context, ret, 716 N_("Failed converting keytab entry " 717 "to memory block for keytab %s", ""), 718 d->filename); 719 goto out; 720 } 721 } 722 723 while(1) { 724 ret = krb5_ret_int32(sp, &len); 725 if(ret == KRB5_KT_END) { 726 len = (uint32_t)keytab.length; 727 break; 728 } 729 if(len < 0) { 730 len = -len; 731 if(len >= (int32_t)keytab.length) { 732 krb5_storage_seek(sp, -4, SEEK_CUR); 733 break; 734 } 735 } 736 krb5_storage_seek(sp, len, SEEK_CUR); 737 } 738 ret = krb5_store_int32(sp, len); 739 if(krb5_storage_write(sp, keytab.data, keytab.length) < 0) { 740 ret = errno; 741 krb5_set_error_message(context, ret, 742 N_("Failed writing keytab block " 743 "in keytab %s: %s", ""), 744 d->filename, strerror(ret)); 745 } 746 memset(keytab.data, 0, keytab.length); 747 krb5_data_free(&keytab); 748 out: 749 krb5_storage_free(sp); 750 _krb5_xunlock(context, fd); 751 close(fd); 752 return ret; 753} 754 755static krb5_error_code KRB5_CALLCONV 756fkt_remove_entry(krb5_context context, 757 krb5_keytab id, 758 krb5_keytab_entry *entry) 759{ 760 krb5_keytab_entry e; 761 krb5_kt_cursor cursor; 762 off_t pos_start, pos_end; 763 int found = 0; 764 krb5_error_code ret; 765 766 ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor); 767 if(ret != 0) 768 goto out; /* return other error here? */ 769 while(fkt_next_entry_int(context, id, &e, &cursor, 770 &pos_start, &pos_end) == 0) { 771 if(krb5_kt_compare(context, &e, entry->principal, 772 entry->vno, entry->keyblock.keytype)) { 773 size_t len; 774 unsigned char buf[128]; 775 found = 1; 776 krb5_storage_seek(cursor.sp, pos_start, SEEK_SET); 777 len = (size_t)(pos_end - pos_start - 4); 778 krb5_store_int32(cursor.sp, -(int32_t)len); 779 memset(buf, 0, sizeof(buf)); 780 while(len > 0) { 781 krb5_storage_write(cursor.sp, buf, 782 min((size_t)len, sizeof(buf))); 783 len -= min(len, sizeof(buf)); 784 } 785 } 786 krb5_kt_free_entry(context, &e); 787 } 788 krb5_kt_end_seq_get(context, id, &cursor); 789 out: 790 if (!found) { 791 krb5_clear_error_message (context); 792 return KRB5_KT_NOTFOUND; 793 } 794 return 0; 795} 796 797const krb5_kt_ops krb5_fkt_ops = { 798 "FILE", 799 fkt_resolve, 800 fkt_get_name, 801 fkt_close, 802 fkt_destroy, 803 NULL, /* get */ 804 fkt_start_seq_get, 805 fkt_next_entry, 806 fkt_end_seq_get, 807 fkt_add_entry, 808 fkt_remove_entry 809}; 810 811const krb5_kt_ops krb5_wrfkt_ops = { 812 "WRFILE", 813 fkt_resolve, 814 fkt_get_name, 815 fkt_close, 816 fkt_destroy, 817 NULL, /* get */ 818 fkt_start_seq_get, 819 fkt_next_entry, 820 fkt_end_seq_get, 821 fkt_add_entry, 822 fkt_remove_entry 823}; 824 825const krb5_kt_ops krb5_javakt_ops = { 826 "JAVA14", 827 fkt_resolve_java14, 828 fkt_get_name, 829 fkt_close, 830 fkt_destroy, 831 NULL, /* get */ 832 fkt_start_seq_get, 833 fkt_next_entry, 834 fkt_end_seq_get, 835 fkt_add_entry, 836 fkt_remove_entry 837}; 838