diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 118 |
1 files changed, 87 insertions, 31 deletions
diff --git a/sshconnect.c b/sshconnect.c index b89321fb8..776d72065 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.126 2002/06/23 03:30:17 deraadt Exp $"); | 16 | RCSID("$OpenBSD: sshconnect.c,v 1.135 2002/09/19 01:58:18 djm Exp $"); |
17 | 17 | ||
18 | #include <openssl/bn.h> | 18 | #include <openssl/bn.h> |
19 | 19 | ||
@@ -41,21 +41,13 @@ extern Options options; | |||
41 | extern char *__progname; | 41 | extern char *__progname; |
42 | extern uid_t original_real_uid; | 42 | extern uid_t original_real_uid; |
43 | extern uid_t original_effective_uid; | 43 | extern uid_t original_effective_uid; |
44 | extern pid_t proxy_command_pid; | ||
44 | 45 | ||
45 | #ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */ | 46 | #ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */ |
46 | #define INET6_ADDRSTRLEN 46 | 47 | #define INET6_ADDRSTRLEN 46 |
47 | #endif | 48 | #endif |
48 | 49 | ||
49 | static const char * | 50 | static int show_other_keys(const char *, Key *); |
50 | sockaddr_ntop(struct sockaddr *sa, socklen_t salen) | ||
51 | { | ||
52 | static char addrbuf[NI_MAXHOST]; | ||
53 | |||
54 | if (getnameinfo(sa, salen, addrbuf, sizeof(addrbuf), NULL, 0, | ||
55 | NI_NUMERICHOST) != 0) | ||
56 | fatal("sockaddr_ntop: getnameinfo NI_NUMERICHOST failed"); | ||
57 | return addrbuf; | ||
58 | } | ||
59 | 51 | ||
60 | /* | 52 | /* |
61 | * Connect to the given ssh server using a proxy command. | 53 | * Connect to the given ssh server using a proxy command. |
@@ -73,9 +65,16 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
73 | /* Convert the port number into a string. */ | 65 | /* Convert the port number into a string. */ |
74 | snprintf(strport, sizeof strport, "%hu", port); | 66 | snprintf(strport, sizeof strport, "%hu", port); |
75 | 67 | ||
76 | /* Build the final command string in the buffer by making the | 68 | /* |
77 | appropriate substitutions to the given proxy command. */ | 69 | * Build the final command string in the buffer by making the |
70 | * appropriate substitutions to the given proxy command. | ||
71 | * | ||
72 | * Use "exec" to avoid "sh -c" processes on some platforms | ||
73 | * (e.g. Solaris) | ||
74 | */ | ||
78 | buffer_init(&command); | 75 | buffer_init(&command); |
76 | buffer_append(&command, "exec ", 5); | ||
77 | |||
79 | for (cp = proxy_command; *cp; cp++) { | 78 | for (cp = proxy_command; *cp; cp++) { |
80 | if (cp[0] == '%' && cp[1] == '%') { | 79 | if (cp[0] == '%' && cp[1] == '%') { |
81 | buffer_append(&command, "%", 1); | 80 | buffer_append(&command, "%", 1); |
@@ -143,6 +142,8 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
143 | /* Parent. */ | 142 | /* Parent. */ |
144 | if (pid < 0) | 143 | if (pid < 0) |
145 | fatal("fork failed: %.100s", strerror(errno)); | 144 | fatal("fork failed: %.100s", strerror(errno)); |
145 | else | ||
146 | proxy_command_pid = pid; /* save pid to clean up later */ | ||
146 | 147 | ||
147 | /* Close child side of the descriptors. */ | 148 | /* Close child side of the descriptors. */ |
148 | close(pin[0]); | 149 | close(pin[0]); |
@@ -238,7 +239,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
238 | int sock = -1, attempt; | 239 | int sock = -1, attempt; |
239 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 240 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
240 | struct addrinfo hints, *ai, *aitop; | 241 | struct addrinfo hints, *ai, *aitop; |
241 | struct linger linger; | ||
242 | struct servent *sp; | 242 | struct servent *sp; |
243 | /* | 243 | /* |
244 | * Did we get only other errors than "Connection refused" (which | 244 | * Did we get only other errors than "Connection refused" (which |
@@ -307,9 +307,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
307 | } else { | 307 | } else { |
308 | if (errno == ECONNREFUSED) | 308 | if (errno == ECONNREFUSED) |
309 | full_failure = 0; | 309 | full_failure = 0; |
310 | log("ssh: connect to address %s port %s: %s", | 310 | debug("connect to address %s port %s: %s", |
311 | sockaddr_ntop(ai->ai_addr, ai->ai_addrlen), | 311 | ntop, strport, strerror(errno)); |
312 | strport, strerror(errno)); | ||
313 | /* | 312 | /* |
314 | * Close the failed socket; there appear to | 313 | * Close the failed socket; there appear to |
315 | * be some problems when reusing a socket for | 314 | * be some problems when reusing a socket for |
@@ -332,20 +331,14 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
332 | freeaddrinfo(aitop); | 331 | freeaddrinfo(aitop); |
333 | 332 | ||
334 | /* Return failure if we didn't get a successful connection. */ | 333 | /* Return failure if we didn't get a successful connection. */ |
335 | if (attempt >= connection_attempts) | 334 | if (attempt >= connection_attempts) { |
335 | log("ssh: connect to host %s port %s: %s", | ||
336 | host, strport, strerror(errno)); | ||
336 | return full_failure ? ECONNABORTED : ECONNREFUSED; | 337 | return full_failure ? ECONNABORTED : ECONNREFUSED; |
338 | } | ||
337 | 339 | ||
338 | debug("Connection established."); | 340 | debug("Connection established."); |
339 | 341 | ||
340 | /* | ||
341 | * Set socket options. We would like the socket to disappear as soon | ||
342 | * as it has been closed for whatever reason. | ||
343 | */ | ||
344 | /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ | ||
345 | linger.l_onoff = 1; | ||
346 | linger.l_linger = 5; | ||
347 | setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); | ||
348 | |||
349 | /* Set keepalives if requested. */ | 342 | /* Set keepalives if requested. */ |
350 | if (options.keepalives && | 343 | if (options.keepalives && |
351 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, | 344 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, |
@@ -476,7 +469,7 @@ confirm(const char *prompt) | |||
476 | (p[0] == '\0') || (p[0] == '\n') || | 469 | (p[0] == '\0') || (p[0] == '\n') || |
477 | strncasecmp(p, "no", 2) == 0) | 470 | strncasecmp(p, "no", 2) == 0) |
478 | ret = 0; | 471 | ret = 0; |
479 | if (strncasecmp(p, "yes", 3) == 0) | 472 | if (p && strncasecmp(p, "yes", 3) == 0) |
480 | ret = 1; | 473 | ret = 1; |
481 | if (p) | 474 | if (p) |
482 | xfree(p); | 475 | xfree(p); |
@@ -503,7 +496,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
503 | int salen; | 496 | int salen; |
504 | char ntop[NI_MAXHOST]; | 497 | char ntop[NI_MAXHOST]; |
505 | char msg[1024]; | 498 | char msg[1024]; |
506 | int len, host_line, ip_line; | 499 | int len, host_line, ip_line, has_keys; |
507 | const char *host_file = NULL, *ip_file = NULL; | 500 | const char *host_file = NULL, *ip_file = NULL; |
508 | 501 | ||
509 | /* | 502 | /* |
@@ -647,14 +640,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
647 | "have requested strict checking.", type, host); | 640 | "have requested strict checking.", type, host); |
648 | goto fail; | 641 | goto fail; |
649 | } 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); | ||
650 | /* The default */ | 644 | /* The default */ |
651 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 645 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
652 | snprintf(msg, sizeof(msg), | 646 | snprintf(msg, sizeof(msg), |
653 | "The authenticity of host '%.200s (%s)' can't be " | 647 | "The authenticity of host '%.200s (%s)' can't be " |
654 | "established.\n" | 648 | "established%s\n" |
655 | "%s key fingerprint is %s.\n" | 649 | "%s key fingerprint is %s.\n" |
656 | "Are you sure you want to continue connecting " | 650 | "Are you sure you want to continue connecting " |
657 | "(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); | ||
658 | xfree(fp); | 656 | xfree(fp); |
659 | if (!confirm(msg)) | 657 | if (!confirm(msg)) |
660 | goto fail; | 658 | goto fail; |
@@ -757,6 +755,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
757 | * accept the authentication. | 755 | * accept the authentication. |
758 | */ | 756 | */ |
759 | break; | 757 | break; |
758 | case HOST_FOUND: | ||
759 | fatal("internal error"); | ||
760 | break; | ||
760 | } | 761 | } |
761 | 762 | ||
762 | if (options.check_host_ip && host_status != HOST_CHANGED && | 763 | if (options.check_host_ip && host_status != HOST_CHANGED && |
@@ -868,3 +869,58 @@ ssh_put_password(char *password) | |||
868 | memset(padded, 0, size); | 869 | memset(padded, 0, size); |
869 | xfree(padded); | 870 | xfree(padded); |
870 | } | 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 %s:%d\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 | } | ||