summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
committerColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
commit137d76ba65883aa8143af1fcad83b57e7badef0c (patch)
treef426e804bb5248ceafedfab7bb78ae6e6752942c /sshconnect.c
parentdac7d049dad31f5f84d421d4eb628a7e13f977d7 (diff)
parentef94e5613d37bcbf880f21ee6094e4b1c7683a4c (diff)
* New upstream release (closes: #474301). Important changes not previously
backported to 4.7p1: - 4.9/4.9p1 (http://www.openssh.com/txt/release-4.9): + Added chroot(2) support for sshd(8), controlled by a new option "ChrootDirectory" (closes: #139047, LP: #24777). + Linked sftp-server(8) into sshd(8). The internal sftp server is used when the command "internal-sftp" is specified in a Subsystem or ForceCommand declaration. When used with ChrootDirectory, the internal sftp server requires no special configuration of files inside the chroot environment. + Added a protocol extension method "posix-rename@openssh.com" for sftp-server(8) to perform POSIX atomic rename() operations; sftp(1) prefers this if available (closes: #308561). + Removed the fixed limit of 100 file handles in sftp-server(8). + ssh(8) will now skip generation of SSH protocol 1 ephemeral server keys when in inetd mode and protocol 2 connections are negotiated. This speeds up protocol 2 connections to inetd-mode servers that also allow Protocol 1. + Accept the PermitRootLogin directive in a sshd_config(5) Match block. Allows for, e.g. permitting root only from the local network. + Reworked sftp(1) argument splitting and escaping to be more internally consistent (i.e. between sftp commands) and more consistent with sh(1). Please note that this will change the interpretation of some quoted strings, especially those with embedded backslash escape sequences. + Support "Banner=none" in sshd_config(5) to disable sending of a pre-login banner (e.g. in a Match block). + ssh(1) ProxyCommands are now executed with $SHELL rather than /bin/sh. + ssh(1)'s ConnectTimeout option is now applied to both the TCP connection and the SSH banner exchange (previously it just covered the TCP connection). This allows callers of ssh(1) to better detect and deal with stuck servers that accept a TCP connection but don't progress the protocol, and also makes ConnectTimeout useful for connections via a ProxyCommand. + scp(1) incorrectly reported "stalled" on slow copies (closes: #140828). + scp(1) date underflow for timestamps before epoch. + ssh(1) used the obsolete SIG DNS RRtype for host keys in DNS, instead of the current standard RRSIG. + Correctly drain ACKs when a sftp(1) upload write fails midway, avoids a fatal() exit from what should be a recoverable condition. + Fixed ssh-keygen(1) selective host key hashing (i.e. "ssh-keygen -HF hostname") to not include any IP address in the data to be hashed. + Make ssh(1) skip listening on the IPv6 wildcard address when a binding address of 0.0.0.0 is used against an old SSH server that does not support the RFC4254 syntax for wildcard bind addresses. + Enable IPV6_V6ONLY socket option on sshd(8) listen socket, as is already done for X11/TCP forwarding sockets (closes: #439661). + Fix FD leak that could hang a ssh(1) connection multiplexing master. + Make ssh(1) -q option documentation consistent with reality. + Fixed sshd(8) PAM support not calling pam_session_close(), or failing to call it with root privileges (closes: #372680). + Fix activation of OpenSSL engine support when requested in configure (LP: #119295). - 5.1/5.1p1 (http://www.openssh.com/txt/release-5.1): + Introduce experimental SSH Fingerprint ASCII Visualisation to ssh(1) and ssh-keygen(1). Visual fingerprint display is controlled by a new ssh_config(5) option "VisualHostKey". The intent is to render SSH host keys in a visual form that is amenable to easy recall and rejection of changed host keys. + sshd_config(5) now supports CIDR address/masklen matching in "Match address" blocks, with a fallback to classic wildcard matching. + sshd(8) now supports CIDR matching in ~/.ssh/authorized_keys from="..." restrictions, also with a fallback to classic wildcard matching. + Added an extended test mode (-T) to sshd(8) to request that it write its effective configuration to stdout and exit. Extended test mode also supports the specification of connection parameters (username, source address and hostname) to test the application of sshd_config(5) Match rules. + ssh(1) now prints the number of bytes transferred and the overall connection throughput for SSH protocol 2 sessions when in verbose mode (previously these statistics were displayed for protocol 1 connections only). + sftp-server(8) now supports extension methods statvfs@openssh.com and fstatvfs@openssh.com that implement statvfs(2)-like operations. + sftp(1) now has a "df" command to the sftp client that uses the statvfs@openssh.com to produce a df(1)-like display of filesystem space and inode utilisation (requires statvfs@openssh.com support on the server). + Added a MaxSessions option to sshd_config(5) to allow control of the number of multiplexed sessions supported over a single TCP connection. This allows increasing the number of allowed sessions above the previous default of 10, disabling connection multiplexing (MaxSessions=1) or disallowing login/shell/subsystem sessions entirely (MaxSessions=0). + Added a no-more-sessions@openssh.com global request extension that is sent from ssh(1) to sshd(8) when the client knows that it will never request another session (i.e. when session multiplexing is disabled). This allows a server to disallow further session requests and terminate the session in cases where the client has been hijacked. + ssh-keygen(1) now supports the use of the -l option in combination with -F to search for a host in ~/.ssh/known_hosts and display its fingerprint. + ssh-keyscan(1) now defaults to "rsa" (protocol 2) keys, instead of "rsa1". + Added an AllowAgentForwarding option to sshd_config(8) to control whether authentication agent forwarding is permitted. Note that this is a loose control, as a client may install their own unofficial forwarder. + ssh(1) and sshd(8): avoid unnecessary malloc/copy/free when receiving network data, resulting in a ~10% speedup. + ssh(1) and sshd(8) will now try additional addresses when connecting to a port forward destination whose DNS name resolves to more than one address. The previous behaviour was to try the only first address and give up if that failed. + ssh(1) and sshd(8) now support signalling that channels are half-closed for writing, through a channel protocol extension notification "eow@openssh.com". This allows propagation of closed file descriptors, so that commands such as "ssh -2 localhost od /bin/ls | true" do not send unnecessary data over the wire. + sshd(8): increased the default size of ssh protocol 1 ephemeral keys from 768 to 1024 bits. + When ssh(1) has been requested to fork after authentication ("ssh -f") with ExitOnForwardFailure enabled, delay the fork until after replies for any -R forwards have been seen. Allows for robust detection of -R forward failure when using -f. + "Match group" blocks in sshd_config(5) now support negation of groups. E.g. "Match group staff,!guests". + sftp(1) and sftp-server(8) now allow chmod-like operations to set set[ug]id/sticky bits. + The MaxAuthTries option is now permitted in sshd_config(5) match blocks. + Multiplexed ssh(1) sessions now support a subset of the ~ escapes that are available to a primary connection. + ssh(1) connection multiplexing will now fall back to creating a new connection in most error cases (closes: #352830). + Make ssh(1) deal more gracefully with channel requests that fail. Previously it would optimistically assume that requests would always succeed, which could cause hangs if they did not (e.g. when the server runs out of file descriptors). + ssh(1) now reports multiplexing errors via the multiplex slave's stderr where possible (subject to LogLevel in the mux master). + Prevent sshd(8) from erroneously applying public key restrictions leaned from ~/.ssh/authorized_keys to other authentication methods when public key authentication subsequently fails (LP: #161047). + Fixed an UMAC alignment problem that manifested on Itanium platforms.
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);