diff options
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | hostfile.c | 44 | ||||
-rw-r--r-- | hostfile.h | 6 | ||||
-rw-r--r-- | sshconnect.c | 73 |
4 files changed, 124 insertions, 15 deletions
@@ -1,3 +1,17 @@ | |||
1 | 20020731 | ||
2 | - (bal) OpenBSD CVS Sync | ||
3 | - markus@cvs.openbsd.org 2002/07/24 16:11:18 | ||
4 | [hostfile.c hostfile.h sshconnect.c] | ||
5 | print out all known keys for a host if we get a unknown host key, | ||
6 | see discussion at http://marc.theaimsgroup.com/?t=101069210100016&r=1&w=4 | ||
7 | |||
8 | the ssharp mitm tool attacks users in a similar way, so i'd like to | ||
9 | pointed out again: | ||
10 | A MITM attack is always possible if the ssh client prints: | ||
11 | The authenticity of host 'bla' can't be established. | ||
12 | (protocol version 2 with pubkey authentication allows you to detect | ||
13 | MITM attacks) | ||
14 | |||
1 | 20020730 | 15 | 20020730 |
2 | - (bal) [uidswap.c] SCO compile correction by gert@greenie.muc.de | 16 | - (bal) [uidswap.c] SCO compile correction by gert@greenie.muc.de |
3 | 17 | ||
@@ -1465,4 +1479,4 @@ | |||
1465 | - (stevesk) entropy.c: typo in debug message | 1479 | - (stevesk) entropy.c: typo in debug message |
1466 | - (djm) ssh-keygen -i needs seeded RNG; report from markus@ | 1480 | - (djm) ssh-keygen -i needs seeded RNG; report from markus@ |
1467 | 1481 | ||
1468 | $Id: ChangeLog,v 1.2409 2002/07/30 19:32:07 mouring Exp $ | 1482 | $Id: ChangeLog,v 1.2410 2002/08/01 01:21:56 mouring Exp $ |
diff --git a/hostfile.c b/hostfile.c index cefff8d62..dcee03448 100644 --- a/hostfile.c +++ b/hostfile.c | |||
@@ -36,7 +36,7 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include "includes.h" | 38 | #include "includes.h" |
39 | RCSID("$OpenBSD: hostfile.c,v 1.29 2001/12/18 10:04:21 jakob Exp $"); | 39 | RCSID("$OpenBSD: hostfile.c,v 1.30 2002/07/24 16:11:18 markus Exp $"); |
40 | 40 | ||
41 | #include "packet.h" | 41 | #include "packet.h" |
42 | #include "match.h" | 42 | #include "match.h" |
@@ -91,11 +91,14 @@ hostfile_check_key(int bits, Key *key, const char *host, const char *filename, i | |||
91 | * in the list of our known hosts. Returns HOST_OK if the host is known and | 91 | * in the list of our known hosts. Returns HOST_OK if the host is known and |
92 | * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED | 92 | * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED |
93 | * if the host is known but used to have a different host key. | 93 | * if the host is known but used to have a different host key. |
94 | * | ||
95 | * If no 'key' has been specified and a key of type 'keytype' is known | ||
96 | * for the specified host, then HOST_FOUND is returned. | ||
94 | */ | 97 | */ |
95 | 98 | ||
96 | HostStatus | 99 | static HostStatus |
97 | check_host_in_hostfile(const char *filename, const char *host, Key *key, | 100 | check_host_in_hostfile_by_key_or_type(const char *filename, |
98 | Key *found, int *numret) | 101 | const char *host, Key *key, int keytype, Key *found, int *numret) |
99 | { | 102 | { |
100 | FILE *f; | 103 | FILE *f; |
101 | char line[8192]; | 104 | char line[8192]; |
@@ -105,8 +108,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, | |||
105 | HostStatus end_return; | 108 | HostStatus end_return; |
106 | 109 | ||
107 | debug3("check_host_in_hostfile: filename %s", filename); | 110 | debug3("check_host_in_hostfile: filename %s", filename); |
108 | if (key == NULL) | 111 | |
109 | fatal("no key to look up"); | ||
110 | /* Open the file containing the list of known hosts. */ | 112 | /* Open the file containing the list of known hosts. */ |
111 | f = fopen(filename, "r"); | 113 | f = fopen(filename, "r"); |
112 | if (!f) | 114 | if (!f) |
@@ -147,12 +149,20 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, | |||
147 | */ | 149 | */ |
148 | if (!hostfile_read_key(&cp, &kbits, found)) | 150 | if (!hostfile_read_key(&cp, &kbits, found)) |
149 | continue; | 151 | continue; |
150 | if (!hostfile_check_key(kbits, found, host, filename, linenum)) | ||
151 | continue; | ||
152 | 152 | ||
153 | if (numret != NULL) | 153 | if (numret != NULL) |
154 | *numret = linenum; | 154 | *numret = linenum; |
155 | 155 | ||
156 | if (key == NULL) { | ||
157 | /* we found a key of the requested type */ | ||
158 | if (found->type == keytype) | ||
159 | return HOST_FOUND; | ||
160 | continue; | ||
161 | } | ||
162 | |||
163 | if (!hostfile_check_key(kbits, found, host, filename, linenum)) | ||
164 | continue; | ||
165 | |||
156 | /* Check if the current key is the same as the given key. */ | 166 | /* Check if the current key is the same as the given key. */ |
157 | if (key_equal(key, found)) { | 167 | if (key_equal(key, found)) { |
158 | /* Ok, they match. */ | 168 | /* Ok, they match. */ |
@@ -177,6 +187,24 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, | |||
177 | return end_return; | 187 | return end_return; |
178 | } | 188 | } |
179 | 189 | ||
190 | HostStatus | ||
191 | check_host_in_hostfile(const char *filename, const char *host, Key *key, | ||
192 | Key *found, int *numret) | ||
193 | { | ||
194 | if (key == NULL) | ||
195 | fatal("no key to look up"); | ||
196 | return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, | ||
197 | found, numret)); | ||
198 | } | ||
199 | |||
200 | int | ||
201 | lookup_key_in_hostfile_by_type(const char *filename, const char *host, | ||
202 | int keytype, Key *found, int *numret) | ||
203 | { | ||
204 | return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, | ||
205 | keytype, found, numret) == HOST_FOUND); | ||
206 | } | ||
207 | |||
180 | /* | 208 | /* |
181 | * Appends an entry to the host file. Returns false if the entry could not | 209 | * Appends an entry to the host file. Returns false if the entry could not |
182 | * be appended. | 210 | * be appended. |
diff --git a/hostfile.h b/hostfile.h index 0244fdb53..063732421 100644 --- a/hostfile.h +++ b/hostfile.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: hostfile.h,v 1.10 2001/12/18 10:04:21 jakob Exp $ */ | 1 | /* $OpenBSD: hostfile.h,v 1.11 2002/07/24 16:11:18 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -15,12 +15,14 @@ | |||
15 | #define HOSTFILE_H | 15 | #define HOSTFILE_H |
16 | 16 | ||
17 | typedef enum { | 17 | typedef enum { |
18 | HOST_OK, HOST_NEW, HOST_CHANGED | 18 | HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND, |
19 | } HostStatus; | 19 | } HostStatus; |
20 | 20 | ||
21 | int hostfile_read_key(char **, u_int *, Key *); | 21 | int hostfile_read_key(char **, u_int *, Key *); |
22 | HostStatus | 22 | HostStatus |
23 | check_host_in_hostfile(const char *, const char *, Key *, Key *, int *); | 23 | check_host_in_hostfile(const char *, const char *, Key *, Key *, int *); |
24 | int add_host_to_hostfile(const char *, const char *, Key *); | 24 | int add_host_to_hostfile(const char *, const char *, Key *); |
25 | int | ||
26 | lookup_key_in_hostfile_by_type(const char *, const char *, int , Key *, int *); | ||
25 | 27 | ||
26 | #endif | 28 | #endif |
diff --git a/sshconnect.c b/sshconnect.c index 9f8458dc7..8599684e5 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include "includes.h" | 15 | #include "includes.h" |
16 | RCSID("$OpenBSD: sshconnect.c,v 1.131 2002/07/12 13:29:09 itojun Exp $"); | 16 | RCSID("$OpenBSD: sshconnect.c,v 1.132 2002/07/24 16:11:18 markus Exp $"); |
17 | 17 | ||
18 | #include <openssl/bn.h> | 18 | #include <openssl/bn.h> |
19 | 19 | ||
@@ -46,6 +46,8 @@ extern uid_t original_effective_uid; | |||
46 | #define INET6_ADDRSTRLEN 46 | 46 | #define INET6_ADDRSTRLEN 46 |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | static int show_other_keys(const char *, Key *); | ||
50 | |||
49 | /* | 51 | /* |
50 | * Connect to the given ssh server using a proxy command. | 52 | * Connect to the given ssh server using a proxy command. |
51 | */ | 53 | */ |
@@ -494,7 +496,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
494 | int salen; | 496 | int salen; |
495 | char ntop[NI_MAXHOST]; | 497 | char ntop[NI_MAXHOST]; |
496 | char msg[1024]; | 498 | char msg[1024]; |
497 | int len, host_line, ip_line; | 499 | int len, host_line, ip_line, has_keys; |
498 | const char *host_file = NULL, *ip_file = NULL; | 500 | const char *host_file = NULL, *ip_file = NULL; |
499 | 501 | ||
500 | /* | 502 | /* |
@@ -638,14 +640,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
638 | "have requested strict checking.", type, host); | 640 | "have requested strict checking.", type, host); |
639 | goto fail; | 641 | goto fail; |
640 | } else if (options.strict_host_key_checking == 2) { | 642 | } else if (options.strict_host_key_checking == 2) { |
643 | has_keys = show_other_keys(host, host_key); | ||
641 | /* The default */ | 644 | /* The default */ |
642 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 645 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
643 | snprintf(msg, sizeof(msg), | 646 | snprintf(msg, sizeof(msg), |
644 | "The authenticity of host '%.200s (%s)' can't be " | 647 | "The authenticity of host '%.200s (%s)' can't be " |
645 | "established.\n" | 648 | "established%s\n" |
646 | "%s key fingerprint is %s.\n" | 649 | "%s key fingerprint is %s.\n" |
647 | "Are you sure you want to continue connecting " | 650 | "Are you sure you want to continue connecting " |
648 | "(yes/no)? ", host, ip, type, fp); | 651 | "(yes/no)? ", |
652 | host, ip, | ||
653 | has_keys ? ",\nbut keys of different type are already " | ||
654 | "known for this host." : ".", | ||
655 | type, fp); | ||
649 | xfree(fp); | 656 | xfree(fp); |
650 | if (!confirm(msg)) | 657 | if (!confirm(msg)) |
651 | goto fail; | 658 | goto fail; |
@@ -748,6 +755,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
748 | * accept the authentication. | 755 | * accept the authentication. |
749 | */ | 756 | */ |
750 | break; | 757 | break; |
758 | case HOST_FOUND: | ||
759 | fatal("internal error"); | ||
760 | break; | ||
751 | } | 761 | } |
752 | 762 | ||
753 | if (options.check_host_ip && host_status != HOST_CHANGED && | 763 | if (options.check_host_ip && host_status != HOST_CHANGED && |
@@ -859,3 +869,58 @@ ssh_put_password(char *password) | |||
859 | memset(padded, 0, size); | 869 | memset(padded, 0, size); |
860 | xfree(padded); | 870 | xfree(padded); |
861 | } | 871 | } |
872 | |||
873 | static int | ||
874 | show_key_from_file(const char *file, const char *host, int keytype) | ||
875 | { | ||
876 | Key *found; | ||
877 | char *fp; | ||
878 | int line, ret; | ||
879 | |||
880 | found = key_new(keytype); | ||
881 | if ((ret = lookup_key_in_hostfile_by_type(file, host, | ||
882 | keytype, found, &line))) { | ||
883 | fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); | ||
884 | log("WARNING: %s key found for host %s\n" | ||
885 | "in file %s line %d with\n" | ||
886 | "%s key fingerprint %s.", | ||
887 | key_type(found), host, file, line, | ||
888 | key_type(found), fp); | ||
889 | xfree(fp); | ||
890 | } | ||
891 | key_free(found); | ||
892 | return (ret); | ||
893 | } | ||
894 | |||
895 | /* print all known host keys for a given host, but skip keys of given type */ | ||
896 | static int | ||
897 | show_other_keys(const char *host, Key *key) | ||
898 | { | ||
899 | int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; | ||
900 | int i, found = 0; | ||
901 | |||
902 | for (i = 0; type[i] != -1; i++) { | ||
903 | if (type[i] == key->type) | ||
904 | continue; | ||
905 | if (type[i] != KEY_RSA1 && | ||
906 | show_key_from_file(options.user_hostfile2, host, type[i])) { | ||
907 | found = 1; | ||
908 | continue; | ||
909 | } | ||
910 | if (type[i] != KEY_RSA1 && | ||
911 | show_key_from_file(options.system_hostfile2, host, type[i])) { | ||
912 | found = 1; | ||
913 | continue; | ||
914 | } | ||
915 | if (show_key_from_file(options.user_hostfile, host, type[i])) { | ||
916 | found = 1; | ||
917 | continue; | ||
918 | } | ||
919 | if (show_key_from_file(options.system_hostfile, host, type[i])) { | ||
920 | found = 1; | ||
921 | continue; | ||
922 | } | ||
923 | debug2("no key of type %d for host %s", type[i], host); | ||
924 | } | ||
925 | return (found); | ||
926 | } | ||