From 7955633a554397bc24913cec9fd7285002935f7e Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 25 Jan 2020 00:21:08 +0000 Subject: [PATCH] upstream: allow UpdateKnownHosts=yes to function when multiple known_hosts files are in use. When updating host keys, ssh will now search subsequent known_hosts files, but will add new/changed host keys to the first specified file only. bz#2738 ok markus@ OpenBSD-Commit-ID: 6ded6d878a03e57d5aa20bab9c31f92e929dbc6c --- clientloop.c | 57 +++++++++++++++++++++++++++++++++++++++------------- hostfile.c | 3 ++- ssh.c | 4 ++-- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/clientloop.c b/clientloop.c index d4c23d5541f9..874e1286d0aa 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.332 2020/01/23 07:10:22 dtucker Exp $ */ +/* $OpenBSD: clientloop.c,v 1.333 2020/01/25 00:21:08 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1895,6 +1895,7 @@ update_known_hosts(struct hostkeys_update_ctx *ctx) SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE; char *fp, *response; size_t i; + struct stat sb; for (i = 0; i < ctx->nkeys; i++) { if (ctx->keys_seen[i] != 2) @@ -1941,19 +1942,37 @@ update_known_hosts(struct hostkeys_update_ctx *ctx) if (was_raw) enter_raw_mode(1); } - + if (options.update_hostkeys == 0) + return; /* * Now that all the keys are verified, we can go ahead and replace * them in known_hosts (assuming SSH_UPDATE_HOSTKEYS_ASK didn't * cancel the operation). */ - if (options.update_hostkeys != 0 && - (r = hostfile_replace_entries(options.user_hostfiles[0], - ctx->host_str, ctx->ip_str, ctx->keys, ctx->nkeys, - options.hash_known_hosts, 0, - options.fingerprint_hash)) != 0) - error("%s: hostfile_replace_entries failed: %s", - __func__, ssh_err(r)); + for (i = 0; i < options.num_user_hostfiles; i++) { + /* + * NB. keys are only added to hostfiles[0], for the rest we + * just delete the hostname entries. + */ + if (stat(options.user_hostfiles[i], &sb) != 0) { + if (errno == ENOENT) { + debug("%s: known hosts file %s does not exist", + __func__, strerror(errno)); + } else { + error("%s: known hosts file %s inaccessible", + __func__, strerror(errno)); + } + continue; + } + if ((r = hostfile_replace_entries(options.user_hostfiles[i], + ctx->host_str, ctx->ip_str, + i == 0 ? ctx->keys : NULL, i == 0 ? ctx->nkeys : 0, + options.hash_known_hosts, 0, + options.fingerprint_hash)) != 0) { + error("%s: hostfile_replace_entries failed for %s: %s", + __func__, options.user_hostfiles[i], ssh_err(r)); + } + } } static void @@ -2146,11 +2165,21 @@ client_input_hostkeys(struct ssh *ssh) options.check_host_ip ? &ctx->ip_str : NULL); /* Find which keys we already know about. */ - if ((r = hostkeys_foreach(options.user_hostfiles[0], hostkeys_find, - ctx, ctx->host_str, ctx->ip_str, - HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) { - error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); - goto out; + for (i = 0; i < options.num_user_hostfiles; i++) { + debug("%s: searching %s for %s / %s", __func__, + options.user_hostfiles[i], ctx->host_str, ctx->ip_str); + if ((r = hostkeys_foreach(options.user_hostfiles[i], + hostkeys_find, ctx, ctx->host_str, ctx->ip_str, + HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) { + if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) { + error("%s: hostkeys file %s does not exist", + __func__, options.user_hostfiles[i]); + continue; + } + error("%s: hostkeys_foreach failed for %s: %s", + __func__, options.user_hostfiles[i], ssh_err(r)); + goto out; + } } /* Figure out if we have any new keys to add */ diff --git a/hostfile.c b/hostfile.c index 96ab880d42cd..4a0349a60a39 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.76 2019/07/07 01:05:00 dtucker Exp $ */ +/* $OpenBSD: hostfile.c,v 1.77 2020/01/25 00:21:08 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -566,6 +566,7 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip, /* Remove all entries for the specified host from the file */ if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, ip, HKF_WANT_PARSE_KEY)) != 0) { + oerrno = errno; error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); goto fail; } diff --git a/ssh.c b/ssh.c index 8931ecf81cf0..4998ebc16eea 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.514 2020/01/25 00:03:36 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.515 2020/01/25 00:21:08 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1248,7 +1248,7 @@ main(int ac, char **av) strcmp(options.proxy_command, "-") == 0 && options.proxy_use_fdpass) fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); - if (options.control_persist && + if (options.control_persist && options.control_path != NULL && options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) { debug("UpdateHostKeys=ask is incompatible with ControlPersist; " "disabling");