From e49e4e13f3946b85e4f91909a87ce56540ca2561 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 3 Jul 2018 08:07:47 +0200 Subject: [PATCH] knownhosts: Implement ssh_known_hosts_get_algorithms() Signed-off-by: Andreas Schneider --- include/libssh/knownhosts.h | 7 +-- src/knownhosts.c | 87 +++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/include/libssh/knownhosts.h b/include/libssh/knownhosts.h index 723c7ebc..d6dda47e 100644 --- a/include/libssh/knownhosts.h +++ b/include/libssh/knownhosts.h @@ -19,9 +19,10 @@ */ -#ifndef KNOWNHOSTS_H_ -#define KNOWNHOSTS_H_ +#ifndef SSH_KNOWNHOSTS_H_ +#define SSH_KNOWNHOSTS_H_ char **ssh_knownhosts_algorithms(ssh_session session); +struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session); -#endif /* KNOWNHOSTS_H_ */ +#endif /* SSH_KNOWNHOSTS_H_ */ diff --git a/src/knownhosts.c b/src/knownhosts.c index d41cb215..1e17f57f 100644 --- a/src/knownhosts.c +++ b/src/knownhosts.c @@ -41,6 +41,7 @@ #include "libssh/misc.h" #include "libssh/pki.h" #include "libssh/dh.h" +#include "libssh/knownhosts.h" static int hash_hostname(const char *name, unsigned char *salt, @@ -271,6 +272,92 @@ static char *ssh_session_get_host_port(ssh_session session) return host_port; } +/** + * @internal + * @brief Check which host keys should be preferred for the session. + * + * This checks the known_hosts file to find out which algorithms should be + * preferred for the connection we are going to establish. + * + * @param[in] session The ssh session to use. + * + * @return A list of supported key types, NULL on error. + */ +struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session) +{ + struct ssh_list *entry_list = NULL; + struct ssh_iterator *it = NULL; + char *host_port = NULL; + size_t count; + struct ssh_list *list = NULL; + int list_error = 0; + int rc; + + if (session->opts.knownhosts == NULL) { + if (ssh_options_apply(session) < 0) { + ssh_set_error(session, + SSH_REQUEST_DENIED, + "Can't find a known_hosts file"); + + return NULL; + } + } + + host_port = ssh_session_get_host_port(session); + if (host_port == NULL) { + return NULL; + } + + list = ssh_list_new(); + if (list == NULL) { + return NULL; + } + + rc = ssh_known_hosts_read_entries(host_port, + session->opts.knownhosts, + &entry_list); + if (rc != 0) { + ssh_list_free(list); + return NULL; + } + + count = ssh_list_count(entry_list); + if (count == 0) { + ssh_list_free(list); + ssh_list_free(entry_list); + return NULL; + } + + for (it = ssh_list_get_iterator(entry_list); + it != NULL; + it = ssh_list_get_iterator(entry_list)) { + struct ssh_knownhosts_entry *entry = NULL; + enum ssh_keytypes_e key_type; + const char *algo = NULL; + + entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it); + key_type = ssh_key_type(entry->publickey); + algo = ssh_key_type_to_char(key_type); + + rc = ssh_list_append(list, algo); + if (rc != SSH_OK) { + list_error = 1; + } + + ssh_knownhosts_entry_free(entry); + ssh_list_remove(entry_list, it); + } + ssh_list_free(entry_list); + if (list_error) { + goto error; + } + + return list; +error: + ssh_list_free(list); + return NULL; +} + /** * @brief Parse a line from a known_hosts entry into a structure *