diff options
author | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:42:53 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:42:53 +0000 |
commit | 87552344215a38d3a2b0d4d63dc151e05978bbe1 (patch) | |
tree | 9f4b96055e6ccaa915e8d59d9f2805e9e119371d /sshconnect.c | |
parent | a25ec0b132c44c9e341e08464ff830de06b81126 (diff) | |
parent | ef94e5613d37bcbf880f21ee6094e4b1c7683a4c (diff) |
import openssh-5.1p1-gsskex-cjwatson-20080722.patch
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 154 |
1 files changed, 117 insertions, 37 deletions
diff --git a/sshconnect.c b/sshconnect.c index a222233d0..ec8ba33e0 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 |
@@ -86,7 +86,10 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
86 | char *command_string, *tmp; | 86 | char *command_string, *tmp; |
87 | int pin[2], pout[2]; | 87 | int pin[2], pout[2]; |
88 | pid_t pid; | 88 | pid_t pid; |
89 | char strport[NI_MAXSERV]; | 89 | char *shell, strport[NI_MAXSERV]; |
90 | |||
91 | if ((shell = getenv("SHELL")) == NULL) | ||
92 | shell = _PATH_BSHELL; | ||
90 | 93 | ||
91 | /* Convert the port number into a string. */ | 94 | /* Convert the port number into a string. */ |
92 | snprintf(strport, sizeof strport, "%hu", port); | 95 | snprintf(strport, sizeof strport, "%hu", port); |
@@ -132,7 +135,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
132 | 135 | ||
133 | /* Stderr is left as it is so that error messages get | 136 | /* Stderr is left as it is so that error messages get |
134 | printed on the user's terminal. */ | 137 | printed on the user's terminal. */ |
135 | argv[0] = _PATH_BSHELL; | 138 | argv[0] = shell; |
136 | argv[1] = "-c"; | 139 | argv[1] = "-c"; |
137 | argv[2] = command_string; | 140 | argv[2] = command_string; |
138 | argv[3] = NULL; | 141 | argv[3] = NULL; |
@@ -158,6 +161,8 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
158 | 161 | ||
159 | /* Set the connection file descriptors. */ | 162 | /* Set the connection file descriptors. */ |
160 | packet_set_connection(pout[0], pin[1]); | 163 | packet_set_connection(pout[0], pin[1]); |
164 | packet_set_timeout(options.server_alive_interval, | ||
165 | options.server_alive_count_max); | ||
161 | 166 | ||
162 | /* Indicate OK return */ | 167 | /* Indicate OK return */ |
163 | return 0; | 168 | return 0; |
@@ -201,10 +206,10 @@ ssh_create_socket(int privileged, struct addrinfo *ai) | |||
201 | hints.ai_socktype = ai->ai_socktype; | 206 | hints.ai_socktype = ai->ai_socktype; |
202 | hints.ai_protocol = ai->ai_protocol; | 207 | hints.ai_protocol = ai->ai_protocol; |
203 | hints.ai_flags = AI_PASSIVE; | 208 | hints.ai_flags = AI_PASSIVE; |
204 | gaierr = getaddrinfo(options.bind_address, "0", &hints, &res); | 209 | gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res); |
205 | if (gaierr) { | 210 | if (gaierr) { |
206 | error("getaddrinfo: %s: %s", options.bind_address, | 211 | error("getaddrinfo: %s: %s", options.bind_address, |
207 | gai_strerror(gaierr)); | 212 | ssh_gai_strerror(gaierr)); |
208 | close(sock); | 213 | close(sock); |
209 | return -1; | 214 | return -1; |
210 | } | 215 | } |
@@ -220,30 +225,36 @@ ssh_create_socket(int privileged, struct addrinfo *ai) | |||
220 | 225 | ||
221 | static int | 226 | static int |
222 | timeout_connect(int sockfd, const struct sockaddr *serv_addr, | 227 | timeout_connect(int sockfd, const struct sockaddr *serv_addr, |
223 | socklen_t addrlen, int timeout) | 228 | socklen_t addrlen, int *timeoutp) |
224 | { | 229 | { |
225 | fd_set *fdset; | 230 | fd_set *fdset; |
226 | struct timeval tv; | 231 | struct timeval tv, t_start; |
227 | socklen_t optlen; | 232 | socklen_t optlen; |
228 | int optval, rc, result = -1; | 233 | int optval, rc, result = -1; |
229 | 234 | ||
230 | if (timeout <= 0) | 235 | gettimeofday(&t_start, NULL); |
231 | return (connect(sockfd, serv_addr, addrlen)); | 236 | |
237 | if (*timeoutp <= 0) { | ||
238 | result = connect(sockfd, serv_addr, addrlen); | ||
239 | goto done; | ||
240 | } | ||
232 | 241 | ||
233 | set_nonblock(sockfd); | 242 | set_nonblock(sockfd); |
234 | rc = connect(sockfd, serv_addr, addrlen); | 243 | rc = connect(sockfd, serv_addr, addrlen); |
235 | if (rc == 0) { | 244 | if (rc == 0) { |
236 | unset_nonblock(sockfd); | 245 | unset_nonblock(sockfd); |
237 | return (0); | 246 | result = 0; |
247 | goto done; | ||
248 | } | ||
249 | if (errno != EINPROGRESS) { | ||
250 | result = -1; | ||
251 | goto done; | ||
238 | } | 252 | } |
239 | if (errno != EINPROGRESS) | ||
240 | return (-1); | ||
241 | 253 | ||
242 | fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), | 254 | fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), |
243 | sizeof(fd_mask)); | 255 | sizeof(fd_mask)); |
244 | FD_SET(sockfd, fdset); | 256 | FD_SET(sockfd, fdset); |
245 | tv.tv_sec = timeout; | 257 | ms_to_timeval(&tv, *timeoutp); |
246 | tv.tv_usec = 0; | ||
247 | 258 | ||
248 | for (;;) { | 259 | for (;;) { |
249 | rc = select(sockfd + 1, NULL, fdset, NULL, &tv); | 260 | rc = select(sockfd + 1, NULL, fdset, NULL, &tv); |
@@ -282,6 +293,16 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, | |||
282 | } | 293 | } |
283 | 294 | ||
284 | 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 | |||
285 | return (result); | 306 | return (result); |
286 | } | 307 | } |
287 | 308 | ||
@@ -298,8 +319,8 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, | |||
298 | */ | 319 | */ |
299 | int | 320 | int |
300 | ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | 321 | ssh_connect(const char *host, struct sockaddr_storage * hostaddr, |
301 | u_short port, int family, int connection_attempts, | 322 | u_short port, int family, int connection_attempts, int *timeout_ms, |
302 | int needpriv, const char *proxy_command) | 323 | int want_keepalive, int needpriv, const char *proxy_command) |
303 | { | 324 | { |
304 | int gaierr; | 325 | int gaierr; |
305 | int on = 1; | 326 | int on = 1; |
@@ -320,8 +341,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
320 | hints.ai_socktype = SOCK_STREAM; | 341 | hints.ai_socktype = SOCK_STREAM; |
321 | snprintf(strport, sizeof strport, "%u", port); | 342 | snprintf(strport, sizeof strport, "%u", port); |
322 | if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) | 343 | if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
323 | fatal("%s: %.100s: %s", __progname, host, | 344 | fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
324 | gai_strerror(gaierr)); | 345 | host, ssh_gai_strerror(gaierr)); |
325 | 346 | ||
326 | for (attempt = 0; attempt < connection_attempts; attempt++) { | 347 | for (attempt = 0; attempt < connection_attempts; attempt++) { |
327 | if (attempt > 0) { | 348 | if (attempt > 0) { |
@@ -352,7 +373,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
352 | continue; | 373 | continue; |
353 | 374 | ||
354 | if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, | 375 | if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, |
355 | options.connection_timeout) >= 0) { | 376 | timeout_ms) >= 0) { |
356 | /* Successful connection. */ | 377 | /* Successful connection. */ |
357 | memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); | 378 | memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); |
358 | break; | 379 | break; |
@@ -379,13 +400,15 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
379 | debug("Connection established."); | 400 | debug("Connection established."); |
380 | 401 | ||
381 | /* Set SO_KEEPALIVE if requested. */ | 402 | /* Set SO_KEEPALIVE if requested. */ |
382 | if (options.tcp_keep_alive && | 403 | if (want_keepalive && |
383 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, | 404 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, |
384 | sizeof(on)) < 0) | 405 | sizeof(on)) < 0) |
385 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); | 406 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); |
386 | 407 | ||
387 | /* Set the connection. */ | 408 | /* Set the connection. */ |
388 | packet_set_connection(sock, sock); | 409 | packet_set_connection(sock, sock); |
410 | packet_set_timeout(options.server_alive_interval, | ||
411 | options.server_alive_count_max); | ||
389 | 412 | ||
390 | return 0; | 413 | return 0; |
391 | } | 414 | } |
@@ -395,7 +418,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
395 | * identification string. | 418 | * identification string. |
396 | */ | 419 | */ |
397 | static void | 420 | static void |
398 | ssh_exchange_identification(void) | 421 | ssh_exchange_identification(int timeout_ms) |
399 | { | 422 | { |
400 | char buf[256], remote_version[256]; /* must be same size! */ | 423 | char buf[256], remote_version[256]; /* must be same size! */ |
401 | int remote_major, remote_minor, mismatch; | 424 | int remote_major, remote_minor, mismatch; |
@@ -403,16 +426,44 @@ ssh_exchange_identification(void) | |||
403 | int connection_out = packet_get_connection_out(); | 426 | int connection_out = packet_get_connection_out(); |
404 | int minor1 = PROTOCOL_MINOR_1; | 427 | int minor1 = PROTOCOL_MINOR_1; |
405 | u_int i, n; | 428 | u_int i, n; |
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); | ||
406 | 436 | ||
407 | /* Read other side's version identification. */ | 437 | /* Read other side's version identification. */ |
438 | remaining = timeout_ms; | ||
408 | for (n = 0;;) { | 439 | for (n = 0;;) { |
409 | for (i = 0; i < sizeof(buf) - 1; i++) { | 440 | for (i = 0; i < sizeof(buf) - 1; i++) { |
410 | size_t len = atomicio(read, connection_in, &buf[i], 1); | 441 | if (timeout_ms > 0) { |
442 | gettimeofday(&t_start, NULL); | ||
443 | ms_to_timeval(&t_remaining, remaining); | ||
444 | FD_SET(connection_in, fdset); | ||
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); | ||
411 | 460 | ||
412 | if (len != 1 && errno == EPIPE) | 461 | if (len != 1 && errno == EPIPE) |
413 | fatal("ssh_exchange_identification: Connection closed by remote host"); | 462 | fatal("ssh_exchange_identification: " |
463 | "Connection closed by remote host"); | ||
414 | else if (len != 1) | 464 | else if (len != 1) |
415 | fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); | 465 | fatal("ssh_exchange_identification: " |
466 | "read: %.100s", strerror(errno)); | ||
416 | if (buf[i] == '\r') { | 467 | if (buf[i] == '\r') { |
417 | buf[i] = '\n'; | 468 | buf[i] = '\n'; |
418 | buf[i + 1] = 0; | 469 | buf[i + 1] = 0; |
@@ -423,7 +474,8 @@ ssh_exchange_identification(void) | |||
423 | break; | 474 | break; |
424 | } | 475 | } |
425 | if (++n > 65536) | 476 | if (++n > 65536) |
426 | fatal("ssh_exchange_identification: No banner received"); | 477 | fatal("ssh_exchange_identification: " |
478 | "No banner received"); | ||
427 | } | 479 | } |
428 | buf[sizeof(buf) - 1] = 0; | 480 | buf[sizeof(buf) - 1] = 0; |
429 | if (strncmp(buf, "SSH-", 4) == 0) | 481 | if (strncmp(buf, "SSH-", 4) == 0) |
@@ -431,6 +483,7 @@ ssh_exchange_identification(void) | |||
431 | debug("ssh_exchange_identification: %s", buf); | 483 | debug("ssh_exchange_identification: %s", buf); |
432 | } | 484 | } |
433 | server_version_string = xstrdup(buf); | 485 | server_version_string = xstrdup(buf); |
486 | xfree(fdset); | ||
434 | 487 | ||
435 | /* | 488 | /* |
436 | * Check that the versions match. In future this might accept | 489 | * Check that the versions match. In future this might accept |
@@ -484,10 +537,10 @@ ssh_exchange_identification(void) | |||
484 | (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, | 537 | (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, |
485 | remote_major); | 538 | remote_major); |
486 | /* Send our own protocol version identification. */ | 539 | /* Send our own protocol version identification. */ |
487 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", | 540 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", |
488 | compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, | 541 | compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, |
489 | compat20 ? PROTOCOL_MINOR_2 : minor1, | 542 | compat20 ? PROTOCOL_MINOR_2 : minor1, |
490 | SSH_VERSION); | 543 | SSH_VERSION, compat20 ? "\r\n" : "\n"); |
491 | if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) | 544 | if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) |
492 | fatal("write: %.100s", strerror(errno)); | 545 | fatal("write: %.100s", strerror(errno)); |
493 | client_version_string = xstrdup(buf); | 546 | client_version_string = xstrdup(buf); |
@@ -536,14 +589,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
536 | Key *file_key; | 589 | Key *file_key; |
537 | const char *type = key_type(host_key); | 590 | const char *type = key_type(host_key); |
538 | char *ip = NULL, *host = NULL; | 591 | char *ip = NULL, *host = NULL; |
539 | char hostline[1000], *hostp, *fp; | 592 | char hostline[1000], *hostp, *fp, *ra; |
540 | HostStatus host_status; | 593 | HostStatus host_status; |
541 | HostStatus ip_status; | 594 | HostStatus ip_status; |
542 | int r, local = 0, host_ip_differ = 0; | 595 | int r, local = 0, host_ip_differ = 0; |
543 | int salen; | 596 | int salen; |
544 | char ntop[NI_MAXHOST]; | 597 | char ntop[NI_MAXHOST]; |
545 | char msg[1024]; | 598 | char msg[1024]; |
546 | int len, host_line, ip_line; | 599 | int len, host_line, ip_line, cancelled_forwarding = 0; |
547 | const char *host_file = NULL, *ip_file = NULL; | 600 | const char *host_file = NULL, *ip_file = NULL; |
548 | 601 | ||
549 | /* | 602 | /* |
@@ -590,6 +643,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
590 | } else { | 643 | } else { |
591 | ip = xstrdup("<no hostip for proxy command>"); | 644 | ip = xstrdup("<no hostip for proxy command>"); |
592 | } | 645 | } |
646 | |||
593 | /* | 647 | /* |
594 | * 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 |
595 | * 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 |
@@ -674,6 +728,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
674 | logit("Warning: Permanently added the %s host " | 728 | logit("Warning: Permanently added the %s host " |
675 | "key for IP address '%.128s' to the list " | 729 | "key for IP address '%.128s' to the list " |
676 | "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); | ||
677 | } | 738 | } |
678 | break; | 739 | break; |
679 | case HOST_NEW: | 740 | case HOST_NEW: |
@@ -709,6 +770,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
709 | snprintf(msg1, sizeof(msg1), "."); | 770 | snprintf(msg1, sizeof(msg1), "."); |
710 | /* The default */ | 771 | /* The default */ |
711 | 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); | ||
712 | msg2[0] = '\0'; | 775 | msg2[0] = '\0'; |
713 | if (options.verify_host_key_dns) { | 776 | if (options.verify_host_key_dns) { |
714 | if (matching_host_key_dns) | 777 | if (matching_host_key_dns) |
@@ -723,10 +786,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
723 | snprintf(msg, sizeof(msg), | 786 | snprintf(msg, sizeof(msg), |
724 | "The authenticity of host '%.200s (%s)' can't be " | 787 | "The authenticity of host '%.200s (%s)' can't be " |
725 | "established%s\n" | 788 | "established%s\n" |
726 | "%s key fingerprint is %s.\n%s" | 789 | "%s key fingerprint is %s.%s%s\n%s" |
727 | "Are you sure you want to continue connecting " | 790 | "Are you sure you want to continue connecting " |
728 | "(yes/no)? ", | 791 | "(yes/no)? ", |
729 | 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); | ||
730 | xfree(fp); | 797 | xfree(fp); |
731 | if (!confirm(msg)) | 798 | if (!confirm(msg)) |
732 | goto fail; | 799 | goto fail; |
@@ -779,7 +846,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
779 | error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); | 846 | error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); |
780 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); | 847 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
781 | error("The %s host key for %s has changed,", type, host); | 848 | error("The %s host key for %s has changed,", type, host); |
782 | error("and the key for the according IP address %s", ip); | 849 | error("and the key for the corresponding IP address %s", ip); |
783 | error("%s. This could either mean that", key_msg); | 850 | error("%s. This could either mean that", key_msg); |
784 | 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"); |
785 | error("and its host key have changed at the same time."); | 852 | error("and its host key have changed at the same time."); |
@@ -811,27 +878,32 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
811 | error("Password authentication is disabled to avoid " | 878 | error("Password authentication is disabled to avoid " |
812 | "man-in-the-middle attacks."); | 879 | "man-in-the-middle attacks."); |
813 | options.password_authentication = 0; | 880 | options.password_authentication = 0; |
881 | cancelled_forwarding = 1; | ||
814 | } | 882 | } |
815 | if (options.kbd_interactive_authentication) { | 883 | if (options.kbd_interactive_authentication) { |
816 | error("Keyboard-interactive authentication is disabled" | 884 | error("Keyboard-interactive authentication is disabled" |
817 | " to avoid man-in-the-middle attacks."); | 885 | " to avoid man-in-the-middle attacks."); |
818 | options.kbd_interactive_authentication = 0; | 886 | options.kbd_interactive_authentication = 0; |
819 | options.challenge_response_authentication = 0; | 887 | options.challenge_response_authentication = 0; |
888 | cancelled_forwarding = 1; | ||
820 | } | 889 | } |
821 | if (options.challenge_response_authentication) { | 890 | if (options.challenge_response_authentication) { |
822 | error("Challenge/response authentication is disabled" | 891 | error("Challenge/response authentication is disabled" |
823 | " to avoid man-in-the-middle attacks."); | 892 | " to avoid man-in-the-middle attacks."); |
824 | options.challenge_response_authentication = 0; | 893 | options.challenge_response_authentication = 0; |
894 | cancelled_forwarding = 1; | ||
825 | } | 895 | } |
826 | if (options.forward_agent) { | 896 | if (options.forward_agent) { |
827 | error("Agent forwarding is disabled to avoid " | 897 | error("Agent forwarding is disabled to avoid " |
828 | "man-in-the-middle attacks."); | 898 | "man-in-the-middle attacks."); |
829 | options.forward_agent = 0; | 899 | options.forward_agent = 0; |
900 | cancelled_forwarding = 1; | ||
830 | } | 901 | } |
831 | if (options.forward_x11) { | 902 | if (options.forward_x11) { |
832 | error("X11 forwarding is disabled to avoid " | 903 | error("X11 forwarding is disabled to avoid " |
833 | "man-in-the-middle attacks."); | 904 | "man-in-the-middle attacks."); |
834 | options.forward_x11 = 0; | 905 | options.forward_x11 = 0; |
906 | cancelled_forwarding = 1; | ||
835 | } | 907 | } |
836 | if (options.num_local_forwards > 0 || | 908 | if (options.num_local_forwards > 0 || |
837 | options.num_remote_forwards > 0) { | 909 | options.num_remote_forwards > 0) { |
@@ -839,12 +911,18 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
839 | "man-in-the-middle attacks."); | 911 | "man-in-the-middle attacks."); |
840 | options.num_local_forwards = | 912 | options.num_local_forwards = |
841 | options.num_remote_forwards = 0; | 913 | options.num_remote_forwards = 0; |
914 | cancelled_forwarding = 1; | ||
842 | } | 915 | } |
843 | if (options.tun_open != SSH_TUNMODE_NO) { | 916 | if (options.tun_open != SSH_TUNMODE_NO) { |
844 | error("Tunnel forwarding is disabled to avoid " | 917 | error("Tunnel forwarding is disabled to avoid " |
845 | "man-in-the-middle attacks."); | 918 | "man-in-the-middle attacks."); |
846 | options.tun_open = SSH_TUNMODE_NO; | 919 | options.tun_open = SSH_TUNMODE_NO; |
920 | cancelled_forwarding = 1; | ||
847 | } | 921 | } |
922 | if (options.exit_on_forward_failure && cancelled_forwarding) | ||
923 | fatal("Error: forwarding disabled due to host key " | ||
924 | "check failure"); | ||
925 | |||
848 | /* | 926 | /* |
849 | * 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. |
850 | * This could be done by converting the host key to an | 928 | * This could be done by converting the host key to an |
@@ -943,7 +1021,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
943 | */ | 1021 | */ |
944 | void | 1022 | void |
945 | ssh_login(Sensitive *sensitive, const char *orighost, | 1023 | ssh_login(Sensitive *sensitive, const char *orighost, |
946 | struct sockaddr *hostaddr, struct passwd *pw) | 1024 | struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms) |
947 | { | 1025 | { |
948 | char *host, *cp; | 1026 | char *host, *cp; |
949 | char *server_user, *local_user; | 1027 | char *server_user, *local_user; |
@@ -958,7 +1036,7 @@ ssh_login(Sensitive *sensitive, const char *orighost, | |||
958 | *cp = (char)tolower(*cp); | 1036 | *cp = (char)tolower(*cp); |
959 | 1037 | ||
960 | /* Exchange protocol version identification strings with the server. */ | 1038 | /* Exchange protocol version identification strings with the server. */ |
961 | ssh_exchange_identification(); | 1039 | ssh_exchange_identification(timeout_ms); |
962 | 1040 | ||
963 | /* Put the connection into non-blocking mode. */ | 1041 | /* Put the connection into non-blocking mode. */ |
964 | packet_set_nonblocking(); | 1042 | packet_set_nonblocking(); |
@@ -997,18 +1075,20 @@ static int | |||
997 | show_key_from_file(const char *file, const char *host, int keytype) | 1075 | show_key_from_file(const char *file, const char *host, int keytype) |
998 | { | 1076 | { |
999 | Key *found; | 1077 | Key *found; |
1000 | char *fp; | 1078 | char *fp, *ra; |
1001 | int line, ret; | 1079 | int line, ret; |
1002 | 1080 | ||
1003 | found = key_new(keytype); | 1081 | found = key_new(keytype); |
1004 | if ((ret = lookup_key_in_hostfile_by_type(file, host, | 1082 | if ((ret = lookup_key_in_hostfile_by_type(file, host, |
1005 | keytype, found, &line))) { | 1083 | keytype, found, &line))) { |
1006 | 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); | ||
1007 | logit("WARNING: %s key found for host %s\n" | 1086 | logit("WARNING: %s key found for host %s\n" |
1008 | "in %s:%d\n" | 1087 | "in %s:%d\n" |
1009 | "%s key fingerprint %s.", | 1088 | "%s key fingerprint %s.\n%s\n", |
1010 | key_type(found), host, file, line, | 1089 | key_type(found), host, file, line, |
1011 | key_type(found), fp); | 1090 | key_type(found), fp, ra); |
1091 | xfree(ra); | ||
1012 | xfree(fp); | 1092 | xfree(fp); |
1013 | } | 1093 | } |
1014 | key_free(found); | 1094 | key_free(found); |