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