aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/hostfile.c
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2021-09-08 01:05:51 +0000
committerEd Maste <emaste@FreeBSD.org>2021-09-08 01:05:51 +0000
commit19261079b74319502c6ffa1249920079f0f69a72 (patch)
treea07fb2205e0cea7dee1ffbcc945d9d5b97124714 /crypto/openssh/hostfile.c
parentc5128c48df3c2f3828432aff2ea536bb9c887e14 (diff)
parent66719ee573ac2290622db642f6e89ab35b179f3d (diff)
downloadsrc-19261079b74319502c6ffa1249920079f0f69a72.tar.gz
src-19261079b74319502c6ffa1249920079f0f69a72.zip
openssh: update to OpenSSH v8.7p1
Some notable changes, from upstream's release notes: - sshd(8): Remove support for obsolete "host/port" syntax. - ssh(1): When prompting whether to record a new host key, accept the key fingerprint as a synonym for "yes". - ssh-keygen(1): when acting as a CA and signing certificates with an RSA key, default to using the rsa-sha2-512 signature algorithm. - ssh(1), sshd(8), ssh-keygen(1): this release removes the "ssh-rsa" (RSA/SHA1) algorithm from those accepted for certificate signatures. - ssh-sk-helper(8): this is a new binary. It is used by the FIDO/U2F support to provide address-space isolation for token middleware libraries (including the internal one). - ssh(1): this release enables UpdateHostkeys by default subject to some conservative preconditions. - scp(1): this release changes the behaviour of remote to remote copies (e.g. "scp host-a:/path host-b:") to transfer through the local host by default. - scp(1): experimental support for transfers using the SFTP protocol as a replacement for the venerable SCP/RCP protocol that it has traditionally used. Additional integration work is needed to support FIDO/U2F in the base system. Deprecation Notice ------------------ OpenSSH will disable the ssh-rsa signature scheme by default in the next release. Reviewed by: imp MFC after: 1 month Relnotes: Yes Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D29985
Diffstat (limited to 'crypto/openssh/hostfile.c')
-rw-r--r--crypto/openssh/hostfile.c269
1 files changed, 185 insertions, 84 deletions
diff --git a/crypto/openssh/hostfile.c b/crypto/openssh/hostfile.c
index e1f826bddc9e..ce00cd713549 100644
--- a/crypto/openssh/hostfile.c
+++ b/crypto/openssh/hostfile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hostfile.c,v 1.73 2018/07/16 03:09:13 djm Exp $ */
+/* $OpenBSD: hostfile.c,v 1.91 2021/07/05 01:16:46 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -49,7 +49,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdarg.h>
#include <unistd.h>
#include "xmalloc.h"
@@ -58,14 +57,11 @@
#include "hostfile.h"
#include "log.h"
#include "misc.h"
+#include "pathnames.h"
#include "ssherr.h"
#include "digest.h"
#include "hmac.h"
-
-struct hostkeys {
- struct hostkey_entry *entries;
- u_int num_entries;
-};
+#include "sshbuf.h"
/* XXX hmac is too easy to dictionary attack; use bcrypt? */
@@ -141,12 +137,12 @@ host_hash(const char *host, const char *name_from_hostfile, u_int src_len)
ssh_hmac_init(ctx, salt, len) < 0 ||
ssh_hmac_update(ctx, host, strlen(host)) < 0 ||
ssh_hmac_final(ctx, result, sizeof(result)))
- fatal("%s: ssh_hmac failed", __func__);
+ fatal_f("ssh_hmac failed");
ssh_hmac_free(ctx);
if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 ||
__b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1)
- fatal("%s: __b64_ntop failed", __func__);
+ fatal_f("__b64_ntop failed");
snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt,
HASH_DELIM, uu_result);
@@ -163,13 +159,12 @@ int
hostfile_read_key(char **cpp, u_int *bitsp, struct sshkey *ret)
{
char *cp;
- int r;
/* Skip leading whitespace. */
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
;
- if ((r = sshkey_read(ret, &cp)) != 0)
+ if (sshkey_read(ret, &cp) != 0)
return 0;
/* Skip trailing whitespace. */
@@ -247,7 +242,7 @@ record_hostkey(struct hostkey_foreach_line *l, void *_ctx)
return 0;
}
- debug3("%s: found %skey type %s in file %s:%lu", __func__,
+ debug3_f("found %skey type %s in file %s:%lu",
l->marker == MRK_NONE ? "" :
(l->marker == MRK_CA ? "ca " : "revoked "),
sshkey_type(l->key), l->path, l->linenum);
@@ -261,6 +256,7 @@ record_hostkey(struct hostkey_foreach_line *l, void *_ctx)
hostkeys->entries[hostkeys->num_entries].key = l->key;
l->key = NULL; /* steal it */
hostkeys->entries[hostkeys->num_entries].marker = l->marker;
+ hostkeys->entries[hostkeys->num_entries].note = l->note;
hostkeys->num_entries++;
ctx->num_loaded++;
@@ -268,7 +264,8 @@ record_hostkey(struct hostkey_foreach_line *l, void *_ctx)
}
void
-load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
+load_hostkeys_file(struct hostkeys *hostkeys, const char *host,
+ const char *path, FILE *f, u_int note)
{
int r;
struct load_callback_ctx ctx;
@@ -277,15 +274,28 @@ load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
ctx.num_loaded = 0;
ctx.hostkeys = hostkeys;
- if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host, NULL,
- HKF_WANT_MATCH|HKF_WANT_PARSE_KEY)) != 0) {
+ if ((r = hostkeys_foreach_file(path, f, record_hostkey, &ctx, host,
+ NULL, HKF_WANT_MATCH|HKF_WANT_PARSE_KEY, note)) != 0) {
if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT)
- debug("%s: hostkeys_foreach failed for %s: %s",
- __func__, path, ssh_err(r));
+ debug_fr(r, "hostkeys_foreach failed for %s", path);
}
if (ctx.num_loaded != 0)
- debug3("%s: loaded %lu keys from %s", __func__,
- ctx.num_loaded, host);
+ debug3_f("loaded %lu keys from %s", ctx.num_loaded, host);
+}
+
+void
+load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path,
+ u_int note)
+{
+ FILE *f;
+
+ if ((f = fopen(path, "r")) == NULL) {
+ debug_f("fopen %s: %s", path, strerror(errno));
+ return;
+ }
+
+ load_hostkeys_file(hostkeys, host, path, f, note);
+ fclose(f);
}
void
@@ -300,8 +310,7 @@ free_hostkeys(struct hostkeys *hostkeys)
explicit_bzero(hostkeys->entries + i, sizeof(*hostkeys->entries));
}
free(hostkeys->entries);
- explicit_bzero(hostkeys, sizeof(*hostkeys));
- free(hostkeys);
+ freezero(hostkeys, sizeof(*hostkeys));
}
static int
@@ -315,7 +324,7 @@ check_key_not_revoked(struct hostkeys *hostkeys, struct sshkey *k)
continue;
if (sshkey_equal_public(k, hostkeys->entries[i].key))
return -1;
- if (is_cert &&
+ if (is_cert && k != NULL &&
sshkey_equal_public(k->cert->signature_key,
hostkeys->entries[i].key))
return -1;
@@ -340,7 +349,7 @@ check_key_not_revoked(struct hostkeys *hostkeys, struct sshkey *k)
*/
static HostStatus
check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
- struct sshkey *k, int keytype, const struct hostkey_entry **found)
+ struct sshkey *k, int keytype, int nid, const struct hostkey_entry **found)
{
u_int i;
HostStatus end_return = HOST_NEW;
@@ -356,6 +365,10 @@ check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
if (k == NULL) {
if (hostkeys->entries[i].key->type != keytype)
continue;
+ if (nid != -1 &&
+ sshkey_type_plain(keytype) == KEY_ECDSA &&
+ hostkeys->entries[i].key->ecdsa_nid != nid)
+ continue;
end_return = HOST_FOUND;
if (found != NULL)
*found = hostkeys->entries + i;
@@ -378,7 +391,7 @@ check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
*found = hostkeys->entries + i;
break;
}
- /* A non-maching key exists */
+ /* A non-matching key exists */
end_return = HOST_CHANGED;
if (found != NULL)
*found = hostkeys->entries + i;
@@ -398,17 +411,29 @@ check_key_in_hostkeys(struct hostkeys *hostkeys, struct sshkey *key,
{
if (key == NULL)
fatal("no key to look up");
- return check_hostkeys_by_key_or_type(hostkeys, key, 0, found);
+ return check_hostkeys_by_key_or_type(hostkeys, key, 0, -1, found);
}
int
-lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype,
+lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, int nid,
const struct hostkey_entry **found)
{
- return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype,
+ return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype, nid,
found) == HOST_FOUND);
}
+int
+lookup_marker_in_hostkeys(struct hostkeys *hostkeys, int want_marker)
+{
+ u_int i;
+
+ for (i = 0; i < hostkeys->num_entries; i++) {
+ if (hostkeys->entries[i].marker == (HostkeyMarker)want_marker)
+ return 1;
+ }
+ return 0;
+}
+
static int
write_host_entry(FILE *f, const char *host, const char *ip,
const struct sshkey *key, int store_hash)
@@ -421,7 +446,7 @@ write_host_entry(FILE *f, const char *host, const char *ip,
if (store_hash) {
if ((hashed_host = host_hash(lhost, NULL, 0)) == NULL) {
- error("%s: host_hash failed", __func__);
+ error_f("host_hash failed");
free(lhost);
return 0;
}
@@ -435,12 +460,53 @@ write_host_entry(FILE *f, const char *host, const char *ip,
if ((r = sshkey_write(key, f)) == 0)
success = 1;
else
- error("%s: sshkey_write failed: %s", __func__, ssh_err(r));
+ error_fr(r, "sshkey_write");
fputc('\n', f);
+ /* If hashing is enabled, the IP address needs to go on its own line */
+ if (success && store_hash && ip != NULL)
+ success = write_host_entry(f, ip, NULL, key, 1);
return success;
}
/*
+ * Create user ~/.ssh directory if it doesn't exist and we want to write to it.
+ * If notify is set, a message will be emitted if the directory is created.
+ */
+void
+hostfile_create_user_ssh_dir(const char *filename, int notify)
+{
+ char *dotsshdir = NULL, *p;
+ size_t len;
+ struct stat st;
+
+ if ((p = strrchr(filename, '/')) == NULL)
+ return;
+ len = p - filename;
+ dotsshdir = tilde_expand_filename("~/" _PATH_SSH_USER_DIR, getuid());
+ if (strlen(dotsshdir) > len || strncmp(filename, dotsshdir, len) != 0)
+ goto out; /* not ~/.ssh prefixed */
+ if (stat(dotsshdir, &st) == 0)
+ goto out; /* dir already exists */
+ else if (errno != ENOENT)
+ error("Could not stat %s: %s", dotsshdir, strerror(errno));
+ else {
+#ifdef WITH_SELINUX
+ ssh_selinux_setfscreatecon(dotsshdir);
+#endif
+ if (mkdir(dotsshdir, 0700) == -1)
+ error("Could not create directory '%.200s' (%s).",
+ dotsshdir, strerror(errno));
+ else if (notify)
+ logit("Created directory '%s'.", dotsshdir);
+#ifdef WITH_SELINUX
+ ssh_selinux_setfscreatecon(NULL);
+#endif
+ }
+ out:
+ free(dotsshdir);
+}
+
+/*
* Appends an entry to the host file. Returns false if the entry could not
* be appended.
*/
@@ -453,6 +519,7 @@ add_host_to_hostfile(const char *filename, const char *host,
if (key == NULL)
return 1; /* XXX ? */
+ hostfile_create_user_ssh_dir(filename, 0);
f = fopen(filename, "a");
if (!f)
return 0;
@@ -464,8 +531,8 @@ add_host_to_hostfile(const char *filename, const char *host,
struct host_delete_ctx {
FILE *out;
int quiet;
- const char *host;
- int *skip_keys; /* XXX split for host/ip? might want to ensure both */
+ const char *host, *ip;
+ u_int *match_keys; /* mask of HKF_MATCH_* for this key */
struct sshkey * const *keys;
size_t nkeys;
int modified;
@@ -478,26 +545,21 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx)
int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
size_t i;
- if (l->status == HKF_STATUS_MATCHED) {
- if (l->marker != MRK_NONE) {
- /* Don't remove CA and revocation lines */
- fprintf(ctx->out, "%s\n", l->line);
- return 0;
- }
-
+ /* Don't remove CA and revocation lines */
+ if (l->status == HKF_STATUS_MATCHED && l->marker == MRK_NONE) {
/*
* If this line contains one of the keys that we will be
* adding later, then don't change it and mark the key for
* skipping.
*/
for (i = 0; i < ctx->nkeys; i++) {
- if (sshkey_equal(ctx->keys[i], l->key)) {
- ctx->skip_keys[i] = 1;
- fprintf(ctx->out, "%s\n", l->line);
- debug3("%s: %s key already at %s:%ld", __func__,
- sshkey_type(l->key), l->path, l->linenum);
- return 0;
- }
+ if (!sshkey_equal(ctx->keys[i], l->key))
+ continue;
+ ctx->match_keys[i] |= l->match;
+ fprintf(ctx->out, "%s\n", l->line);
+ debug3_f("%s key already at %s:%ld",
+ sshkey_type(l->key), l->path, l->linenum);
+ return 0;
}
/*
@@ -528,15 +590,19 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip,
int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
struct host_delete_ctx ctx;
char *fp, *temp = NULL, *back = NULL;
+ const char *what;
mode_t omask;
size_t i;
+ u_int want;
omask = umask(077);
memset(&ctx, 0, sizeof(ctx));
ctx.host = host;
+ ctx.ip = ip;
ctx.quiet = quiet;
- if ((ctx.skip_keys = calloc(nkeys, sizeof(*ctx.skip_keys))) == NULL)
+
+ if ((ctx.match_keys = calloc(nkeys, sizeof(*ctx.match_keys))) == NULL)
return SSH_ERR_ALLOC_FAIL;
ctx.keys = keys;
ctx.nkeys = nkeys;
@@ -545,50 +611,73 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip,
/*
* Prepare temporary file for in-place deletion.
*/
- if ((r = asprintf(&temp, "%s.XXXXXXXXXXX", filename)) < 0 ||
- (r = asprintf(&back, "%s.old", filename)) < 0) {
+ if ((r = asprintf(&temp, "%s.XXXXXXXXXXX", filename)) == -1 ||
+ (r = asprintf(&back, "%s.old", filename)) == -1) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
if ((fd = mkstemp(temp)) == -1) {
oerrno = errno;
- error("%s: mkstemp: %s", __func__, strerror(oerrno));
+ error_f("mkstemp: %s", strerror(oerrno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if ((ctx.out = fdopen(fd, "w")) == NULL) {
oerrno = errno;
close(fd);
- error("%s: fdopen: %s", __func__, strerror(oerrno));
+ error_f("fdopen: %s", strerror(oerrno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
- /* Remove all entries for the specified host from the file */
+ /* Remove stale/mismatching entries for the specified host */
if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, ip,
- HKF_WANT_PARSE_KEY)) != 0) {
- error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));
+ HKF_WANT_PARSE_KEY, 0)) != 0) {
+ oerrno = errno;
+ error_fr(r, "hostkeys_foreach");
goto fail;
}
- /* Add the requested keys */
+ /* Re-add the requested keys */
+ want = HKF_MATCH_HOST | (ip == NULL ? 0 : HKF_MATCH_IP);
for (i = 0; i < nkeys; i++) {
- if (ctx.skip_keys[i])
+ if ((want & ctx.match_keys[i]) == want)
continue;
if ((fp = sshkey_fingerprint(keys[i], hash_alg,
SSH_FP_DEFAULT)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
- do_log2(loglevel, "%s%sAdding new key for %s to %s: %s %s",
- quiet ? __func__ : "", quiet ? ": " : "", host, filename,
+ /* write host/ip */
+ what = "";
+ if (ctx.match_keys[i] == 0) {
+ what = "Adding new key";
+ if (!write_host_entry(ctx.out, host, ip,
+ keys[i], store_hash)) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto fail;
+ }
+ } else if ((want & ~ctx.match_keys[i]) == HKF_MATCH_HOST) {
+ what = "Fixing match (hostname)";
+ if (!write_host_entry(ctx.out, host, NULL,
+ keys[i], store_hash)) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto fail;
+ }
+ } else if ((want & ~ctx.match_keys[i]) == HKF_MATCH_IP) {
+ what = "Fixing match (address)";
+ if (!write_host_entry(ctx.out, ip, NULL,
+ keys[i], store_hash)) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto fail;
+ }
+ }
+ do_log2(loglevel, "%s%s%s for %s%s%s to %s: %s %s",
+ quiet ? __func__ : "", quiet ? ": " : "", what,
+ host, ip == NULL ? "" : ",", ip == NULL ? "" : ip, filename,
sshkey_ssh_name(keys[i]), fp);
free(fp);
- if (!write_host_entry(ctx.out, host, ip, keys[i], store_hash)) {
- r = SSH_ERR_INTERNAL_ERROR;
- goto fail;
- }
ctx.modified = 1;
}
fclose(ctx.out);
@@ -598,30 +687,28 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip,
/* Backup the original file and replace it with the temporary */
if (unlink(back) == -1 && errno != ENOENT) {
oerrno = errno;
- error("%s: unlink %.100s: %s", __func__,
- back, strerror(errno));
+ error_f("unlink %.100s: %s", back, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if (link(filename, back) == -1) {
oerrno = errno;
- error("%s: link %.100s to %.100s: %s", __func__,
- filename, back, strerror(errno));
+ error_f("link %.100s to %.100s: %s", filename,
+ back, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if (rename(temp, filename) == -1) {
oerrno = errno;
- error("%s: rename \"%s\" to \"%s\": %s", __func__,
- temp, filename, strerror(errno));
+ error_f("rename \"%s\" to \"%s\": %s", temp,
+ filename, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
} else {
/* No changes made; just delete the temporary file */
if (unlink(temp) != 0)
- error("%s: unlink \"%s\": %s", __func__,
- temp, strerror(errno));
+ error_f("unlink \"%s\": %s", temp, strerror(errno));
}
/* success */
@@ -633,7 +720,7 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip,
free(back);
if (ctx.out != NULL)
fclose(ctx.out);
- free(ctx.skip_keys);
+ free(ctx.match_keys);
umask(omask);
if (r == SSH_ERR_SYSTEM_ERROR)
errno = oerrno;
@@ -659,10 +746,9 @@ match_maybe_hashed(const char *host, const char *names, int *was_hashed)
}
int
-hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
- const char *host, const char *ip, u_int options)
+hostkeys_foreach_file(const char *path, FILE *f, hostkeys_foreach_fn *callback,
+ void *ctx, const char *host, const char *ip, u_int options, u_int note)
{
- FILE *f;
char *line = NULL, ktype[128];
u_long linenum = 0;
char *cp, *cp2;
@@ -675,10 +761,7 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
memset(&lineinfo, 0, sizeof(lineinfo));
if (host == NULL && (options & HKF_WANT_MATCH) != 0)
return SSH_ERR_INVALID_ARGUMENT;
- if ((f = fopen(path, "r")) == NULL)
- return SSH_ERR_SYSTEM_ERROR;
- debug3("%s: reading file \"%s\"", __func__, path);
while (getline(&line, &linesize, f) != -1) {
linenum++;
line[strcspn(line, "\n")] = '\0';
@@ -692,6 +775,7 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
lineinfo.marker = MRK_NONE;
lineinfo.status = HKF_STATUS_OK;
lineinfo.keytype = KEY_UNSPEC;
+ lineinfo.note = note;
/* Skip any leading whitespace, comments and empty lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
@@ -706,8 +790,7 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
}
if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) {
- verbose("%s: invalid marker at %s:%lu",
- __func__, path, linenum);
+ verbose_f("invalid marker at %s:%lu", path, linenum);
if ((options & HKF_WANT_MATCH) == 0)
goto bad;
continue;
@@ -723,8 +806,8 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
if (host != NULL) {
if ((s = match_maybe_hashed(host, lineinfo.hosts,
&hashed)) == -1) {
- debug2("%s: %s:%ld: bad host hash \"%.32s\"",
- __func__, path, linenum, lineinfo.hosts);
+ debug2_f("%s:%ld: bad host hash \"%.32s\"",
+ path, linenum, lineinfo.hosts);
goto bad;
}
if (s == 1) {
@@ -736,9 +819,9 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
if (ip != NULL) {
if ((s = match_maybe_hashed(ip, lineinfo.hosts,
&hashed)) == -1) {
- debug2("%s: %s:%ld: bad ip hash "
- "\"%.32s\"", __func__, path,
- linenum, lineinfo.hosts);
+ debug2_f("%s:%ld: bad ip hash "
+ "\"%.32s\"", path, linenum,
+ lineinfo.hosts);
goto bad;
}
if (s == 1) {
@@ -773,7 +856,7 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
* lines.
*/
if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) {
- error("%s: sshkey_new failed", __func__);
+ error_f("sshkey_new failed");
r = SSH_ERR_ALLOC_FAIL;
break;
}
@@ -829,6 +912,24 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
sshkey_free(lineinfo.key);
free(lineinfo.line);
free(line);
+ return r;
+}
+
+int
+hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
+ const char *host, const char *ip, u_int options, u_int note)
+{
+ FILE *f;
+ int r, oerrno;
+
+ if ((f = fopen(path, "r")) == NULL)
+ return SSH_ERR_SYSTEM_ERROR;
+
+ debug3_f("reading file \"%s\"", path);
+ r = hostkeys_foreach_file(path, f, callback, ctx, host, ip,
+ options, note);
+ oerrno = errno;
fclose(f);
+ errno = oerrno;
return r;
}