diff options
author | Anderson Toshiyuki Sasaki <ansasaki@redhat.com> | 2019-07-31 15:48:48 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2019-08-06 16:53:22 +0200 |
commit | 5b18bcb0ac39c3c366dd769e893af381ddb5deb2 (patch) | |
tree | 5386bc5a427e2068226be387b5a3d42f5795ab51 /src/known_hosts.c | |
parent | 742918cb1cf99b711538dc9c21e3850fd487dfd6 (diff) | |
download | libssh-5b18bcb0ac39c3c366dd769e893af381ddb5deb2.tar.gz libssh-5b18bcb0ac39c3c366dd769e893af381ddb5deb2.tar.xz libssh-5b18bcb0ac39c3c366dd769e893af381ddb5deb2.zip |
knownhosts: Use ssh_mkdirs() instead of ssh_mkdir()
Previously, if the path to known_hosts file set through
SSH_OPTIONS_KNOWNHOSTS included missing directories,
ssh_session_update_known_hosts() would fail. The added test case checks
that this is not the case anymore.
The logic of checking if the directory is accessible before creating it
was replaced by creating the directory if opening the file failed. This
is to minimize the risk of TOCTOU race conditions.
Fixes: T166
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Diffstat (limited to 'src/known_hosts.c')
-rw-r--r-- | src/known_hosts.c | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/src/known_hosts.c b/src/known_hosts.c index 80520907..9a09d1c4 100644 --- a/src/known_hosts.c +++ b/src/known_hosts.c @@ -496,6 +496,7 @@ int ssh_write_knownhost(ssh_session session) { FILE *file; char *buffer; char *dir; + int rc; if (session->opts.knownhosts == NULL) { if (ssh_options_apply(session) < 0) { @@ -504,30 +505,42 @@ int ssh_write_knownhost(ssh_session session) { } } - /* Check if directory exists and create it if not */ - dir = ssh_dirname(session->opts.knownhosts); - if (dir == NULL) { - ssh_set_error(session, SSH_FATAL, "%s", strerror(errno)); - return SSH_ERROR; - } + errno = 0; + file = fopen(session->opts.knownhosts, "a"); + if (file == NULL) { + if (errno == ENOENT) { + dir = ssh_dirname(session->opts.knownhosts); + if (dir == NULL) { + ssh_set_error(session, SSH_FATAL, "%s", strerror(errno)); + return SSH_ERROR; + } - if (!ssh_file_readaccess_ok(dir)) { - if (ssh_mkdir(dir, 0700) < 0) { - ssh_set_error(session, SSH_FATAL, - "Cannot create %s directory.", dir); + rc = ssh_mkdirs(dir, 0700); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, + "Cannot create %s directory: %s", + dir, strerror(errno)); + SAFE_FREE(dir); + return SSH_ERROR; + } SAFE_FREE(dir); + + errno = 0; + file = fopen(session->opts.knownhosts, "a"); + if (file == NULL) { + ssh_set_error(session, SSH_FATAL, + "Couldn't open known_hosts file %s" + " for appending: %s", + session->opts.knownhosts, strerror(errno)); + return SSH_ERROR; + } + } else { + ssh_set_error(session, SSH_FATAL, + "Couldn't open known_hosts file %s for appending: %s", + session->opts.knownhosts, strerror(errno)); return SSH_ERROR; } } - SAFE_FREE(dir); - - file = fopen(session->opts.knownhosts, "a"); - if (file == NULL) { - ssh_set_error(session, SSH_FATAL, - "Couldn't open known_hosts file %s for appending: %s", - session->opts.knownhosts, strerror(errno)); - return SSH_ERROR; - } buffer = ssh_dump_knownhost(session); if (buffer == NULL) { |