diff options
-rw-r--r-- | src/known_hosts.c | 51 | ||||
-rw-r--r-- | src/knownhosts.c | 59 | ||||
-rw-r--r-- | tests/client/torture_knownhosts_verify.c | 42 |
3 files changed, 107 insertions, 45 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) { diff --git a/src/knownhosts.c b/src/knownhosts.c index cf9d8a6b..b3587e6c 100644 --- a/src/knownhosts.c +++ b/src/knownhosts.c @@ -979,34 +979,41 @@ int ssh_session_update_known_hosts(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; - } - - rc = ssh_file_readaccess_ok(dir); - if (rc == 0) { - rc = ssh_mkdir(dir, 0700); - } else { - rc = 0; - } - - if (rc != 0) { - ssh_set_error(session, SSH_FATAL, - "Cannot create %s directory.", dir); - SAFE_FREE(dir); - return SSH_ERROR; - } - SAFE_FREE(dir); - + errno = 0; fp = fopen(session->opts.knownhosts, "a"); if (fp == 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; + if (errno == ENOENT) { + dir = ssh_dirname(session->opts.knownhosts); + if (dir == NULL) { + ssh_set_error(session, SSH_FATAL, "%s", strerror(errno)); + return SSH_ERROR; + } + + 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; + fp = fopen(session->opts.knownhosts, "a"); + if (fp == 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; + } } rc = ssh_session_export_known_hosts_entry(session, &entry); diff --git a/tests/client/torture_knownhosts_verify.c b/tests/client/torture_knownhosts_verify.c index df8363e2..2a2a6b64 100644 --- a/tests/client/torture_knownhosts_verify.c +++ b/tests/client/torture_knownhosts_verify.c @@ -35,6 +35,8 @@ #define BAD_RSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQDXvXuawzaArEwkLIXTz/EWywLOCtqQL3P9yKkrhz6AplXP2PhOh5pyxa1VfGKe453jNeYBJ0ROto3BshXgZXbo86oLXTkbe0gO5xi3r5WjXxjOFvRRTLot5fPLNDOv9+TnsPmkNn0iIeyPnfrcPIyjWt5zSWUfkNC8oNHxsiSshjpbJvTXSDipukpUy41d7jg4uWGuonMTF7yu7HfuHqq7lhb0WlwSpfbqAbfYARBddcdcARyhix4RMWZZqVY20H3Vsjq8bjKC+NJXFce1PRg+qcOWQdlXEei4dkzAvHvfQRx1TjzkrBZ6B6thmZtyeb9IsiB0tg2g0JN2VTAGkxqp" +const char template[] = "temp_dir_XXXXXX"; + static int sshd_group_setup(void **state) { torture_setup_sshd_server(state, false); @@ -414,6 +416,43 @@ static void torture_knownhosts_conflict(void **state) /* session will be freed by session_teardown() */ } +static void torture_knownhosts_new_file(void **state) +{ + struct torture_state *s = *state; + ssh_session session = s->ssh.session; + enum ssh_known_hosts_e found; + int rc; + + char new_known_hosts[256]; + char *tmp_dir = NULL; + ssize_t count = 0; + + /* Create a disposable directory */ + tmp_dir = torture_make_temp_dir(template); + assert_non_null(tmp_dir); + + count = snprintf(new_known_hosts, sizeof(new_known_hosts), + "%s/a/b/c/d/known_hosts", tmp_dir); + assert_return_code(count, errno); + + rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, new_known_hosts); + assert_ssh_return_code(session, rc); + + rc = ssh_connect(session); + assert_ssh_return_code(session, rc); + + rc = ssh_session_update_known_hosts(session); + assert_ssh_return_code(session, rc); + + found = ssh_session_is_known_server(session); + assert_int_equal(found, SSH_KNOWN_HOSTS_OK); + + /* Cleanup */ + torture_rmdirs(tmp_dir); + + SAFE_FREE(tmp_dir); +} + int torture_run_tests(void) { int rc; struct CMUnitTest tests[] = { @@ -438,6 +477,9 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_knownhosts_duplicate, session_setup, session_teardown), + cmocka_unit_test_setup_teardown(torture_knownhosts_new_file, + session_setup, + session_teardown), }; ssh_init(); |