aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cryptomilk.org>2018-02-03 16:38:11 +0100
committerAndreas Schneider <asn@cryptomilk.org>2018-06-04 11:20:28 +0200
commita465ea2d49539af1d2575498a5ce45e51980d982 (patch)
treecaadcd85b183e93572804b94a56997c1826c215a
parent702e9e8ad56491e3dda7fc215c8e2f4f139e2d2e (diff)
downloadlibssh-a465ea2d49539af1d2575498a5ce45e51980d982.tar.gz
libssh-a465ea2d49539af1d2575498a5ce45e51980d982.tar.xz
libssh-a465ea2d49539af1d2575498a5ce45e51980d982.zip
knownhosts: Add ssh_known_hosts_read_entries()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--src/knownhosts.c87
-rw-r--r--tests/unittests/torture_knownhosts_parsing.c30
2 files changed, 117 insertions, 0 deletions
diff --git a/src/knownhosts.c b/src/knownhosts.c
index 6557f89f..cf353ef5 100644
--- a/src/knownhosts.c
+++ b/src/knownhosts.c
@@ -142,6 +142,93 @@ void ssh_knownhosts_entry_free(struct ssh_knownhosts_entry *entry)
SAFE_FREE(entry);
}
+static int known_hosts_read_line(FILE *fp,
+ char *buf,
+ size_t buf_size,
+ size_t *buf_len,
+ size_t *lineno)
+{
+ while (fgets(buf, buf_size, fp) != NULL) {
+ size_t len;
+ if (buf[0] == '\0') {
+ continue;
+ }
+
+ *lineno += 1;
+ len = strlen(buf);
+ if (buf_len != NULL) {
+ *buf_len = len;
+ }
+ if (buf[len - 1] == '\n' || feof(fp)) {
+ return 0;
+ } else {
+ errno = E2BIG;
+ return -1;
+ }
+ }
+
+ return -1;
+}
+
+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;
+ FILE *fp;
+ int rc;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return SSH_ERROR;
+ }
+
+ entry_list = ssh_list_new();
+ if (entry_list == NULL) {
+ return SSH_ERROR;
+ }
+
+ for (rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno);
+ rc == 0;
+ rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno)) {
+ struct ssh_knownhosts_entry *entry = NULL;
+ char *p;
+
+ if (line[len] != '\n') {
+ len = strcspn(line, "\n");
+ }
+ line[len] = '\0';
+
+ /* Skip leading spaces */
+ for (p = line; isspace((int)p[0]); p++);
+
+ /* Skip comments and empty lines */
+ if (p[0] == '\0' || p[0] == '#') {
+ continue;
+ }
+
+ rc = ssh_known_hosts_parse_line(match,
+ line,
+ &entry);
+ if (rc == SSH_AGAIN) {
+ continue;
+ } else if (rc != SSH_OK) {
+ goto error;
+ }
+ ssh_list_append(entry_list, entry);
+ }
+
+ *entries = entry_list;
+
+ return SSH_OK;
+error:
+ ssh_list_free(entry_list);
+ return SSH_ERROR;
+}
+
/**
* @brief Parse a line from a known_hosts entry into a structure
*
diff --git a/tests/unittests/torture_knownhosts_parsing.c b/tests/unittests/torture_knownhosts_parsing.c
index 8955c7e8..51d816f2 100644
--- a/tests/unittests/torture_knownhosts_parsing.c
+++ b/tests/unittests/torture_knownhosts_parsing.c
@@ -199,6 +199,33 @@ static void torture_knownhosts_parse_line_hashed_ed25519(void **state) {
SSH_KNOWNHOSTS_ENTRY_FREE(entry);
}
+static void torture_knownhosts_read_file(void **state)
+{
+ const char *knownhosts_file = *state;
+ struct ssh_list *entry_list = NULL;
+ struct ssh_iterator *it = NULL;
+ int rc;
+
+ rc = ssh_known_hosts_read_entries("localhost",
+ knownhosts_file,
+ &entry_list);
+ assert_int_equal(rc, SSH_OK);
+ assert_non_null(entry_list);
+ it = ssh_list_get_iterator(entry_list);
+ assert_non_null(it);
+ for (;it != NULL; it = it->next) {
+ struct ssh_knownhosts_entry *entry = NULL;
+ enum ssh_keytypes_e type;
+
+ entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
+ assert_non_null(entry);
+
+ assert_string_equal(entry->hostname, "localhost");
+ type = ssh_key_type(entry->publickey);
+ assert_int_equal(type, SSH_KEYTYPE_ED25519);
+ }
+}
+
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -208,6 +235,9 @@ int torture_run_tests(void) {
cmocka_unit_test(torture_knownhosts_parse_line_port_ed25519),
cmocka_unit_test(torture_knownhosts_parse_line_pattern_ed25519),
cmocka_unit_test(torture_knownhosts_parse_line_hashed_ed25519),
+ cmocka_unit_test_setup_teardown(torture_knownhosts_read_file,
+ setup_knownhosts_file,
+ teardown_knownhosts_file),
};
ssh_init();