diff options
author | Colin Watson <cjwatson@debian.org> | 2003-09-01 02:05:26 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2003-09-01 02:05:26 +0000 |
commit | 6d5a72bc1d98a42ba42f082e50a22e911c1d82d3 (patch) | |
tree | 1bf23174bdb6fc71e2846dda0eca195a418484e7 /sshconnect.c | |
parent | 2ee26b431f98cf1dc0e4fb9809ad1e0c879b8c08 (diff) | |
parent | 58657d96514cd6f16d82add8d6f4adbb36765758 (diff) |
Debian release 3.5p1-1.
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 120 |
1 files changed, 88 insertions, 32 deletions
diff --git a/sshconnect.c b/sshconnect.c index 8eb5fda7d..95e0f6d77 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,6 +41,7 @@ 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 |
@@ -48,22 +49,13 @@ extern uid_t original_effective_uid; | |||
48 | 49 | ||
49 | static sig_atomic_t banner_timedout; | 50 | static sig_atomic_t banner_timedout; |
50 | 51 | ||
51 | static const char * | ||
52 | sockaddr_ntop(struct sockaddr *sa, socklen_t salen) | ||
53 | { | ||
54 | static char addrbuf[NI_MAXHOST]; | ||
55 | |||
56 | if (getnameinfo(sa, salen, addrbuf, sizeof(addrbuf), NULL, 0, | ||
57 | NI_NUMERICHOST) != 0) | ||
58 | fatal("sockaddr_ntop: getnameinfo NI_NUMERICHOST failed"); | ||
59 | return addrbuf; | ||
60 | } | ||
61 | |||
62 | static void banner_alarm_catch (int signum) | 52 | static void banner_alarm_catch (int signum) |
63 | { | 53 | { |
64 | banner_timedout = 1; | 54 | banner_timedout = 1; |
65 | } | 55 | } |
66 | 56 | ||
57 | static int show_other_keys(const char *, Key *); | ||
58 | |||
67 | /* | 59 | /* |
68 | * Connect to the given ssh server using a proxy command. | 60 | * Connect to the given ssh server using a proxy command. |
69 | */ | 61 | */ |
@@ -80,9 +72,16 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
80 | /* Convert the port number into a string. */ | 72 | /* Convert the port number into a string. */ |
81 | snprintf(strport, sizeof strport, "%hu", port); | 73 | snprintf(strport, sizeof strport, "%hu", port); |
82 | 74 | ||
83 | /* Build the final command string in the buffer by making the | 75 | /* |
84 | appropriate substitutions to the given proxy command. */ | 76 | * Build the final command string in the buffer by making the |
77 | * appropriate substitutions to the given proxy command. | ||
78 | * | ||
79 | * Use "exec" to avoid "sh -c" processes on some platforms | ||
80 | * (e.g. Solaris) | ||
81 | */ | ||
85 | buffer_init(&command); | 82 | buffer_init(&command); |
83 | buffer_append(&command, "exec ", 5); | ||
84 | |||
86 | for (cp = proxy_command; *cp; cp++) { | 85 | for (cp = proxy_command; *cp; cp++) { |
87 | if (cp[0] == '%' && cp[1] == '%') { | 86 | if (cp[0] == '%' && cp[1] == '%') { |
88 | buffer_append(&command, "%", 1); | 87 | buffer_append(&command, "%", 1); |
@@ -150,6 +149,8 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
150 | /* Parent. */ | 149 | /* Parent. */ |
151 | if (pid < 0) | 150 | if (pid < 0) |
152 | fatal("fork failed: %.100s", strerror(errno)); | 151 | fatal("fork failed: %.100s", strerror(errno)); |
152 | else | ||
153 | proxy_command_pid = pid; /* save pid to clean up later */ | ||
153 | 154 | ||
154 | /* Close child side of the descriptors. */ | 155 | /* Close child side of the descriptors. */ |
155 | close(pin[0]); | 156 | close(pin[0]); |
@@ -245,7 +246,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
245 | int sock = -1, attempt; | 246 | int sock = -1, attempt; |
246 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 247 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
247 | struct addrinfo hints, *ai, *aitop; | 248 | struct addrinfo hints, *ai, *aitop; |
248 | struct linger linger; | ||
249 | struct servent *sp; | 249 | struct servent *sp; |
250 | /* | 250 | /* |
251 | * Did we get only other errors than "Connection refused" (which | 251 | * Did we get only other errors than "Connection refused" (which |
@@ -314,9 +314,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
314 | } else { | 314 | } else { |
315 | if (errno == ECONNREFUSED) | 315 | if (errno == ECONNREFUSED) |
316 | full_failure = 0; | 316 | full_failure = 0; |
317 | log("ssh: connect to address %s port %s: %s", | 317 | debug("connect to address %s port %s: %s", |
318 | sockaddr_ntop(ai->ai_addr, ai->ai_addrlen), | 318 | ntop, strport, strerror(errno)); |
319 | strport, strerror(errno)); | ||
320 | /* | 319 | /* |
321 | * Close the failed socket; there appear to | 320 | * Close the failed socket; there appear to |
322 | * be some problems when reusing a socket for | 321 | * be some problems when reusing a socket for |
@@ -339,20 +338,14 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
339 | freeaddrinfo(aitop); | 338 | freeaddrinfo(aitop); |
340 | 339 | ||
341 | /* Return failure if we didn't get a successful connection. */ | 340 | /* Return failure if we didn't get a successful connection. */ |
342 | if (attempt >= connection_attempts) | 341 | if (attempt >= connection_attempts) { |
342 | log("ssh: connect to host %s port %s: %s", | ||
343 | host, strport, strerror(errno)); | ||
343 | return full_failure ? ECONNABORTED : ECONNREFUSED; | 344 | return full_failure ? ECONNABORTED : ECONNREFUSED; |
345 | } | ||
344 | 346 | ||
345 | debug("Connection established."); | 347 | debug("Connection established."); |
346 | 348 | ||
347 | /* | ||
348 | * Set socket options. We would like the socket to disappear as soon | ||
349 | * as it has been closed for whatever reason. | ||
350 | */ | ||
351 | /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ | ||
352 | linger.l_onoff = 1; | ||
353 | linger.l_linger = 5; | ||
354 | setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); | ||
355 | |||
356 | /* Set keepalives if requested. */ | 349 | /* Set keepalives if requested. */ |
357 | if (options.keepalives && | 350 | if (options.keepalives && |
358 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, | 351 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, |
@@ -508,7 +501,7 @@ confirm(const char *prompt) | |||
508 | (p[0] == '\0') || (p[0] == '\n') || | 501 | (p[0] == '\0') || (p[0] == '\n') || |
509 | strncasecmp(p, "no", 2) == 0) | 502 | strncasecmp(p, "no", 2) == 0) |
510 | ret = 0; | 503 | ret = 0; |
511 | if (strncasecmp(p, "yes", 3) == 0) | 504 | if (p && strncasecmp(p, "yes", 3) == 0) |
512 | ret = 1; | 505 | ret = 1; |
513 | if (p) | 506 | if (p) |
514 | xfree(p); | 507 | xfree(p); |
@@ -535,7 +528,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
535 | int salen; | 528 | int salen; |
536 | char ntop[NI_MAXHOST]; | 529 | char ntop[NI_MAXHOST]; |
537 | char msg[1024]; | 530 | char msg[1024]; |
538 | int len, host_line, ip_line; | 531 | int len, host_line, ip_line, has_keys; |
539 | const char *host_file = NULL, *ip_file = NULL; | 532 | const char *host_file = NULL, *ip_file = NULL; |
540 | 533 | ||
541 | /* | 534 | /* |
@@ -679,14 +672,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
679 | "have requested strict checking.", type, host); | 672 | "have requested strict checking.", type, host); |
680 | goto fail; | 673 | goto fail; |
681 | } else if (options.strict_host_key_checking == 2) { | 674 | } else if (options.strict_host_key_checking == 2) { |
675 | has_keys = show_other_keys(host, host_key); | ||
682 | /* The default */ | 676 | /* The default */ |
683 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 677 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
684 | snprintf(msg, sizeof(msg), | 678 | snprintf(msg, sizeof(msg), |
685 | "The authenticity of host '%.200s (%s)' can't be " | 679 | "The authenticity of host '%.200s (%s)' can't be " |
686 | "established.\n" | 680 | "established%s\n" |
687 | "%s key fingerprint is %s.\n" | 681 | "%s key fingerprint is %s.\n" |
688 | "Are you sure you want to continue connecting " | 682 | "Are you sure you want to continue connecting " |
689 | "(yes/no)? ", host, ip, type, fp); | 683 | "(yes/no)? ", |
684 | host, ip, | ||
685 | has_keys ? ",\nbut keys of different type are already " | ||
686 | "known for this host." : ".", | ||
687 | type, fp); | ||
690 | xfree(fp); | 688 | xfree(fp); |
691 | if (!confirm(msg)) | 689 | if (!confirm(msg)) |
692 | goto fail; | 690 | goto fail; |
@@ -789,6 +787,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
789 | * accept the authentication. | 787 | * accept the authentication. |
790 | */ | 788 | */ |
791 | break; | 789 | break; |
790 | case HOST_FOUND: | ||
791 | fatal("internal error"); | ||
792 | break; | ||
792 | } | 793 | } |
793 | 794 | ||
794 | if (options.check_host_ip && host_status != HOST_CHANGED && | 795 | if (options.check_host_ip && host_status != HOST_CHANGED && |
@@ -900,3 +901,58 @@ ssh_put_password(char *password) | |||
900 | memset(padded, 0, size); | 901 | memset(padded, 0, size); |
901 | xfree(padded); | 902 | xfree(padded); |
902 | } | 903 | } |
904 | |||
905 | static int | ||
906 | show_key_from_file(const char *file, const char *host, int keytype) | ||
907 | { | ||
908 | Key *found; | ||
909 | char *fp; | ||
910 | int line, ret; | ||
911 | |||
912 | found = key_new(keytype); | ||
913 | if ((ret = lookup_key_in_hostfile_by_type(file, host, | ||
914 | keytype, found, &line))) { | ||
915 | fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); | ||
916 | log("WARNING: %s key found for host %s\n" | ||
917 | "in %s:%d\n" | ||
918 | "%s key fingerprint %s.", | ||
919 | key_type(found), host, file, line, | ||
920 | key_type(found), fp); | ||
921 | xfree(fp); | ||
922 | } | ||
923 | key_free(found); | ||
924 | return (ret); | ||
925 | } | ||
926 | |||
927 | /* print all known host keys for a given host, but skip keys of given type */ | ||
928 | static int | ||
929 | show_other_keys(const char *host, Key *key) | ||
930 | { | ||
931 | int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; | ||
932 | int i, found = 0; | ||
933 | |||
934 | for (i = 0; type[i] != -1; i++) { | ||
935 | if (type[i] == key->type) | ||
936 | continue; | ||
937 | if (type[i] != KEY_RSA1 && | ||
938 | show_key_from_file(options.user_hostfile2, host, type[i])) { | ||
939 | found = 1; | ||
940 | continue; | ||
941 | } | ||
942 | if (type[i] != KEY_RSA1 && | ||
943 | show_key_from_file(options.system_hostfile2, host, type[i])) { | ||
944 | found = 1; | ||
945 | continue; | ||
946 | } | ||
947 | if (show_key_from_file(options.user_hostfile, host, type[i])) { | ||
948 | found = 1; | ||
949 | continue; | ||
950 | } | ||
951 | if (show_key_from_file(options.system_hostfile, host, type[i])) { | ||
952 | found = 1; | ||
953 | continue; | ||
954 | } | ||
955 | debug2("no key of type %d for host %s", type[i], host); | ||
956 | } | ||
957 | return (found); | ||
958 | } | ||