hostfile.c (7bc8c308) | hostfile.c (06c9be66) |
---|---|
1/* $OpenBSD: hostfile.c,v 1.61 2015/01/18 21:48:09 djm Exp $ */ | 1/* $OpenBSD: hostfile.c,v 1.62 2015/01/26 03:04:45 djm Exp $ */ |
2/* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Functions for manipulating the known hosts files. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this --- 22 unchanged lines hidden (view full) --- 32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/types.h> | 2/* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Functions for manipulating the known hosts files. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this --- 22 unchanged lines hidden (view full) --- 32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/types.h> |
40#include <sys/stat.h> |
|
40 41#include <netinet/in.h> 42 43#include <errno.h> 44#include <resolv.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <stdarg.h> | 41 42#include <netinet/in.h> 43 44#include <errno.h> 45#include <resolv.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49#include <stdarg.h> |
50#include <unistd.h> |
|
49 50#include "xmalloc.h" 51#include "match.h" 52#include "sshkey.h" 53#include "hostfile.h" 54#include "log.h" 55#include "misc.h" 56#include "ssherr.h" --- 365 unchanged lines hidden (view full) --- 422int 423lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, 424 const struct hostkey_entry **found) 425{ 426 return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype, 427 found) == HOST_FOUND); 428} 429 | 51 52#include "xmalloc.h" 53#include "match.h" 54#include "sshkey.h" 55#include "hostfile.h" 56#include "log.h" 57#include "misc.h" 58#include "ssherr.h" --- 365 unchanged lines hidden (view full) --- 424int 425lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, 426 const struct hostkey_entry **found) 427{ 428 return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype, 429 found) == HOST_FOUND); 430} 431 |
432static int 433write_host_entry(FILE *f, const char *host, 434 const struct sshkey *key, int store_hash) 435{ 436 int r, success = 0; 437 char *hashed_host = NULL; 438 439 if (store_hash) { 440 if ((hashed_host = host_hash(host, NULL, 0)) == NULL) { 441 error("%s: host_hash failed", __func__); 442 return 0; 443 } 444 } 445 fprintf(f, "%s ", store_hash ? hashed_host : host); 446 447 if ((r = sshkey_write(key, f)) == 0) 448 success = 1; 449 else 450 error("%s: sshkey_write failed: %s", __func__, ssh_err(r)); 451 fputc('\n', f); 452 return success; 453} 454 |
|
430/* 431 * Appends an entry to the host file. Returns false if the entry could not 432 * be appended. 433 */ 434int 435add_host_to_hostfile(const char *filename, const char *host, 436 const struct sshkey *key, int store_hash) 437{ 438 FILE *f; | 455/* 456 * Appends an entry to the host file. Returns false if the entry could not 457 * be appended. 458 */ 459int 460add_host_to_hostfile(const char *filename, const char *host, 461 const struct sshkey *key, int store_hash) 462{ 463 FILE *f; |
439 int r, success = 0; 440 char *hashed_host = NULL; | 464 int success; |
441 442 if (key == NULL) 443 return 1; /* XXX ? */ 444 f = fopen(filename, "a"); 445 if (!f) 446 return 0; | 465 466 if (key == NULL) 467 return 1; /* XXX ? */ 468 f = fopen(filename, "a"); 469 if (!f) 470 return 0; |
471 success = write_host_entry(f, host, key, store_hash); 472 fclose(f); 473 return success; 474} |
|
447 | 475 |
448 if (store_hash) { 449 if ((hashed_host = host_hash(host, NULL, 0)) == NULL) { 450 error("%s: host_hash failed", __func__); 451 fclose(f); | 476struct host_delete_ctx { 477 FILE *out; 478 int quiet; 479 const char *host; 480 int *skip_keys; 481 struct sshkey * const *keys; 482 size_t nkeys; 483}; 484 485static int 486host_delete(struct hostkey_foreach_line *l, void *_ctx) 487{ 488 struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx; 489 int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO; 490 size_t i; 491 492 if (l->status == HKF_STATUS_HOST_MATCHED) { 493 if (l->marker != MRK_NONE) { 494 /* Don't remove CA and revocation lines */ 495 fprintf(ctx->out, "%s\n", l->line); |
452 return 0; 453 } | 496 return 0; 497 } |
498 499 /* XXX might need a knob for this later */ 500 /* Don't remove RSA1 keys */ 501 if (l->key->type == KEY_RSA1) { 502 fprintf(ctx->out, "%s\n", l->line); 503 return 0; 504 } 505 506 /* 507 * If this line contains one of the keys that we will be 508 * adding later, then don't change it and mark the key for 509 * skipping. 510 */ 511 for (i = 0; i < ctx->nkeys; i++) { 512 if (sshkey_equal(ctx->keys[i], l->key)) { 513 ctx->skip_keys[i] = 1; 514 fprintf(ctx->out, "%s\n", l->line); 515 debug3("%s: %s key already at %s:%ld", __func__, 516 sshkey_type(l->key), l->path, l->linenum); 517 return 0; 518 } 519 } 520 521 /* 522 * Hostname matches and has no CA/revoke marker, delete it 523 * by *not* writing the line to ctx->out. 524 */ 525 do_log2(loglevel, "%s%s%s:%ld: Host %s removed", 526 ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "", 527 l->path, l->linenum, ctx->host); 528 return 0; |
|
454 } | 529 } |
455 fprintf(f, "%s ", store_hash ? hashed_host : host); | 530 /* Retain non-matching hosts and invalid lines when deleting */ 531 if (l->status == HKF_STATUS_INVALID) { 532 do_log2(loglevel, "%s%s%s:%ld: invalid known_hosts entry", 533 ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "", 534 l->path, l->linenum); 535 } 536 fprintf(ctx->out, "%s\n", l->line); 537 return 0; 538} |
456 | 539 |
457 if ((r = sshkey_write(key, f)) != 0) { 458 error("%s: saving key in %s failed: %s", 459 __func__, filename, ssh_err(r)); 460 } else 461 success = 1; 462 fputc('\n', f); 463 fclose(f); 464 return success; | 540int 541hostfile_replace_entries(const char *filename, const char *host, 542 struct sshkey **keys, size_t nkeys, int store_hash, int quiet) 543{ 544 int r, fd, oerrno = 0; 545 int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO; 546 struct host_delete_ctx ctx; 547 char *temp = NULL, *back = NULL; 548 mode_t omask; 549 size_t i; 550 551 memset(&ctx, 0, sizeof(ctx)); 552 ctx.host = host; 553 ctx.quiet = quiet; 554 if ((ctx.skip_keys = calloc(nkeys, sizeof(*ctx.skip_keys))) == NULL) 555 return SSH_ERR_ALLOC_FAIL; 556 ctx.keys = keys; 557 ctx.nkeys = nkeys; 558 559 /* 560 * Prepare temporary file for in-place deletion. 561 */ 562 if ((r = asprintf(&temp, "%s.XXXXXXXXXXX", filename)) < 0 || 563 (r = asprintf(&back, "%s.old", filename)) < 0) { 564 r = SSH_ERR_ALLOC_FAIL; 565 goto fail; 566 } 567 568 omask = umask(077); 569 if ((fd = mkstemp(temp)) == -1) { 570 oerrno = errno; 571 error("%s: mkstemp: %s", __func__, strerror(oerrno)); 572 r = SSH_ERR_SYSTEM_ERROR; 573 goto fail; 574 } 575 if ((ctx.out = fdopen(fd, "w")) == NULL) { 576 oerrno = errno; 577 close(fd); 578 error("%s: fdopen: %s", __func__, strerror(oerrno)); 579 r = SSH_ERR_SYSTEM_ERROR; 580 goto fail; 581 } 582 583 /* Remove all entries for the specified host from the file */ 584 if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, 585 HKF_WANT_PARSE_KEY)) != 0) { 586 error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); 587 goto fail; 588 } 589 590 /* Add the requested keys */ 591 for (i = 0; i < nkeys; i++) { 592 if (ctx.skip_keys[i]) 593 continue; 594 do_log2(loglevel, "%s%sadd %s key to %s", 595 quiet ? __func__ : "", quiet ? ": " : NULL, 596 sshkey_type(keys[i]), filename); 597 if (!write_host_entry(ctx.out, host, keys[i], store_hash)) { 598 r = SSH_ERR_INTERNAL_ERROR; 599 goto fail; 600 } 601 } 602 fclose(ctx.out); 603 ctx.out = NULL; 604 605 /* Backup the original file and replace it with the temporary */ 606 if (unlink(back) == -1 && errno != ENOENT) { 607 oerrno = errno; 608 error("%s: unlink %.100s: %s", __func__, back, strerror(errno)); 609 r = SSH_ERR_SYSTEM_ERROR; 610 goto fail; 611 } 612 if (link(filename, back) == -1) { 613 oerrno = errno; 614 error("%s: link %.100s to %.100s: %s", __func__, filename, back, 615 strerror(errno)); 616 r = SSH_ERR_SYSTEM_ERROR; 617 goto fail; 618 } 619 if (rename(temp, filename) == -1) { 620 oerrno = errno; 621 error("%s: rename \"%s\" to \"%s\": %s", __func__, 622 temp, filename, strerror(errno)); 623 r = SSH_ERR_SYSTEM_ERROR; 624 goto fail; 625 } 626 /* success */ 627 r = 0; 628 fail: 629 if (temp != NULL && r != 0) 630 unlink(temp); 631 free(temp); 632 free(back); 633 if (ctx.out != NULL) 634 fclose(ctx.out); 635 free(ctx.skip_keys); 636 if (r == SSH_ERR_SYSTEM_ERROR) 637 errno = oerrno; 638 return r; |
465} 466 467static int 468match_maybe_hashed(const char *host, const char *names, int *was_hashed) 469{ 470 int hashed = *names == HASH_DELIM; 471 const char *hashed_host; 472 size_t nlen = strlen(names); --- 133 unchanged lines hidden --- | 639} 640 641static int 642match_maybe_hashed(const char *host, const char *names, int *was_hashed) 643{ 644 int hashed = *names == HASH_DELIM; 645 const char *hashed_host; 646 size_t nlen = strlen(names); --- 133 unchanged lines hidden --- |