diff options
author | Jakub Jelen <jjelen@redhat.com> | 2018-10-19 14:20:40 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2018-10-19 17:43:20 +0200 |
commit | f622c4309b0ffe4679bd1b124638fc1bcddb5758 (patch) | |
tree | 88dca37cad36e79ea0797257ad5f8a179efbe258 /src | |
parent | ae6b0e0f4990421f15157510a1ed53788bf99bff (diff) | |
download | libssh-f622c4309b0ffe4679bd1b124638fc1bcddb5758.tar.gz libssh-f622c4309b0ffe4679bd1b124638fc1bcddb5758.tar.xz libssh-f622c4309b0ffe4679bd1b124638fc1bcddb5758.zip |
knownhosts: Consult also the global known hosts file
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/knownhosts.c | 122 |
1 files changed, 106 insertions, 16 deletions
diff --git a/src/knownhosts.c b/src/knownhosts.c index 54a2f292..23902a5f 100644 --- a/src/knownhosts.c +++ b/src/knownhosts.c @@ -182,11 +182,16 @@ static int known_hosts_read_line(FILE *fp, return -1; } +/* This method reads the known_hosts file referenced by the path + * in filename argument, and entries matching the match argument + * will be added to the list in entries argument. + * If the entries list is NULL, it will allocate a new list. Caller + * is responsible to free it even if an error occurs. + */ static int ssh_known_hosts_read_entries(const char *match, const char *filename, struct ssh_list **entries) { - struct ssh_list *entry_list; char line[8192]; size_t lineno = 0; size_t len = 0; @@ -195,13 +200,18 @@ static int ssh_known_hosts_read_entries(const char *match, fp = fopen(filename, "r"); if (fp == NULL) { - return SSH_ERROR; + SSH_LOG(SSH_LOG_WARN, "Failed to open the known_hosts file '%s': %s", + filename, strerror(errno)); + /* The missing file is not an error here */ + return SSH_OK; } - entry_list = ssh_list_new(); - if (entry_list == NULL) { - fclose(fp); - return SSH_ERROR; + if (*entries == NULL) { + *entries = ssh_list_new(); + if (*entries == NULL) { + fclose(fp); + return SSH_ERROR; + } } for (rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno); @@ -231,15 +241,12 @@ static int ssh_known_hosts_read_entries(const char *match, } else if (rc != SSH_OK) { goto error; } - ssh_list_append(entry_list, entry); + ssh_list_append(*entries, entry); } - *entries = entry_list; - fclose(fp); return SSH_OK; error: - ssh_list_free(entry_list); fclose(fp); return SSH_ERROR; } @@ -323,8 +330,23 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session) rc = ssh_known_hosts_read_entries(host_port, session->opts.knownhosts, &entry_list); + if (rc != 0) { + ssh_list_free(entry_list); + ssh_list_free(list); + return NULL; + } + + rc = ssh_known_hosts_read_entries(host_port, + session->opts.global_knownhosts, + &entry_list); SAFE_FREE(host_port); if (rc != 0) { + ssh_list_free(entry_list); + ssh_list_free(list); + return NULL; + } + + if (entry_list == NULL) { ssh_list_free(list); return NULL; } @@ -554,8 +576,17 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session) rc = ssh_known_hosts_read_entries(host_port, session->opts.knownhosts, &entry_list); + if (rc != 0) { + ssh_list_free(entry_list); + return SSH_KNOWN_HOSTS_UNKNOWN; + } + + rc = ssh_known_hosts_read_entries(host_port, + session->opts.global_knownhosts, + &entry_list); SAFE_FREE(host_port); if (rc != 0) { + ssh_list_free(entry_list); return SSH_KNOWN_HOSTS_UNKNOWN; } @@ -655,10 +686,11 @@ int ssh_session_export_known_hosts_entry(ssh_session session, } /** - * @brief Add the current connected server to the known_hosts file. + * @brief Add the current connected server to the user known_hosts file. * * This adds the currently connected server to the known_hosts file by - * appending a new line at the end. + * appending a new line at the end. The global known_hosts file is considered + * read-only so it is not touched by this function. * * @param[in] session The session to use to write the entry. * @@ -745,6 +777,7 @@ ssh_known_hosts_check_server_key(const char *hosts_entry, filename, &entry_list); if (rc != 0) { + ssh_list_free(entry_list); return SSH_KNOWN_HOSTS_UNKNOWN; } @@ -822,9 +855,7 @@ enum ssh_known_hosts_e ssh_session_get_known_hosts_entry(ssh_session session, struct ssh_knownhosts_entry **pentry) { - ssh_key server_pubkey = NULL; - char *host_port = NULL; - enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN; + enum ssh_known_hosts_e old_rv, rv = SSH_KNOWN_HOSTS_UNKNOWN; if (session->opts.knownhosts == NULL) { if (ssh_options_apply(session) < 0) { @@ -836,6 +867,65 @@ ssh_session_get_known_hosts_entry(ssh_session session, } } + rv = ssh_session_get_known_hosts_entry_file(session, + session->opts.knownhosts, + pentry); + if (rv == SSH_KNOWN_HOSTS_OK) { + /* We already found a match in the first file: return */ + return rv; + } + + old_rv = rv; + rv = ssh_session_get_known_hosts_entry_file(session, + session->opts.global_knownhosts, + pentry); + + /* If we did not find any match at all: we report the previous result */ + if (rv == SSH_KNOWN_HOSTS_UNKNOWN) { + return old_rv; + } + + /* We found some match: return it */ + return rv; + +} + +/** + * @brief Get the known_hosts entry for the current connected session + * from the given known_hosts file. + * + * @param[in] session The session to validate. + * + * @param[in] filename The filename to parse. + * + * @param[in] pentry A pointer to store the allocated known hosts entry. + * + * @returns SSH_KNOWN_HOSTS_OK: The server is known and has not changed.\n + * SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you + * are under attack or the administrator + * changed the key. You HAVE to warn the + * user about a possible attack.\n + * SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while + * we had an other type recorded. It is a + * possible attack.\n + * SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should + * confirm the public key hash is correct.\n + * SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The + * host is thus unknown. File will be + * created if host key is accepted.\n + * SSH_KNOWN_HOSTS_ERROR: There had been an eror checking the host. + * + * @see ssh_knownhosts_entry_free() + */ +enum ssh_known_hosts_e +ssh_session_get_known_hosts_entry_file(ssh_session session, + const char *filename, + struct ssh_knownhosts_entry **pentry) +{ + ssh_key server_pubkey = NULL; + char *host_port = NULL; + enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN; + server_pubkey = ssh_dh_get_current_server_publickey(session); if (server_pubkey == NULL) { ssh_set_error(session, @@ -852,7 +942,7 @@ ssh_session_get_known_hosts_entry(ssh_session session, } found = ssh_known_hosts_check_server_key(host_port, - session->opts.knownhosts, + filename, server_pubkey, pentry); SAFE_FREE(host_port); |