summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c206
1 files changed, 121 insertions, 85 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 3c888e36a..01337fe40 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.200 2006/10/10 10:12:45 markus Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.211 2008/07/01 07:24:22 dtucker Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -74,13 +74,6 @@ extern pid_t proxy_command_pid;
74#define INET6_ADDRSTRLEN 46 74#define INET6_ADDRSTRLEN 46
75#endif 75#endif
76 76
77static sig_atomic_t banner_timedout;
78
79static void banner_alarm_catch (int signum)
80{
81 banner_timedout = 1;
82}
83
84static int show_other_keys(const char *, Key *); 77static int show_other_keys(const char *, Key *);
85static void warn_changed_key(Key *); 78static void warn_changed_key(Key *);
86 79
@@ -93,7 +86,10 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
93 char *command_string, *tmp; 86 char *command_string, *tmp;
94 int pin[2], pout[2]; 87 int pin[2], pout[2];
95 pid_t pid; 88 pid_t pid;
96 char strport[NI_MAXSERV]; 89 char *shell, strport[NI_MAXSERV];
90
91 if ((shell = getenv("SHELL")) == NULL)
92 shell = _PATH_BSHELL;
97 93
98 /* Convert the port number into a string. */ 94 /* Convert the port number into a string. */
99 snprintf(strport, sizeof strport, "%hu", port); 95 snprintf(strport, sizeof strport, "%hu", port);
@@ -139,7 +135,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
139 135
140 /* Stderr is left as it is so that error messages get 136 /* Stderr is left as it is so that error messages get
141 printed on the user's terminal. */ 137 printed on the user's terminal. */
142 argv[0] = _PATH_BSHELL; 138 argv[0] = shell;
143 argv[1] = "-c"; 139 argv[1] = "-c";
144 argv[2] = command_string; 140 argv[2] = command_string;
145 argv[3] = NULL; 141 argv[3] = NULL;
@@ -164,7 +160,9 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
164 xfree(command_string); 160 xfree(command_string);
165 161
166 /* Set the connection file descriptors. */ 162 /* Set the connection file descriptors. */
167 packet_set_connection(pout[0], pin[1], options.setuptimeout); 163 packet_set_connection(pout[0], pin[1]);
164 packet_set_timeout(options.server_alive_interval,
165 options.server_alive_count_max);
168 166
169 /* Indicate OK return */ 167 /* Indicate OK return */
170 return 0; 168 return 0;
@@ -208,10 +206,10 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
208 hints.ai_socktype = ai->ai_socktype; 206 hints.ai_socktype = ai->ai_socktype;
209 hints.ai_protocol = ai->ai_protocol; 207 hints.ai_protocol = ai->ai_protocol;
210 hints.ai_flags = AI_PASSIVE; 208 hints.ai_flags = AI_PASSIVE;
211 gaierr = getaddrinfo(options.bind_address, "0", &hints, &res); 209 gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
212 if (gaierr) { 210 if (gaierr) {
213 error("getaddrinfo: %s: %s", options.bind_address, 211 error("getaddrinfo: %s: %s", options.bind_address,
214 gai_strerror(gaierr)); 212 ssh_gai_strerror(gaierr));
215 close(sock); 213 close(sock);
216 return -1; 214 return -1;
217 } 215 }
@@ -227,30 +225,36 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
227 225
228static int 226static int
229timeout_connect(int sockfd, const struct sockaddr *serv_addr, 227timeout_connect(int sockfd, const struct sockaddr *serv_addr,
230 socklen_t addrlen, int timeout) 228 socklen_t addrlen, int *timeoutp)
231{ 229{
232 fd_set *fdset; 230 fd_set *fdset;
233 struct timeval tv; 231 struct timeval tv, t_start;
234 socklen_t optlen; 232 socklen_t optlen;
235 int optval, rc, result = -1; 233 int optval, rc, result = -1;
236 234
237 if (timeout <= 0) 235 gettimeofday(&t_start, NULL);
238 return (connect(sockfd, serv_addr, addrlen)); 236
237 if (*timeoutp <= 0) {
238 result = connect(sockfd, serv_addr, addrlen);
239 goto done;
240 }
239 241
240 set_nonblock(sockfd); 242 set_nonblock(sockfd);
241 rc = connect(sockfd, serv_addr, addrlen); 243 rc = connect(sockfd, serv_addr, addrlen);
242 if (rc == 0) { 244 if (rc == 0) {
243 unset_nonblock(sockfd); 245 unset_nonblock(sockfd);
244 return (0); 246 result = 0;
247 goto done;
248 }
249 if (errno != EINPROGRESS) {
250 result = -1;
251 goto done;
245 } 252 }
246 if (errno != EINPROGRESS)
247 return (-1);
248 253
249 fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), 254 fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
250 sizeof(fd_mask)); 255 sizeof(fd_mask));
251 FD_SET(sockfd, fdset); 256 FD_SET(sockfd, fdset);
252 tv.tv_sec = timeout; 257 ms_to_timeval(&tv, *timeoutp);
253 tv.tv_usec = 0;
254 258
255 for (;;) { 259 for (;;) {
256 rc = select(sockfd + 1, NULL, fdset, NULL, &tv); 260 rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
@@ -289,6 +293,16 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
289 } 293 }
290 294
291 xfree(fdset); 295 xfree(fdset);
296
297 done:
298 if (result == 0 && *timeoutp > 0) {
299 ms_subtract_diff(&t_start, timeoutp);
300 if (*timeoutp <= 0) {
301 errno = ETIMEDOUT;
302 result = -1;
303 }
304 }
305
292 return (result); 306 return (result);
293} 307}
294 308
@@ -305,8 +319,8 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
305 */ 319 */
306int 320int
307ssh_connect(const char *host, struct sockaddr_storage * hostaddr, 321ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
308 u_short port, int family, int connection_attempts, 322 u_short port, int family, int connection_attempts, int *timeout_ms,
309 int needpriv, const char *proxy_command) 323 int want_keepalive, int needpriv, const char *proxy_command)
310{ 324{
311 int gaierr; 325 int gaierr;
312 int on = 1; 326 int on = 1;
@@ -327,8 +341,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
327 hints.ai_socktype = SOCK_STREAM; 341 hints.ai_socktype = SOCK_STREAM;
328 snprintf(strport, sizeof strport, "%u", port); 342 snprintf(strport, sizeof strport, "%u", port);
329 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) 343 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
330 fatal("%s: %.100s: %s", __progname, host, 344 fatal("%s: Could not resolve hostname %.100s: %s", __progname,
331 gai_strerror(gaierr)); 345 host, ssh_gai_strerror(gaierr));
332 346
333 for (attempt = 0; attempt < connection_attempts; attempt++) { 347 for (attempt = 0; attempt < connection_attempts; attempt++) {
334 if (attempt > 0) { 348 if (attempt > 0) {
@@ -359,7 +373,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
359 continue; 373 continue;
360 374
361 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 375 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
362 options.connection_timeout) >= 0) { 376 timeout_ms) >= 0) {
363 /* Successful connection. */ 377 /* Successful connection. */
364 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 378 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
365 break; 379 break;
@@ -386,13 +400,15 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
386 debug("Connection established."); 400 debug("Connection established.");
387 401
388 /* Set SO_KEEPALIVE if requested. */ 402 /* Set SO_KEEPALIVE if requested. */
389 if (options.tcp_keep_alive && 403 if (want_keepalive &&
390 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 404 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
391 sizeof(on)) < 0) 405 sizeof(on)) < 0)
392 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 406 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
393 407
394 /* Set the connection. */ 408 /* Set the connection. */
395 packet_set_connection(sock, sock, options.setuptimeout); 409 packet_set_connection(sock, sock);
410 packet_set_timeout(options.server_alive_interval,
411 options.server_alive_count_max);
396 412
397 return 0; 413 return 0;
398} 414}
@@ -402,7 +418,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
402 * identification string. 418 * identification string.
403 */ 419 */
404static void 420static void
405ssh_exchange_identification(void) 421ssh_exchange_identification(int timeout_ms)
406{ 422{
407 char buf[256], remote_version[256]; /* must be same size! */ 423 char buf[256], remote_version[256]; /* must be same size! */
408 int remote_major, remote_minor, mismatch; 424 int remote_major, remote_minor, mismatch;
@@ -410,40 +426,44 @@ ssh_exchange_identification(void)
410 int connection_out = packet_get_connection_out(); 426 int connection_out = packet_get_connection_out();
411 int minor1 = PROTOCOL_MINOR_1; 427 int minor1 = PROTOCOL_MINOR_1;
412 u_int i, n; 428 u_int i, n;
413 struct sigaction sa, osa; 429 size_t len;
430 int fdsetsz, remaining, rc;
431 struct timeval t_start, t_remaining;
432 fd_set *fdset;
433
434 fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
435 fdset = xcalloc(1, fdsetsz);
414 436
415 /* Read other side's version identification.
416 * If SetupTimeOut has been set, give up after the specified amount
417 * of time.
418 */
419 if (options.setuptimeout > 0) {
420 memset(&sa, 0, sizeof(sa));
421 sa.sa_handler = banner_alarm_catch;
422 /* throw away any pending alarms, since we'd block otherwise */
423 alarm(0);
424 sigaction(SIGALRM, &sa, &osa);
425 alarm(options.setuptimeout);
426 }
427 /* Read other side's version identification. */ 437 /* Read other side's version identification. */
438 remaining = timeout_ms;
428 for (n = 0;;) { 439 for (n = 0;;) {
429 for (i = 0; i < sizeof(buf) - 1; ) { 440 for (i = 0; i < sizeof(buf) - 1; i++) {
430 ssize_t len = read(connection_in, &buf[i], 1); 441 if (timeout_ms > 0) {
431 if (banner_timedout) 442 gettimeofday(&t_start, NULL);
432 fatal("ssh_exchange_identification: Timeout waiting for version information."); 443 ms_to_timeval(&t_remaining, remaining);
433 if (len == 0) 444 FD_SET(connection_in, fdset);
434 errno = EPIPE; 445 rc = select(connection_in + 1, fdset, NULL,
446 fdset, &t_remaining);
447 ms_subtract_diff(&t_start, &remaining);
448 if (rc == 0 || remaining <= 0)
449 fatal("Connection timed out during "
450 "banner exchange");
451 if (rc == -1) {
452 if (errno == EINTR)
453 continue;
454 fatal("ssh_exchange_identification: "
455 "select: %s", strerror(errno));
456 }
457 }
458
459 len = atomicio(read, connection_in, &buf[i], 1);
435 460
436 if (len != 1 && errno == EPIPE) 461 if (len != 1 && errno == EPIPE)
437 fatal("ssh_exchange_identification: Connection closed by remote host"); 462 fatal("ssh_exchange_identification: "
438 else if (len != 1) { 463 "Connection closed by remote host");
439#ifdef EWOULDBLOCK 464 else if (len != 1)
440 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) 465 fatal("ssh_exchange_identification: "
441#else 466 "read: %.100s", strerror(errno));
442 if (errno == EINTR || errno == EAGAIN)
443#endif
444 continue;
445 fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
446 }
447 if (buf[i] == '\r') { 467 if (buf[i] == '\r') {
448 buf[i] = '\n'; 468 buf[i] = '\n';
449 buf[i + 1] = 0; 469 buf[i + 1] = 0;
@@ -453,13 +473,9 @@ ssh_exchange_identification(void)
453 buf[i + 1] = 0; 473 buf[i + 1] = 0;
454 break; 474 break;
455 } 475 }
456 if (buf[i] == '\r') {
457 buf[i] = '\n';
458 buf[i + 1] = 0; /**XXX wait for \n */
459 }
460 if (++n > 65536) 476 if (++n > 65536)
461 fatal("ssh_exchange_identification: No banner received"); 477 fatal("ssh_exchange_identification: "
462 i++; 478 "No banner received");
463 } 479 }
464 buf[sizeof(buf) - 1] = 0; 480 buf[sizeof(buf) - 1] = 0;
465 if (strncmp(buf, "SSH-", 4) == 0) 481 if (strncmp(buf, "SSH-", 4) == 0)
@@ -467,14 +483,7 @@ ssh_exchange_identification(void)
467 debug("ssh_exchange_identification: %s", buf); 483 debug("ssh_exchange_identification: %s", buf);
468 } 484 }
469 server_version_string = xstrdup(buf); 485 server_version_string = xstrdup(buf);
470 486 xfree(fdset);
471 /* If SetupTimeOut has been set, unset the alarm now, and
472 * put the correct handler for SIGALRM back.
473 */
474 if (options.setuptimeout > 0) {
475 alarm(0);
476 sigaction(SIGALRM, &osa, NULL);
477 }
478 487
479 /* 488 /*
480 * Check that the versions match. In future this might accept 489 * Check that the versions match. In future this might accept
@@ -528,10 +537,10 @@ ssh_exchange_identification(void)
528 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 537 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
529 remote_major); 538 remote_major);
530 /* Send our own protocol version identification. */ 539 /* Send our own protocol version identification. */
531 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 540 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s",
532 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 541 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
533 compat20 ? PROTOCOL_MINOR_2 : minor1, 542 compat20 ? PROTOCOL_MINOR_2 : minor1,
534 SSH_RELEASE); 543 SSH_RELEASE, compat20 ? "\r\n" : "\n");
535 if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) 544 if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf))
536 fatal("write: %.100s", strerror(errno)); 545 fatal("write: %.100s", strerror(errno));
537 client_version_string = xstrdup(buf); 546 client_version_string = xstrdup(buf);
@@ -580,14 +589,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
580 Key *file_key; 589 Key *file_key;
581 const char *type = key_type(host_key); 590 const char *type = key_type(host_key);
582 char *ip = NULL, *host = NULL; 591 char *ip = NULL, *host = NULL;
583 char hostline[1000], *hostp, *fp; 592 char hostline[1000], *hostp, *fp, *ra;
584 HostStatus host_status; 593 HostStatus host_status;
585 HostStatus ip_status; 594 HostStatus ip_status;
586 int r, local = 0, host_ip_differ = 0; 595 int r, local = 0, host_ip_differ = 0;
587 int salen; 596 int salen;
588 char ntop[NI_MAXHOST]; 597 char ntop[NI_MAXHOST];
589 char msg[1024]; 598 char msg[1024];
590 int len, host_line, ip_line; 599 int len, host_line, ip_line, cancelled_forwarding = 0;
591 const char *host_file = NULL, *ip_file = NULL; 600 const char *host_file = NULL, *ip_file = NULL;
592 601
593 /* 602 /*
@@ -634,6 +643,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
634 } else { 643 } else {
635 ip = xstrdup("<no hostip for proxy command>"); 644 ip = xstrdup("<no hostip for proxy command>");
636 } 645 }
646
637 /* 647 /*
638 * Turn off check_host_ip if the connection is to localhost, via proxy 648 * Turn off check_host_ip if the connection is to localhost, via proxy
639 * command or if we don't have a hostname to compare with 649 * command or if we don't have a hostname to compare with
@@ -718,6 +728,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
718 logit("Warning: Permanently added the %s host " 728 logit("Warning: Permanently added the %s host "
719 "key for IP address '%.128s' to the list " 729 "key for IP address '%.128s' to the list "
720 "of known hosts.", type, ip); 730 "of known hosts.", type, ip);
731 } else if (options.visual_host_key) {
732 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
733 ra = key_fingerprint(host_key, SSH_FP_MD5,
734 SSH_FP_RANDOMART);
735 logit("Host key fingerprint is %s\n%s\n", fp, ra);
736 xfree(ra);
737 xfree(fp);
721 } 738 }
722 break; 739 break;
723 case HOST_NEW: 740 case HOST_NEW:
@@ -753,6 +770,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
753 snprintf(msg1, sizeof(msg1), "."); 770 snprintf(msg1, sizeof(msg1), ".");
754 /* The default */ 771 /* The default */
755 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 772 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
773 ra = key_fingerprint(host_key, SSH_FP_MD5,
774 SSH_FP_RANDOMART);
756 msg2[0] = '\0'; 775 msg2[0] = '\0';
757 if (options.verify_host_key_dns) { 776 if (options.verify_host_key_dns) {
758 if (matching_host_key_dns) 777 if (matching_host_key_dns)
@@ -767,10 +786,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
767 snprintf(msg, sizeof(msg), 786 snprintf(msg, sizeof(msg),
768 "The authenticity of host '%.200s (%s)' can't be " 787 "The authenticity of host '%.200s (%s)' can't be "
769 "established%s\n" 788 "established%s\n"
770 "%s key fingerprint is %s.\n%s" 789 "%s key fingerprint is %s.%s%s\n%s"
771 "Are you sure you want to continue connecting " 790 "Are you sure you want to continue connecting "
772 "(yes/no)? ", 791 "(yes/no)? ",
773 host, ip, msg1, type, fp, msg2); 792 host, ip, msg1, type, fp,
793 options.visual_host_key ? "\n" : "",
794 options.visual_host_key ? ra : "",
795 msg2);
796 xfree(ra);
774 xfree(fp); 797 xfree(fp);
775 if (!confirm(msg)) 798 if (!confirm(msg))
776 goto fail; 799 goto fail;
@@ -823,7 +846,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
823 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 846 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
824 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 847 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
825 error("The %s host key for %s has changed,", type, host); 848 error("The %s host key for %s has changed,", type, host);
826 error("and the key for the according IP address %s", ip); 849 error("and the key for the corresponding IP address %s", ip);
827 error("%s. This could either mean that", key_msg); 850 error("%s. This could either mean that", key_msg);
828 error("DNS SPOOFING is happening or the IP address for the host"); 851 error("DNS SPOOFING is happening or the IP address for the host");
829 error("and its host key have changed at the same time."); 852 error("and its host key have changed at the same time.");
@@ -855,27 +878,32 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
855 error("Password authentication is disabled to avoid " 878 error("Password authentication is disabled to avoid "
856 "man-in-the-middle attacks."); 879 "man-in-the-middle attacks.");
857 options.password_authentication = 0; 880 options.password_authentication = 0;
881 cancelled_forwarding = 1;
858 } 882 }
859 if (options.kbd_interactive_authentication) { 883 if (options.kbd_interactive_authentication) {
860 error("Keyboard-interactive authentication is disabled" 884 error("Keyboard-interactive authentication is disabled"
861 " to avoid man-in-the-middle attacks."); 885 " to avoid man-in-the-middle attacks.");
862 options.kbd_interactive_authentication = 0; 886 options.kbd_interactive_authentication = 0;
863 options.challenge_response_authentication = 0; 887 options.challenge_response_authentication = 0;
888 cancelled_forwarding = 1;
864 } 889 }
865 if (options.challenge_response_authentication) { 890 if (options.challenge_response_authentication) {
866 error("Challenge/response authentication is disabled" 891 error("Challenge/response authentication is disabled"
867 " to avoid man-in-the-middle attacks."); 892 " to avoid man-in-the-middle attacks.");
868 options.challenge_response_authentication = 0; 893 options.challenge_response_authentication = 0;
894 cancelled_forwarding = 1;
869 } 895 }
870 if (options.forward_agent) { 896 if (options.forward_agent) {
871 error("Agent forwarding is disabled to avoid " 897 error("Agent forwarding is disabled to avoid "
872 "man-in-the-middle attacks."); 898 "man-in-the-middle attacks.");
873 options.forward_agent = 0; 899 options.forward_agent = 0;
900 cancelled_forwarding = 1;
874 } 901 }
875 if (options.forward_x11) { 902 if (options.forward_x11) {
876 error("X11 forwarding is disabled to avoid " 903 error("X11 forwarding is disabled to avoid "
877 "man-in-the-middle attacks."); 904 "man-in-the-middle attacks.");
878 options.forward_x11 = 0; 905 options.forward_x11 = 0;
906 cancelled_forwarding = 1;
879 } 907 }
880 if (options.num_local_forwards > 0 || 908 if (options.num_local_forwards > 0 ||
881 options.num_remote_forwards > 0) { 909 options.num_remote_forwards > 0) {
@@ -883,12 +911,18 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
883 "man-in-the-middle attacks."); 911 "man-in-the-middle attacks.");
884 options.num_local_forwards = 912 options.num_local_forwards =
885 options.num_remote_forwards = 0; 913 options.num_remote_forwards = 0;
914 cancelled_forwarding = 1;
886 } 915 }
887 if (options.tun_open != SSH_TUNMODE_NO) { 916 if (options.tun_open != SSH_TUNMODE_NO) {
888 error("Tunnel forwarding is disabled to avoid " 917 error("Tunnel forwarding is disabled to avoid "
889 "man-in-the-middle attacks."); 918 "man-in-the-middle attacks.");
890 options.tun_open = SSH_TUNMODE_NO; 919 options.tun_open = SSH_TUNMODE_NO;
920 cancelled_forwarding = 1;
891 } 921 }
922 if (options.exit_on_forward_failure && cancelled_forwarding)
923 fatal("Error: forwarding disabled due to host key "
924 "check failure");
925
892 /* 926 /*
893 * XXX Should permit the user to change to use the new id. 927 * XXX Should permit the user to change to use the new id.
894 * This could be done by converting the host key to an 928 * This could be done by converting the host key to an
@@ -987,7 +1021,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
987 */ 1021 */
988void 1022void
989ssh_login(Sensitive *sensitive, const char *orighost, 1023ssh_login(Sensitive *sensitive, const char *orighost,
990 struct sockaddr *hostaddr, struct passwd *pw) 1024 struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms)
991{ 1025{
992 char *host, *cp; 1026 char *host, *cp;
993 char *server_user, *local_user; 1027 char *server_user, *local_user;
@@ -1002,7 +1036,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
1002 *cp = (char)tolower(*cp); 1036 *cp = (char)tolower(*cp);
1003 1037
1004 /* Exchange protocol version identification strings with the server. */ 1038 /* Exchange protocol version identification strings with the server. */
1005 ssh_exchange_identification(); 1039 ssh_exchange_identification(timeout_ms);
1006 1040
1007 /* Put the connection into non-blocking mode. */ 1041 /* Put the connection into non-blocking mode. */
1008 packet_set_nonblocking(); 1042 packet_set_nonblocking();
@@ -1041,18 +1075,20 @@ static int
1041show_key_from_file(const char *file, const char *host, int keytype) 1075show_key_from_file(const char *file, const char *host, int keytype)
1042{ 1076{
1043 Key *found; 1077 Key *found;
1044 char *fp; 1078 char *fp, *ra;
1045 int line, ret; 1079 int line, ret;
1046 1080
1047 found = key_new(keytype); 1081 found = key_new(keytype);
1048 if ((ret = lookup_key_in_hostfile_by_type(file, host, 1082 if ((ret = lookup_key_in_hostfile_by_type(file, host,
1049 keytype, found, &line))) { 1083 keytype, found, &line))) {
1050 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); 1084 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
1085 ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART);
1051 logit("WARNING: %s key found for host %s\n" 1086 logit("WARNING: %s key found for host %s\n"
1052 "in %s:%d\n" 1087 "in %s:%d\n"
1053 "%s key fingerprint %s.", 1088 "%s key fingerprint %s.\n%s\n",
1054 key_type(found), host, file, line, 1089 key_type(found), host, file, line,
1055 key_type(found), fp); 1090 key_type(found), fp, ra);
1091 xfree(ra);
1056 xfree(fp); 1092 xfree(fp);
1057 } 1093 }
1058 key_free(found); 1094 key_free(found);