diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2015-02-16 22:08:58 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2015-02-16 22:08:58 +0000 |
commit | 606ca0953e73ebb7e65d20fe23163fc9bf8f0a3d (patch) | |
tree | eca7df87ae6e98135f00282928f4b553be6a5702 /usr.bin | |
parent | 5a7066d9e713023a0eb5014886361b7be6ed67f5 (diff) |
Refactor hostkeys_foreach() and dependent code
Deal with IP addresses (i.e. CheckHostIP)
Don't clobber known_hosts when nothing changed
ok markus@ as part of larger commit
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/ssh/clientloop.c | 22 | ||||
-rw-r--r-- | usr.bin/ssh/hostfile.c | 219 | ||||
-rw-r--r-- | usr.bin/ssh/hostfile.h | 31 | ||||
-rw-r--r-- | usr.bin/ssh/ssh-keygen.c | 71 |
4 files changed, 218 insertions, 125 deletions
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index 778f0a55fea..54d72155917 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.267 2015/01/26 03:04:45 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.268 2015/02/16 22:08:57 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -2084,8 +2084,9 @@ client_input_hostkeys(void) struct sshbuf *buf = NULL; struct sshkey *key = NULL, **tmp, **keys = NULL; int r, success = 1; - char *fp, *host_str = NULL; + char *fp, *host_str = NULL, *ip_str = NULL; static int hostkeys_seen = 0; /* XXX use struct ssh */ + extern struct sockaddr_storage hostaddr; /* XXX from ssh.c */ /* * NB. Return success for all cases other than protocol error. The @@ -2130,16 +2131,24 @@ client_input_hostkeys(void) key = NULL; } - debug3("%s: received %u keys from server", __func__, nkeys); if (nkeys == 0) { error("%s: server sent no hostkeys", __func__); goto out; } - get_hostfile_hostname_ipaddr(host, NULL, options.port, &host_str, NULL); + get_hostfile_hostname_ipaddr(host, + options.check_host_ip ? (struct sockaddr *)&hostaddr : NULL, + options.port, &host_str, options.check_host_ip ? &ip_str : NULL); - if ((r = hostfile_replace_entries(options.user_hostfiles[0], host_str, - keys, nkeys, options.hash_known_hosts, 1)) != 0) { + debug3("%s: update known hosts for %s%s%s with %u keys from server", + __func__, host_str, + options.check_host_ip ? " " : "", + options.check_host_ip ? ip_str : "", nkeys); + + if ((r = hostfile_replace_entries(options.user_hostfiles[0], + host_str, options.check_host_ip ? ip_str : NULL, + keys, nkeys, options.hash_known_hosts, 0, + options.fingerprint_hash)) != 0) { error("%s: hostfile_replace_entries failed: %s", __func__, ssh_err(r)); goto out; @@ -2148,6 +2157,7 @@ client_input_hostkeys(void) /* Success */ out: free(host_str); + free(ip_str); sshkey_free(key); for (i = 0; i < nkeys; i++) sshkey_free(keys[i]); diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c index ee327fabddd..b067bfc97a5 100644 --- a/usr.bin/ssh/hostfile.c +++ b/usr.bin/ssh/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.63 2015/01/26 13:36:53 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.64 2015/02/16 22:08:57 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -181,24 +181,6 @@ hostfile_read_key(char **cpp, u_int *bitsp, struct sshkey *ret) return 1; } -static int -hostfile_check_key(int bits, const struct sshkey *key, const char *host, - const char *filename, u_long linenum) -{ -#ifdef WITH_SSH1 - if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) - return 1; - if (bits != BN_num_bits(key->rsa->n)) { - logit("Warning: %s, line %lu: keysize mismatch for host %s: " - "actual %d vs. announced %d.", - filename, linenum, host, BN_num_bits(key->rsa->n), bits); - logit("Warning: replace %d with %d in %s, line %lu.", - bits, BN_num_bits(key->rsa->n), filename, linenum); - } -#endif - return 1; -} - static HostkeyMarker check_markers(char **cpp) { @@ -292,8 +274,8 @@ load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path) ctx.num_loaded = 0; ctx.hostkeys = hostkeys; - if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host, - HKF_WANT_MATCH_HOST|HKF_WANT_PARSE_KEY)) != 0) { + if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host, NULL, + HKF_WANT_MATCH|HKF_WANT_PARSE_KEY)) != 0) { if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT) debug("%s: hostkeys_foreach failed for %s: %s", __func__, path, ssh_err(r)); @@ -430,7 +412,7 @@ lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, } static int -write_host_entry(FILE *f, const char *host, +write_host_entry(FILE *f, const char *host, const char *ip, const struct sshkey *key, int store_hash) { int r, success = 0; @@ -441,8 +423,11 @@ write_host_entry(FILE *f, const char *host, error("%s: host_hash failed", __func__); return 0; } - } - fprintf(f, "%s ", store_hash ? hashed_host : host); + fprintf(f, "%s ", hashed_host); + } else if (ip != NULL) + fprintf(f, "%s,%s ", host, ip); + else + fprintf(f, "%s ", host); if ((r = sshkey_write(key, f)) == 0) success = 1; @@ -468,7 +453,7 @@ add_host_to_hostfile(const char *filename, const char *host, f = fopen(filename, "a"); if (!f) return 0; - success = write_host_entry(f, host, key, store_hash); + success = write_host_entry(f, host, NULL, key, store_hash); fclose(f); return success; } @@ -477,19 +462,20 @@ struct host_delete_ctx { FILE *out; int quiet; const char *host; - int *skip_keys; + int *skip_keys; /* XXX split for host/ip? might want to ensure both */ struct sshkey * const *keys; size_t nkeys; + int modified; }; static int host_delete(struct hostkey_foreach_line *l, void *_ctx) { struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx; - int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO; + int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE; size_t i; - if (l->status == HKF_STATUS_HOST_MATCHED) { + if (l->status == HKF_STATUS_MATCHED) { if (l->marker != MRK_NONE) { /* Don't remove CA and revocation lines */ fprintf(ctx->out, "%s\n", l->line); @@ -522,9 +508,10 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx) * Hostname matches and has no CA/revoke marker, delete it * by *not* writing the line to ctx->out. */ - do_log2(loglevel, "%s%s%s:%ld: Host %s removed", + do_log2(loglevel, "%s%s%s:%ld: Removed %s key for host %s", ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "", - l->path, l->linenum, ctx->host); + l->path, l->linenum, sshkey_type(l->key), ctx->host); + ctx->modified = 1; return 0; } /* Retain non-matching hosts and invalid lines when deleting */ @@ -538,13 +525,13 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx) } int -hostfile_replace_entries(const char *filename, const char *host, - struct sshkey **keys, size_t nkeys, int store_hash, int quiet) +hostfile_replace_entries(const char *filename, const char *host, const char *ip, + struct sshkey **keys, size_t nkeys, int store_hash, int quiet, int hash_alg) { int r, fd, oerrno = 0; - int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO; + int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE; struct host_delete_ctx ctx; - char *temp = NULL, *back = NULL; + char *fp, *temp = NULL, *back = NULL; mode_t omask; size_t i; @@ -557,6 +544,7 @@ hostfile_replace_entries(const char *filename, const char *host, return SSH_ERR_ALLOC_FAIL; ctx.keys = keys; ctx.nkeys = nkeys; + ctx.modified = 0; /* * Prepare temporary file for in-place deletion. @@ -582,7 +570,7 @@ hostfile_replace_entries(const char *filename, const char *host, } /* Remove all entries for the specified host from the file */ - if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, + if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, ip, HKF_WANT_PARSE_KEY)) != 0) { error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); goto fail; @@ -592,38 +580,54 @@ hostfile_replace_entries(const char *filename, const char *host, for (i = 0; i < nkeys; i++) { if (ctx.skip_keys[i]) continue; - do_log2(loglevel, "%s%sadd %s key to %s", - quiet ? __func__ : "", quiet ? ": " : NULL, - sshkey_type(keys[i]), filename); - if (!write_host_entry(ctx.out, host, keys[i], store_hash)) { + if ((fp = sshkey_fingerprint(keys[i], hash_alg, + SSH_FP_DEFAULT)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto fail; + } + do_log2(loglevel, "%s%sAdding new key for %s to %s: %s %s", + quiet ? __func__ : "", quiet ? ": " : "", host, filename, + sshkey_ssh_name(keys[i]), fp); + free(fp); + if (!write_host_entry(ctx.out, host, ip, keys[i], store_hash)) { r = SSH_ERR_INTERNAL_ERROR; goto fail; } + ctx.modified = 1; } fclose(ctx.out); ctx.out = NULL; - /* Backup the original file and replace it with the temporary */ - if (unlink(back) == -1 && errno != ENOENT) { - oerrno = errno; - error("%s: unlink %.100s: %s", __func__, back, strerror(errno)); - r = SSH_ERR_SYSTEM_ERROR; - goto fail; - } - if (link(filename, back) == -1) { - oerrno = errno; - error("%s: link %.100s to %.100s: %s", __func__, filename, back, - strerror(errno)); - r = SSH_ERR_SYSTEM_ERROR; - goto fail; - } - if (rename(temp, filename) == -1) { - oerrno = errno; - error("%s: rename \"%s\" to \"%s\": %s", __func__, - temp, filename, strerror(errno)); - r = SSH_ERR_SYSTEM_ERROR; - goto fail; + if (ctx.modified) { + /* Backup the original file and replace it with the temporary */ + if (unlink(back) == -1 && errno != ENOENT) { + oerrno = errno; + error("%s: unlink %.100s: %s", __func__, + back, strerror(errno)); + r = SSH_ERR_SYSTEM_ERROR; + goto fail; + } + if (link(filename, back) == -1) { + oerrno = errno; + error("%s: link %.100s to %.100s: %s", __func__, + filename, back, strerror(errno)); + r = SSH_ERR_SYSTEM_ERROR; + goto fail; + } + if (rename(temp, filename) == -1) { + oerrno = errno; + error("%s: rename \"%s\" to \"%s\": %s", __func__, + temp, filename, strerror(errno)); + r = SSH_ERR_SYSTEM_ERROR; + goto fail; + } + } else { + /* No changes made; just delete the temporary file */ + if (unlink(temp) != 0) + error("%s: unlink \"%s\": %s", __func__, + temp, strerror(errno)); } + /* success */ r = 0; fail: @@ -660,18 +664,20 @@ match_maybe_hashed(const char *host, const char *names, int *was_hashed) int hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, - const char *host, u_int options) + const char *host, const char *ip, u_int options) { FILE *f; - char line[8192], oline[8192]; + char line[8192], oline[8192], ktype[128]; u_long linenum = 0; char *cp, *cp2; u_int kbits; + int hashed; int s, r = 0; struct hostkey_foreach_line lineinfo; + size_t l; memset(&lineinfo, 0, sizeof(lineinfo)); - if (host == NULL && (options & HKF_WANT_MATCH_HOST) != 0) + if (host == NULL && (options & HKF_WANT_MATCH) != 0) return SSH_ERR_INVALID_ARGUMENT; if ((f = fopen(path, "r")) == NULL) return SSH_ERR_SYSTEM_ERROR; @@ -686,13 +692,15 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, lineinfo.path = path; lineinfo.linenum = linenum; lineinfo.line = oline; + lineinfo.marker = MRK_NONE; lineinfo.status = HKF_STATUS_OK; + lineinfo.keytype = KEY_UNSPEC; /* Skip any leading whitespace, comments and empty lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '#' || *cp == '\n') { - if ((options & HKF_WANT_MATCH_HOST) == 0) { + if ((options & HKF_WANT_MATCH) == 0) { lineinfo.status = HKF_STATUS_COMMENT; if ((r = callback(&lineinfo, ctx)) != 0) break; @@ -703,7 +711,7 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) { verbose("%s: invalid marker at %s:%lu", __func__, path, linenum); - if ((options & HKF_WANT_MATCH_HOST) == 0) + if ((options & HKF_WANT_MATCH) == 0) goto bad; continue; } @@ -716,24 +724,47 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, /* Check if the host name matches. */ if (host != NULL) { - s = match_maybe_hashed(host, lineinfo.hosts, - &lineinfo.was_hashed); - if (s == 1) - lineinfo.status = HKF_STATUS_HOST_MATCHED; - else if ((options & HKF_WANT_MATCH_HOST) != 0) - continue; - else if (s == -1) { + if ((s = match_maybe_hashed(host, lineinfo.hosts, + &hashed)) == -1) { debug2("%s: %s:%ld: bad host hash \"%.32s\"", __func__, path, linenum, lineinfo.hosts); goto bad; } + if (s == 1) { + lineinfo.status = HKF_STATUS_MATCHED; + lineinfo.match |= HKF_MATCH_HOST | + (hashed ? HKF_MATCH_HOST_HASHED : 0); + } + /* Try matching IP address if supplied */ + if (ip != NULL) { + if ((s = match_maybe_hashed(ip, lineinfo.hosts, + &hashed)) == -1) { + debug2("%s: %s:%ld: bad ip hash " + "\"%.32s\"", __func__, path, + linenum, lineinfo.hosts); + goto bad; + } + if (s == 1) { + lineinfo.status = HKF_STATUS_MATCHED; + lineinfo.match |= HKF_MATCH_IP | + (hashed ? HKF_MATCH_IP_HASHED : 0); + } + } + /* + * Skip this line if host matching requested and + * neither host nor address matched. + */ + if ((options & HKF_WANT_MATCH) != 0 && + lineinfo.status != HKF_STATUS_MATCHED) + continue; } /* Got a match. Skip host name and any following whitespace */ for (; *cp2 == ' ' || *cp2 == '\t'; cp2++) ; if (*cp2 == '\0' || *cp2 == '#') { - debug2("%s:%ld: truncated before key", path, linenum); + debug2("%s:%ld: truncated before key type", + path, linenum); goto bad; } lineinfo.rawkey = cp = cp2; @@ -746,7 +777,8 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, */ if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) { error("%s: sshkey_new failed", __func__); - return SSH_ERR_ALLOC_FAIL; + r = SSH_ERR_ALLOC_FAIL; + break; } if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) { #ifdef WITH_SSH1 @@ -754,7 +786,8 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, lineinfo.key = sshkey_new(KEY_RSA1); if (lineinfo.key == NULL) { error("%s: sshkey_new fail", __func__); - return SSH_ERR_ALLOC_FAIL; + r = SSH_ERR_ALLOC_FAIL; + break; } if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) @@ -763,9 +796,43 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, goto bad; #endif } - if (!hostfile_check_key(kbits, lineinfo.key, host, - path, linenum)) { + lineinfo.keytype = lineinfo.key->type; + lineinfo.comment = cp; + } else { + /* Extract and parse key type */ + l = strcspn(lineinfo.rawkey, " \t"); + if (l <= 1 || l >= sizeof(ktype) || + lineinfo.rawkey[l] == '\0') + goto bad; + memcpy(ktype, lineinfo.rawkey, l); + ktype[l] = '\0'; + lineinfo.keytype = sshkey_type_from_name(ktype); +#ifdef WITH_SSH1 + /* + * Assume RSA1 if the first component is a short + * decimal number. + */ + if (lineinfo.keytype == KEY_UNSPEC && l < 8 && + strspn(ktype, "0123456789") == l) + lineinfo.keytype = KEY_RSA1; +#endif + /* + * Check that something other than whitespace follows + * the key type. This won't catch all corruption, but + * it does catch trivial truncation. + */ + cp2 += l; /* Skip past key type */ + for (; *cp2 == ' ' || *cp2 == '\t'; cp2++) + ; + if (*cp2 == '\0' || *cp2 == '#') { + debug2("%s:%ld: truncated after key type", + path, linenum); + lineinfo.keytype = KEY_UNSPEC; + } + if (lineinfo.keytype == KEY_UNSPEC) { bad: + sshkey_free(lineinfo.key); + lineinfo.key = NULL; lineinfo.status = HKF_STATUS_INVALID; if ((r = callback(&lineinfo, ctx)) != 0) break; diff --git a/usr.bin/ssh/hostfile.h b/usr.bin/ssh/hostfile.h index 9080b5edb6a..bd2104373f8 100644 --- a/usr.bin/ssh/hostfile.h +++ b/usr.bin/ssh/hostfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.h,v 1.23 2015/01/26 03:04:45 djm Exp $ */ +/* $OpenBSD: hostfile.h,v 1.24 2015/02/16 22:08:57 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -44,8 +44,9 @@ int hostfile_read_key(char **, u_int *, struct sshkey *); int add_host_to_hostfile(const char *, const char *, const struct sshkey *, int); -int hostfile_replace_entries(const char *filename, const char *host, - struct sshkey **keys, size_t nkeys, int store_hash, int quiet); +int hostfile_replace_entries(const char *filename, + const char *host, const char *ip, struct sshkey **keys, size_t nkeys, + int store_hash, int quiet, int hash_alg); #define HASH_MAGIC "|1|" #define HASH_DELIM '|' @@ -60,13 +61,19 @@ char *host_hash(const char *, const char *, u_int); * hostnames. Allows access to the raw keyfile lines to allow * streaming edits to the file to take place. */ -#define HKF_WANT_MATCH_HOST (1) /* return only matching hosts */ +#define HKF_WANT_MATCH (1) /* return only matching hosts/addrs */ #define HKF_WANT_PARSE_KEY (1<<1) /* need key parsed */ -#define HKF_STATUS_OK 1 /* Line parsed, didn't match host */ -#define HKF_STATUS_INVALID 2 /* line had parse error */ -#define HKF_STATUS_COMMENT 3 /* valid line contained no key */ -#define HKF_STATUS_HOST_MATCHED 4 /* hostname matched */ +#define HKF_STATUS_OK 0 /* Line parsed, didn't match host */ +#define HKF_STATUS_INVALID 1 /* line had parse error */ +#define HKF_STATUS_COMMENT 2 /* valid line contained no key */ +#define HKF_STATUS_MATCHED 3 /* hostname or IP matched */ + +#define HKF_MATCH_HOST (1) /* hostname matched */ +#define HKF_MATCH_IP (1<<1) /* address matched */ +#define HKF_MATCH_HOST_HASHED (1<<2) /* hostname was hashed */ +#define HKF_MATCH_IP_HASHED (1<<3) /* address was hashed */ +/* XXX HKF_MATCH_KEY_TYPE? */ /* * The callback function receives this as an argument for each matching @@ -76,12 +83,13 @@ char *host_hash(const char *, const char *, u_int); struct hostkey_foreach_line { const char *path; /* Path of file */ u_long linenum; /* Line number */ - int status; /* One of HKF_STATUS_* */ + u_int status; /* One of HKF_STATUS_* */ + u_int match; /* Zero or more of HKF_MATCH_* OR'd together */ char *line; /* Entire key line; mutable by callback */ int marker; /* CA/revocation markers; indicated by MRK_* value */ const char *hosts; /* Raw hosts text, may be hashed or list multiple */ - int was_hashed; /* Non-zero if hostname was hashed */ const char *rawkey; /* Text of key and any comment following it */ + int keytype; /* Type of key; KEY_UNSPEC for invalid/comment lines */ struct sshkey *key; /* Key, if parsed ok and HKF_WANT_MATCH_HOST set */ const char *comment; /* Any comment following the key */ }; @@ -93,7 +101,8 @@ struct hostkey_foreach_line { */ typedef int hostkeys_foreach_fn(struct hostkey_foreach_line *l, void *ctx); +/* Iterate over a hostkeys file */ int hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, - const char *host, u_int options); + const char *host, const char *ip, u_int options); #endif diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c index 6021837e0ff..9f1f37decd9 100644 --- a/usr.bin/ssh/ssh-keygen.c +++ b/usr.bin/ssh/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.261 2015/01/30 01:10:33 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.262 2015/02/16 22:08:57 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -1033,40 +1033,47 @@ known_hosts_hash(struct hostkey_foreach_line *l, void *_ctx) char *hashed, *cp, *hosts, *ohosts; int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts); - /* Retain invalid lines when hashing, but mark file as invalid. */ - if (l->status == HKF_STATUS_INVALID) { + switch (l->status) { + case HKF_STATUS_OK: + case HKF_STATUS_MATCHED: + /* + * Don't hash hosts already already hashed, with wildcard + * characters or a CA/revocation marker. + */ + if ((l->match & HKF_MATCH_HOST_HASHED) != 0 || + has_wild || l->marker != MRK_NONE) { + fprintf(ctx->out, "%s\n", l->line); + if (has_wild && !find_host) { + fprintf(stderr, "%s:%ld: ignoring host name " + "with wildcard: %.64s\n", l->path, + l->linenum, l->hosts); + } + return 0; + } + /* + * Split any comma-separated hostnames from the host list, + * hash and store separately. + */ + ohosts = hosts = xstrdup(l->hosts); + while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') { + if ((hashed = host_hash(cp, NULL, 0)) == NULL) + fatal("hash_host failed"); + fprintf(ctx->out, "%s %s\n", hashed, l->rawkey); + ctx->has_unhashed = 1; + } + free(ohosts); + return 0; + case HKF_STATUS_INVALID: + /* Retain invalid lines, but mark file as invalid. */ ctx->invalid = 1; fprintf(stderr, "%s:%ld: invalid line\n", l->path, l->linenum); + /* FALLTHROUGH */ + default: fprintf(ctx->out, "%s\n", l->line); return 0; } - - /* - * Don't hash hosts already already hashed, with wildcard characters - * or a CA/revocation marker. - */ - if (l->was_hashed || has_wild || l->marker != MRK_NONE) { - fprintf(ctx->out, "%s\n", l->line); - if (has_wild && !find_host) { - fprintf(stderr, "%s:%ld: ignoring host name " - "with wildcard: %.64s\n", l->path, - l->linenum, l->hosts); - } - return 0; - } - /* - * Split any comma-separated hostnames from the host list, - * hash and store separately. - */ - ohosts = hosts = xstrdup(l->hosts); - while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') { - if ((hashed = host_hash(cp, NULL, 0)) == NULL) - fatal("hash_host failed"); - fprintf(ctx->out, "%s %s\n", hashed, l->rawkey); - ctx->has_unhashed = 1; - } - free(ohosts); - return 0; + /* NOTREACHED */ + return -1; } static int @@ -1074,7 +1081,7 @@ known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx) { struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; - if (l->status == HKF_STATUS_HOST_MATCHED) { + if (l->status == HKF_STATUS_MATCHED) { if (delete_host) { if (l->marker != MRK_NONE) { /* Don't remove CA and revocation lines */ @@ -1161,7 +1168,7 @@ do_known_hosts(struct passwd *pw, const char *name) /* XXX support identity_file == "-" for stdin */ if ((r = hostkeys_foreach(identity_file, hash_hosts ? known_hosts_hash : known_hosts_find_delete, &ctx, - name, find_host ? HKF_WANT_MATCH_HOST : 0)) != 0) + name, NULL, find_host ? HKF_WANT_MATCH : 0)) != 0) fatal("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); if (inplace) |