diff options
-rw-r--r-- | usr.bin/ssh/hostfile.c | 44 | ||||
-rw-r--r-- | usr.bin/ssh/hostfile.h | 6 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect.c | 73 |
3 files changed, 109 insertions, 14 deletions
diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c index cefff8d6276..dcee0344833 100644 --- a/usr.bin/ssh/hostfile.c +++ b/usr.bin/ssh/hostfile.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: hostfile.c,v 1.29 2001/12/18 10:04:21 jakob Exp $"); +RCSID("$OpenBSD: hostfile.c,v 1.30 2002/07/24 16:11:18 markus Exp $"); #include "packet.h" #include "match.h" @@ -91,11 +91,14 @@ hostfile_check_key(int bits, Key *key, const char *host, const char *filename, i * in the list of our known hosts. Returns HOST_OK if the host is known and * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED * if the host is known but used to have a different host key. + * + * If no 'key' has been specified and a key of type 'keytype' is known + * for the specified host, then HOST_FOUND is returned. */ -HostStatus -check_host_in_hostfile(const char *filename, const char *host, Key *key, - Key *found, int *numret) +static HostStatus +check_host_in_hostfile_by_key_or_type(const char *filename, + const char *host, Key *key, int keytype, Key *found, int *numret) { FILE *f; char line[8192]; @@ -105,8 +108,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, HostStatus end_return; debug3("check_host_in_hostfile: filename %s", filename); - if (key == NULL) - fatal("no key to look up"); + /* Open the file containing the list of known hosts. */ f = fopen(filename, "r"); if (!f) @@ -147,12 +149,20 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, */ if (!hostfile_read_key(&cp, &kbits, found)) continue; - if (!hostfile_check_key(kbits, found, host, filename, linenum)) - continue; if (numret != NULL) *numret = linenum; + if (key == NULL) { + /* we found a key of the requested type */ + if (found->type == keytype) + return HOST_FOUND; + continue; + } + + if (!hostfile_check_key(kbits, found, host, filename, linenum)) + continue; + /* Check if the current key is the same as the given key. */ if (key_equal(key, found)) { /* Ok, they match. */ @@ -177,6 +187,24 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, return end_return; } +HostStatus +check_host_in_hostfile(const char *filename, const char *host, Key *key, + Key *found, int *numret) +{ + if (key == NULL) + fatal("no key to look up"); + return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, + found, numret)); +} + +int +lookup_key_in_hostfile_by_type(const char *filename, const char *host, + int keytype, Key *found, int *numret) +{ + return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, + keytype, found, numret) == HOST_FOUND); +} + /* * Appends an entry to the host file. Returns false if the entry could not * be appended. diff --git a/usr.bin/ssh/hostfile.h b/usr.bin/ssh/hostfile.h index 0244fdb53ea..06373242147 100644 --- a/usr.bin/ssh/hostfile.h +++ b/usr.bin/ssh/hostfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.h,v 1.10 2001/12/18 10:04:21 jakob Exp $ */ +/* $OpenBSD: hostfile.h,v 1.11 2002/07/24 16:11:18 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -15,12 +15,14 @@ #define HOSTFILE_H typedef enum { - HOST_OK, HOST_NEW, HOST_CHANGED + HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND, } HostStatus; int hostfile_read_key(char **, u_int *, Key *); HostStatus check_host_in_hostfile(const char *, const char *, Key *, Key *, int *); int add_host_to_hostfile(const char *, const char *, Key *); +int +lookup_key_in_hostfile_by_type(const char *, const char *, int , Key *, int *); #endif diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c index e642fa21b67..d042fbf59b5 100644 --- a/usr.bin/ssh/sshconnect.c +++ b/usr.bin/ssh/sshconnect.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.131 2002/07/12 13:29:09 itojun Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.132 2002/07/24 16:11:18 markus Exp $"); #include <openssl/bn.h> @@ -42,6 +42,8 @@ extern char *__progname; extern uid_t original_real_uid; extern uid_t original_effective_uid; +static int show_other_keys(const char *, Key *); + /* * Connect to the given ssh server using a proxy command. */ @@ -489,7 +491,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, int local = 0, host_ip_differ = 0; char ntop[NI_MAXHOST]; char msg[1024]; - int len, host_line, ip_line; + int len, host_line, ip_line, has_keys; const char *host_file = NULL, *ip_file = NULL; /* @@ -630,14 +632,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, "have requested strict checking.", type, host); goto fail; } else if (options.strict_host_key_checking == 2) { + has_keys = show_other_keys(host, host_key); /* The default */ fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); snprintf(msg, sizeof(msg), "The authenticity of host '%.200s (%s)' can't be " - "established.\n" + "established%s\n" "%s key fingerprint is %s.\n" "Are you sure you want to continue connecting " - "(yes/no)? ", host, ip, type, fp); + "(yes/no)? ", + host, ip, + has_keys ? ",\nbut keys of different type are already " + "known for this host." : ".", + type, fp); xfree(fp); if (!confirm(msg)) goto fail; @@ -740,6 +747,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, * accept the authentication. */ break; + case HOST_FOUND: + fatal("internal error"); + break; } if (options.check_host_ip && host_status != HOST_CHANGED && @@ -851,3 +861,58 @@ ssh_put_password(char *password) memset(padded, 0, size); xfree(padded); } + +static int +show_key_from_file(const char *file, const char *host, int keytype) +{ + Key *found; + char *fp; + int line, ret; + + found = key_new(keytype); + if ((ret = lookup_key_in_hostfile_by_type(file, host, + keytype, found, &line))) { + fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); + log("WARNING: %s key found for host %s\n" + "in file %s line %d with\n" + "%s key fingerprint %s.", + key_type(found), host, file, line, + key_type(found), fp); + xfree(fp); + } + key_free(found); + return (ret); +} + +/* print all known host keys for a given host, but skip keys of given type */ +static int +show_other_keys(const char *host, Key *key) +{ + int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; + int i, found = 0; + + for (i = 0; type[i] != -1; i++) { + if (type[i] == key->type) + continue; + if (type[i] != KEY_RSA1 && + show_key_from_file(options.user_hostfile2, host, type[i])) { + found = 1; + continue; + } + if (type[i] != KEY_RSA1 && + show_key_from_file(options.system_hostfile2, host, type[i])) { + found = 1; + continue; + } + if (show_key_from_file(options.user_hostfile, host, type[i])) { + found = 1; + continue; + } + if (show_key_from_file(options.system_hostfile, host, type[i])) { + found = 1; + continue; + } + debug2("no key of type %d for host %s", type[i], host); + } + return (found); +} |