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 krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET); 525 return ret; 526} 527 528static krb5_error_code KRB5_CALLCONV 529fkt_next_entry(krb5_context context, 530 krb5_keytab id, 531 krb5_keytab_entry *entry, 532 krb5_kt_cursor *cursor) 533{ 534 return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL); 535} 536 537static krb5_error_code KRB5_CALLCONV 538fkt_end_seq_get(krb5_context context, 539 krb5_keytab id, 540 krb5_kt_cursor *cursor) 541{ 542 krb5_storage_free(cursor->sp); 543 _krb5_xunlock(context, cursor->fd); 544 close(cursor->fd); 545 return 0; 546} 547 548static krb5_error_code KRB5_CALLCONV 549fkt_setup_keytab(krb5_context context, 550 krb5_keytab id, 551 krb5_storage *sp) 552{ 553 krb5_error_code ret; 554 ret = krb5_store_int8(sp, 5); 555 if(ret) 556 return ret; 557 if(id->version == 0) 558 id->version = KRB5_KT_VNO; 559 return krb5_store_int8 (sp, id->version); 560} 561 562static krb5_error_code KRB5_CALLCONV 563fkt_add_entry(krb5_context context, 564 krb5_keytab id, 565 krb5_keytab_entry *entry) 566{ 567 int ret; 568 int fd; 569 krb5_storage *sp; 570 struct fkt_data *d = id->data; 571 krb5_data keytab; 572 int32_t len; 573 574 fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC); 575 if (fd < 0) { 576 fd = open (d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600); 577 if (fd < 0) { 578 ret = errno; 579 krb5_set_error_message(context, ret, 580 N_("open(%s): %s", ""), d->filename, 581 strerror(ret)); 582 return ret; 583 } 584 rk_cloexec(fd); 585 586 ret = _krb5_xlock(context, fd, 1, d->filename); 587 if (ret) { 588 close(fd); 589 return ret; 590 } 591 sp = krb5_storage_from_fd(fd); 592 krb5_storage_set_eof_code(sp, KRB5_KT_END); 593 ret = fkt_setup_keytab(context, id, sp); 594 if(ret) { 595 goto out; 596 } 597 storage_set_flags(context, sp, id->version); 598 } else { 599 int8_t pvno, tag; 600 601 rk_cloexec(fd); 602 603 ret = _krb5_xlock(context, fd, 1, d->filename); 604 if (ret) { 605 close(fd); 606 return ret; 607 } 608 sp = krb5_storage_from_fd(fd); 609 if (sp == NULL) { 610 ret = ENOMEM; 611 krb5_set_error_message(context, ret, N_("out of memory", "")); 612 goto out; 613 } 614 krb5_storage_set_eof_code(sp, KRB5_KT_END); 615 ret = krb5_ret_int8(sp, &pvno); 616 if(ret) { 617 /* we probably have a zero byte file, so try to set it up 618 properly */ 619 ret = fkt_setup_keytab(context, id, sp); 620 if(ret) { 621 krb5_set_error_message(context, ret, 622 N_("%s: keytab is corrupted: %s", ""), 623 d->filename, strerror(ret)); 624 goto out; 625 } 626 storage_set_flags(context, sp, id->version); 627 } else { 628 if(pvno != 5) { 629 ret = KRB5_KEYTAB_BADVNO; 630 krb5_set_error_message(context, ret, 631 N_("Bad version in keytab %s", ""), 632 d->filename); 633 goto out; 634 } 635 ret = krb5_ret_int8 (sp, &tag); 636 if (ret) { 637 krb5_set_error_message(context, ret, 638 N_("failed reading tag from " 639 "keytab %s", ""), 640 d->filename); 641 goto out; 642 } 643 id->version = tag; 644 storage_set_flags(context, sp, id->version); 645 } 646 } 647 648 { 649 krb5_storage *emem; 650 emem = krb5_storage_emem(); 651 if(emem == NULL) { 652 ret = ENOMEM; 653 krb5_set_error_message(context, ret, 654 N_("malloc: out of memory", "")); 655 goto out; 656 } 657 ret = krb5_kt_store_principal(context, emem, entry->principal); 658 if(ret) { 659 krb5_set_error_message(context, ret, 660 N_("Failed storing principal " 661 "in keytab %s", ""), 662 d->filename); 663 krb5_storage_free(emem); 664 goto out; 665 } 666 ret = krb5_store_int32 (emem, entry->timestamp); 667 if(ret) { 668 krb5_set_error_message(context, ret, 669 N_("Failed storing timpstamp " 670 "in keytab %s", ""), 671 d->filename); 672 krb5_storage_free(emem); 673 goto out; 674 } 675 ret = krb5_store_int8 (emem, entry->vno % 256); 676 if(ret) { 677 krb5_set_error_message(context, ret, 678 N_("Failed storing kvno " 679 "in keytab %s", ""), 680 d->filename); 681 krb5_storage_free(emem); 682 goto out; 683 } 684 ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock); 685 if(ret) { 686 krb5_storage_free(emem); 687 goto out; 688 } 689 if ((d->flags & KRB5_KT_FL_JAVA) == 0) { 690 ret = krb5_store_int32 (emem, entry->vno); 691 if (ret) { 692 krb5_set_error_message(context, ret, 693 N_("Failed storing extended kvno " 694 "in keytab %s", ""), 695 d->filename); 696 krb5_storage_free(emem); 697 goto out; 698 } 699 ret = krb5_store_uint32 (emem, entry->flags); 700 if (ret) { 701 krb5_set_error_message(context, ret, 702 N_("Failed storing extended kvno " 703 "in keytab %s", ""), 704 d->filename); 705 krb5_storage_free(emem); 706 goto out; 707 } 708 } 709 710 ret = krb5_storage_to_data(emem, &keytab); 711 krb5_storage_free(emem); 712 if(ret) { 713 krb5_set_error_message(context, ret, 714 N_("Failed converting keytab entry " 715 "to memory block for keytab %s", ""), 716 d->filename); 717 goto out; 718 } 719 } 720 721 while(1) { 722 ret = krb5_ret_int32(sp, &len); 723 if(ret == KRB5_KT_END) { 724 len = (uint32_t)keytab.length; 725 break; 726 } 727 if(len < 0) { 728 len = -len; 729 if(len >= (uint32_t)keytab.length) { 730 krb5_storage_seek(sp, -4, SEEK_CUR); 731 break; 732 } 733 } 734 krb5_storage_seek(sp, len, SEEK_CUR); 735 } 736 ret = krb5_store_int32(sp, len); 737 if(krb5_storage_write(sp, keytab.data, keytab.length) < 0) { 738 ret = errno; 739 krb5_set_error_message(context, ret, 740 N_("Failed writing keytab block " 741 "in keytab %s: %s", ""), 742 d->filename, strerror(ret)); 743 } 744 memset(keytab.data, 0, keytab.length); 745 krb5_data_free(&keytab); 746 out: 747 krb5_storage_free(sp); 748 _krb5_xunlock(context, fd); 749 close(fd); 750 return ret; 751} 752 753static krb5_error_code KRB5_CALLCONV 754fkt_remove_entry(krb5_context context, 755 krb5_keytab id, 756 krb5_keytab_entry *entry) 757{ 758 krb5_keytab_entry e; 759 krb5_kt_cursor cursor; 760 off_t pos_start, pos_end; 761 int found = 0; 762 krb5_error_code ret; 763 764 ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor); 765 if(ret != 0) 766 goto out; /* return other error here? */ 767 while(fkt_next_entry_int(context, id, &e, &cursor, 768 &pos_start, &pos_end) == 0) { 769 if(krb5_kt_compare(context, &e, entry->principal, 770 entry->vno, entry->keyblock.keytype)) { 771 size_t len; 772 unsigned char buf[128]; 773 found = 1; 774 krb5_storage_seek(cursor.sp, pos_start, SEEK_SET); 775 len = (size_t)(pos_end - pos_start - 4); 776 krb5_store_int32(cursor.sp, -(int32_t)len); 777 memset(buf, 0, sizeof(buf)); 778 while(len > 0) { 779 krb5_storage_write(cursor.sp, buf, 780 min((size_t)len, sizeof(buf))); 781 len -= min(len, sizeof(buf)); 782 } 783 } 784 krb5_kt_free_entry(context, &e); 785 } 786 krb5_kt_end_seq_get(context, id, &cursor); 787 out: 788 if (!found) { 789 krb5_clear_error_message (context); 790 return KRB5_KT_NOTFOUND; 791 } 792 return 0; 793} 794 795const krb5_kt_ops krb5_fkt_ops = { 796 "FILE", 797 fkt_resolve, 798 fkt_get_name, 799 fkt_close, 800 fkt_destroy, 801 NULL, /* get */ 802 fkt_start_seq_get, 803 fkt_next_entry, 804 fkt_end_seq_get, 805 fkt_add_entry, 806 fkt_remove_entry 807}; 808 809const krb5_kt_ops krb5_wrfkt_ops = { 810 "WRFILE", 811 fkt_resolve, 812 fkt_get_name, 813 fkt_close, 814 fkt_destroy, 815 NULL, /* get */ 816 fkt_start_seq_get, 817 fkt_next_entry, 818 fkt_end_seq_get, 819 fkt_add_entry, 820 fkt_remove_entry 821}; 822 823const krb5_kt_ops krb5_javakt_ops = { 824 "JAVA14", 825 fkt_resolve_java14, 826 fkt_get_name, 827 fkt_close, 828 fkt_destroy, 829 NULL, /* get */ 830 fkt_start_seq_get, 831 fkt_next_entry, 832 fkt_end_seq_get, 833 fkt_add_entry, 834 fkt_remove_entry 835}; 836