diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | ssh.c | 15 | ||||
-rw-r--r-- | sshconnect.c | 105 | ||||
-rw-r--r-- | sshconnect.h | 6 |
4 files changed, 107 insertions, 29 deletions
@@ -25,6 +25,14 @@ | |||
25 | make file descriptor passing code return an error rather than call fatal() | 25 | make file descriptor passing code return an error rather than call fatal() |
26 | when it encounters problems, and use this to make session multiplexing | 26 | when it encounters problems, and use this to make session multiplexing |
27 | masters survive slaves failing to pass all stdio FDs; ok markus@ | 27 | masters survive slaves failing to pass all stdio FDs; ok markus@ |
28 | - djm@cvs.openbsd.org 2007/09/04 11:15:56 | ||
29 | [ssh.c sshconnect.c sshconnect.h] | ||
30 | make ssh(1)'s ConnectTimeout option apply to both the TCP connection and | ||
31 | SSH banner exchange (previously it just covered the TCP connection). | ||
32 | This allows callers of ssh(1) to better detect and deal with stuck servers | ||
33 | that accept a TCP connection but don't progress the protocol, and also | ||
34 | makes ConnectTimeout useful for connections via a ProxyCommand; | ||
35 | feedback and "looks ok" markus@ | ||
28 | 36 | ||
29 | 20070914 | 37 | 20070914 |
30 | - (dtucker) [openbsd-compat/bsd-asprintf.c] Plug mem leak in error path. | 38 | - (dtucker) [openbsd-compat/bsd-asprintf.c] Plug mem leak in error path. |
@@ -3222,4 +3230,4 @@ | |||
3222 | OpenServer 6 and add osr5bigcrypt support so when someone migrates | 3230 | OpenServer 6 and add osr5bigcrypt support so when someone migrates |
3223 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ | 3231 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ |
3224 | 3232 | ||
3225 | $Id: ChangeLog,v 1.4748 2007/09/17 02:04:08 djm Exp $ | 3233 | $Id: ChangeLog,v 1.4749 2007/09/17 02:06:57 djm Exp $ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.302 2007/09/04 03:21:03 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.303 2007/09/04 11:15:55 djm 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 |
@@ -210,7 +210,7 @@ main(int ac, char **av) | |||
210 | char *p, *cp, *line, buf[256]; | 210 | char *p, *cp, *line, buf[256]; |
211 | struct stat st; | 211 | struct stat st; |
212 | struct passwd *pw; | 212 | struct passwd *pw; |
213 | int dummy; | 213 | int dummy, timeout_ms; |
214 | extern int optind, optreset; | 214 | extern int optind, optreset; |
215 | extern char *optarg; | 215 | extern char *optarg; |
216 | struct servent *sp; | 216 | struct servent *sp; |
@@ -681,9 +681,12 @@ main(int ac, char **av) | |||
681 | if (options.control_path != NULL) | 681 | if (options.control_path != NULL) |
682 | control_client(options.control_path); | 682 | control_client(options.control_path); |
683 | 683 | ||
684 | timeout_ms = options.connection_timeout * 1000; | ||
685 | |||
684 | /* Open a connection to the remote host. */ | 686 | /* Open a connection to the remote host. */ |
685 | if (ssh_connect(host, &hostaddr, options.port, | 687 | if (ssh_connect(host, &hostaddr, options.port, |
686 | options.address_family, options.connection_attempts, | 688 | options.address_family, options.connection_attempts, &timeout_ms, |
689 | options.tcp_keep_alive, | ||
687 | #ifdef HAVE_CYGWIN | 690 | #ifdef HAVE_CYGWIN |
688 | options.use_privileged_port, | 691 | options.use_privileged_port, |
689 | #else | 692 | #else |
@@ -692,6 +695,9 @@ main(int ac, char **av) | |||
692 | options.proxy_command) != 0) | 695 | options.proxy_command) != 0) |
693 | exit(255); | 696 | exit(255); |
694 | 697 | ||
698 | if (timeout_ms > 0) | ||
699 | debug3("timeout: %d ms remain after connect", timeout_ms); | ||
700 | |||
695 | /* | 701 | /* |
696 | * If we successfully made the connection, load the host private key | 702 | * If we successfully made the connection, load the host private key |
697 | * in case we will need it later for combined rsa-rhosts | 703 | * in case we will need it later for combined rsa-rhosts |
@@ -767,7 +773,8 @@ main(int ac, char **av) | |||
767 | signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ | 773 | signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ |
768 | 774 | ||
769 | /* Log into the remote system. This never returns if the login fails. */ | 775 | /* Log into the remote system. This never returns if the login fails. */ |
770 | ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); | 776 | ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, |
777 | pw, timeout_ms); | ||
771 | 778 | ||
772 | /* We no longer need the private host keys. Clear them now. */ | 779 | /* We no longer need the private host keys. Clear them now. */ |
773 | if (sensitive_data.nkeys != 0) { | 780 | if (sensitive_data.nkeys != 0) { |
diff --git a/sshconnect.c b/sshconnect.c index 7e3c9fff4..933df39fa 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.201 2007/08/23 03:23:26 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.202 2007/09/04 11:15:55 djm 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 |
@@ -77,6 +77,23 @@ extern pid_t proxy_command_pid; | |||
77 | static int show_other_keys(const char *, Key *); | 77 | static int show_other_keys(const char *, Key *); |
78 | static void warn_changed_key(Key *); | 78 | static void warn_changed_key(Key *); |
79 | 79 | ||
80 | static void | ||
81 | ms_subtract_diff(struct timeval *start, int *ms) | ||
82 | { | ||
83 | struct timeval diff, finish; | ||
84 | |||
85 | gettimeofday(&finish, NULL); | ||
86 | timersub(&finish, start, &diff); | ||
87 | *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); | ||
88 | } | ||
89 | |||
90 | static void | ||
91 | ms_to_timeval(struct timeval *tv, int ms) | ||
92 | { | ||
93 | tv->tv_sec = ms / 1000; | ||
94 | tv->tv_usec = (ms % 1000) * 1000; | ||
95 | } | ||
96 | |||
80 | /* | 97 | /* |
81 | * Connect to the given ssh server using a proxy command. | 98 | * Connect to the given ssh server using a proxy command. |
82 | */ | 99 | */ |
@@ -223,30 +240,36 @@ ssh_create_socket(int privileged, struct addrinfo *ai) | |||
223 | 240 | ||
224 | static int | 241 | static int |
225 | timeout_connect(int sockfd, const struct sockaddr *serv_addr, | 242 | timeout_connect(int sockfd, const struct sockaddr *serv_addr, |
226 | socklen_t addrlen, int timeout) | 243 | socklen_t addrlen, int *timeoutp) |
227 | { | 244 | { |
228 | fd_set *fdset; | 245 | fd_set *fdset; |
229 | struct timeval tv; | 246 | struct timeval tv, t_start; |
230 | socklen_t optlen; | 247 | socklen_t optlen; |
231 | int optval, rc, result = -1; | 248 | int optval, rc, result = -1; |
232 | 249 | ||
233 | if (timeout <= 0) | 250 | gettimeofday(&t_start, NULL); |
234 | return (connect(sockfd, serv_addr, addrlen)); | 251 | |
252 | if (*timeoutp <= 0) { | ||
253 | result = connect(sockfd, serv_addr, addrlen); | ||
254 | goto done; | ||
255 | } | ||
235 | 256 | ||
236 | set_nonblock(sockfd); | 257 | set_nonblock(sockfd); |
237 | rc = connect(sockfd, serv_addr, addrlen); | 258 | rc = connect(sockfd, serv_addr, addrlen); |
238 | if (rc == 0) { | 259 | if (rc == 0) { |
239 | unset_nonblock(sockfd); | 260 | unset_nonblock(sockfd); |
240 | return (0); | 261 | result = 0; |
262 | goto done; | ||
263 | } | ||
264 | if (errno != EINPROGRESS) { | ||
265 | result = -1; | ||
266 | goto done; | ||
241 | } | 267 | } |
242 | if (errno != EINPROGRESS) | ||
243 | return (-1); | ||
244 | 268 | ||
245 | fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), | 269 | fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), |
246 | sizeof(fd_mask)); | 270 | sizeof(fd_mask)); |
247 | FD_SET(sockfd, fdset); | 271 | FD_SET(sockfd, fdset); |
248 | tv.tv_sec = timeout; | 272 | ms_to_timeval(&tv, *timeoutp); |
249 | tv.tv_usec = 0; | ||
250 | 273 | ||
251 | for (;;) { | 274 | for (;;) { |
252 | rc = select(sockfd + 1, NULL, fdset, NULL, &tv); | 275 | rc = select(sockfd + 1, NULL, fdset, NULL, &tv); |
@@ -285,6 +308,16 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, | |||
285 | } | 308 | } |
286 | 309 | ||
287 | xfree(fdset); | 310 | xfree(fdset); |
311 | |||
312 | done: | ||
313 | if (result == 0 && *timeoutp > 0) { | ||
314 | ms_subtract_diff(&t_start, timeoutp); | ||
315 | if (*timeoutp <= 0) { | ||
316 | errno = ETIMEDOUT; | ||
317 | result = -1; | ||
318 | } | ||
319 | } | ||
320 | |||
288 | return (result); | 321 | return (result); |
289 | } | 322 | } |
290 | 323 | ||
@@ -301,8 +334,8 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, | |||
301 | */ | 334 | */ |
302 | int | 335 | int |
303 | ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | 336 | ssh_connect(const char *host, struct sockaddr_storage * hostaddr, |
304 | u_short port, int family, int connection_attempts, | 337 | u_short port, int family, int connection_attempts, int *timeout_ms, |
305 | int needpriv, const char *proxy_command) | 338 | int want_keepalive, int needpriv, const char *proxy_command) |
306 | { | 339 | { |
307 | int gaierr; | 340 | int gaierr; |
308 | int on = 1; | 341 | int on = 1; |
@@ -355,7 +388,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
355 | continue; | 388 | continue; |
356 | 389 | ||
357 | if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, | 390 | if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, |
358 | options.connection_timeout) >= 0) { | 391 | timeout_ms) >= 0) { |
359 | /* Successful connection. */ | 392 | /* Successful connection. */ |
360 | memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); | 393 | memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); |
361 | break; | 394 | break; |
@@ -382,7 +415,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
382 | debug("Connection established."); | 415 | debug("Connection established."); |
383 | 416 | ||
384 | /* Set SO_KEEPALIVE if requested. */ | 417 | /* Set SO_KEEPALIVE if requested. */ |
385 | if (options.tcp_keep_alive && | 418 | if (want_keepalive && |
386 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, | 419 | setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, |
387 | sizeof(on)) < 0) | 420 | sizeof(on)) < 0) |
388 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); | 421 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); |
@@ -398,7 +431,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
398 | * identification string. | 431 | * identification string. |
399 | */ | 432 | */ |
400 | static void | 433 | static void |
401 | ssh_exchange_identification(void) | 434 | ssh_exchange_identification(int timeout_ms) |
402 | { | 435 | { |
403 | char buf[256], remote_version[256]; /* must be same size! */ | 436 | char buf[256], remote_version[256]; /* must be same size! */ |
404 | int remote_major, remote_minor, mismatch; | 437 | int remote_major, remote_minor, mismatch; |
@@ -406,16 +439,44 @@ ssh_exchange_identification(void) | |||
406 | int connection_out = packet_get_connection_out(); | 439 | int connection_out = packet_get_connection_out(); |
407 | int minor1 = PROTOCOL_MINOR_1; | 440 | int minor1 = PROTOCOL_MINOR_1; |
408 | u_int i, n; | 441 | u_int i, n; |
442 | size_t len; | ||
443 | int fdsetsz, remaining, rc; | ||
444 | struct timeval t_start, t_remaining; | ||
445 | fd_set *fdset; | ||
446 | |||
447 | fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask); | ||
448 | fdset = xcalloc(1, fdsetsz); | ||
409 | 449 | ||
410 | /* Read other side's version identification. */ | 450 | /* Read other side's version identification. */ |
451 | remaining = timeout_ms; | ||
411 | for (n = 0;;) { | 452 | for (n = 0;;) { |
412 | for (i = 0; i < sizeof(buf) - 1; i++) { | 453 | for (i = 0; i < sizeof(buf) - 1; i++) { |
413 | size_t len = atomicio(read, connection_in, &buf[i], 1); | 454 | if (timeout_ms > 0) { |
455 | gettimeofday(&t_start, NULL); | ||
456 | ms_to_timeval(&t_remaining, remaining); | ||
457 | FD_SET(connection_in, fdset); | ||
458 | rc = select(connection_in + 1, fdset, NULL, | ||
459 | fdset, &t_remaining); | ||
460 | ms_subtract_diff(&t_start, &remaining); | ||
461 | if (rc == 0 || remaining <= 0) | ||
462 | fatal("Connection timed out during " | ||
463 | "banner exchange"); | ||
464 | if (rc == -1) { | ||
465 | if (errno == EINTR) | ||
466 | continue; | ||
467 | fatal("ssh_exchange_identification: " | ||
468 | "select: %s", strerror(errno)); | ||
469 | } | ||
470 | } | ||
471 | |||
472 | len = atomicio(read, connection_in, &buf[i], 1); | ||
414 | 473 | ||
415 | if (len != 1 && errno == EPIPE) | 474 | if (len != 1 && errno == EPIPE) |
416 | fatal("ssh_exchange_identification: Connection closed by remote host"); | 475 | fatal("ssh_exchange_identification: " |
476 | "Connection closed by remote host"); | ||
417 | else if (len != 1) | 477 | else if (len != 1) |
418 | fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); | 478 | fatal("ssh_exchange_identification: " |
479 | "read: %.100s", strerror(errno)); | ||
419 | if (buf[i] == '\r') { | 480 | if (buf[i] == '\r') { |
420 | buf[i] = '\n'; | 481 | buf[i] = '\n'; |
421 | buf[i + 1] = 0; | 482 | buf[i + 1] = 0; |
@@ -426,7 +487,8 @@ ssh_exchange_identification(void) | |||
426 | break; | 487 | break; |
427 | } | 488 | } |
428 | if (++n > 65536) | 489 | if (++n > 65536) |
429 | fatal("ssh_exchange_identification: No banner received"); | 490 | fatal("ssh_exchange_identification: " |
491 | "No banner received"); | ||
430 | } | 492 | } |
431 | buf[sizeof(buf) - 1] = 0; | 493 | buf[sizeof(buf) - 1] = 0; |
432 | if (strncmp(buf, "SSH-", 4) == 0) | 494 | if (strncmp(buf, "SSH-", 4) == 0) |
@@ -434,6 +496,7 @@ ssh_exchange_identification(void) | |||
434 | debug("ssh_exchange_identification: %s", buf); | 496 | debug("ssh_exchange_identification: %s", buf); |
435 | } | 497 | } |
436 | server_version_string = xstrdup(buf); | 498 | server_version_string = xstrdup(buf); |
499 | xfree(fdset); | ||
437 | 500 | ||
438 | /* | 501 | /* |
439 | * Check that the versions match. In future this might accept | 502 | * Check that the versions match. In future this might accept |
@@ -946,7 +1009,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
946 | */ | 1009 | */ |
947 | void | 1010 | void |
948 | ssh_login(Sensitive *sensitive, const char *orighost, | 1011 | ssh_login(Sensitive *sensitive, const char *orighost, |
949 | struct sockaddr *hostaddr, struct passwd *pw) | 1012 | struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms) |
950 | { | 1013 | { |
951 | char *host, *cp; | 1014 | char *host, *cp; |
952 | char *server_user, *local_user; | 1015 | char *server_user, *local_user; |
@@ -961,7 +1024,7 @@ ssh_login(Sensitive *sensitive, const char *orighost, | |||
961 | *cp = (char)tolower(*cp); | 1024 | *cp = (char)tolower(*cp); |
962 | 1025 | ||
963 | /* Exchange protocol version identification strings with the server. */ | 1026 | /* Exchange protocol version identification strings with the server. */ |
964 | ssh_exchange_identification(); | 1027 | ssh_exchange_identification(timeout_ms); |
965 | 1028 | ||
966 | /* Put the connection into non-blocking mode. */ | 1029 | /* Put the connection into non-blocking mode. */ |
967 | packet_set_nonblocking(); | 1030 | packet_set_nonblocking(); |
diff --git a/sshconnect.h b/sshconnect.h index 4e66bbffc..75bde1a4d 100644 --- a/sshconnect.h +++ b/sshconnect.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.h,v 1.23 2006/08/03 03:34:42 deraadt Exp $ */ | 1 | /* $OpenBSD: sshconnect.h,v 1.24 2007/09/04 11:15:56 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -33,10 +33,10 @@ struct Sensitive { | |||
33 | 33 | ||
34 | int | 34 | int |
35 | ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, | 35 | ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, |
36 | int, const char *); | 36 | int *, int, int, const char *); |
37 | 37 | ||
38 | void | 38 | void |
39 | ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *); | 39 | ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *, int); |
40 | 40 | ||
41 | int verify_host_key(char *, struct sockaddr *, Key *); | 41 | int verify_host_key(char *, struct sockaddr *, Key *); |
42 | 42 | ||