summaryrefslogtreecommitdiffstats
path: root/usr.bin/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r--usr.bin/ssh/ssh.c15
-rw-r--r--usr.bin/ssh/sshconnect.c105
-rw-r--r--usr.bin/ssh/sshconnect.h6
3 files changed, 98 insertions, 28 deletions
diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index db350e2cbb4..dcdfee558ea 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.302 2007/09/04 03:21:03 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.303 2007/09/04 11:15:55 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -202,7 +202,7 @@ main(int ac, char **av)
char *p, *cp, *line, buf[256];
struct stat st;
struct passwd *pw;
- int dummy;
+ int dummy, timeout_ms;
extern int optind, optreset;
extern char *optarg;
struct servent *sp;
@@ -666,13 +666,19 @@ main(int ac, char **av)
if (options.control_path != NULL)
control_client(options.control_path);
+ timeout_ms = options.connection_timeout * 1000;
+
/* Open a connection to the remote host. */
if (ssh_connect(host, &hostaddr, options.port,
- options.address_family, options.connection_attempts,
+ options.address_family, options.connection_attempts, &timeout_ms,
+ options.tcp_keep_alive,
original_effective_uid == 0 && options.use_privileged_port,
options.proxy_command) != 0)
exit(255);
+ if (timeout_ms > 0)
+ debug3("timeout: %d ms remain after connect", timeout_ms);
+
/*
* If we successfully made the connection, load the host private key
* in case we will need it later for combined rsa-rhosts
@@ -748,7 +754,8 @@ main(int ac, char **av)
signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
/* Log into the remote system. This never returns if the login fails. */
- ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw);
+ ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
+ pw, timeout_ms);
/* We no longer need the private host keys. Clear them now. */
if (sensitive_data.nkeys != 0) {
diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c
index cb0eeab0be7..760fbb6b03a 100644
--- a/usr.bin/ssh/sshconnect.c
+++ b/usr.bin/ssh/sshconnect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.201 2007/08/23 03:23:26 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.202 2007/09/04 11:15:55 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -64,6 +64,23 @@ extern pid_t proxy_command_pid;
static int show_other_keys(const char *, Key *);
static void warn_changed_key(Key *);
+static void
+ms_subtract_diff(struct timeval *start, int *ms)
+{
+ struct timeval diff, finish;
+
+ gettimeofday(&finish, NULL);
+ timersub(&finish, start, &diff);
+ *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
+}
+
+static void
+ms_to_timeval(struct timeval *tv, int ms)
+{
+ tv->tv_sec = ms / 1000;
+ tv->tv_usec = (ms % 1000) * 1000;
+}
+
/*
* Connect to the given ssh server using a proxy command.
*/
@@ -210,30 +227,36 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
static int
timeout_connect(int sockfd, const struct sockaddr *serv_addr,
- socklen_t addrlen, int timeout)
+ socklen_t addrlen, int *timeoutp)
{
fd_set *fdset;
- struct timeval tv;
+ struct timeval tv, t_start;
socklen_t optlen;
int optval, rc, result = -1;
- if (timeout <= 0)
- return (connect(sockfd, serv_addr, addrlen));
+ gettimeofday(&t_start, NULL);
+
+ if (*timeoutp <= 0) {
+ result = connect(sockfd, serv_addr, addrlen);
+ goto done;
+ }
set_nonblock(sockfd);
rc = connect(sockfd, serv_addr, addrlen);
if (rc == 0) {
unset_nonblock(sockfd);
- return (0);
+ result = 0;
+ goto done;
+ }
+ if (errno != EINPROGRESS) {
+ result = -1;
+ goto done;
}
- if (errno != EINPROGRESS)
- return (-1);
fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
sizeof(fd_mask));
FD_SET(sockfd, fdset);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
+ ms_to_timeval(&tv, *timeoutp);
for (;;) {
rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
@@ -272,6 +295,16 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
}
xfree(fdset);
+
+ done:
+ if (result == 0 && *timeoutp > 0) {
+ ms_subtract_diff(&t_start, timeoutp);
+ if (*timeoutp <= 0) {
+ errno = ETIMEDOUT;
+ result = -1;
+ }
+ }
+
return (result);
}
@@ -288,8 +321,8 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
*/
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
- u_short port, int family, int connection_attempts,
- int needpriv, const char *proxy_command)
+ u_short port, int family, int connection_attempts, int *timeout_ms,
+ int want_keepalive, int needpriv, const char *proxy_command)
{
int gaierr;
int on = 1;
@@ -342,7 +375,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
continue;
if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
- options.connection_timeout) >= 0) {
+ timeout_ms) >= 0) {
/* Successful connection. */
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
break;
@@ -369,7 +402,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
debug("Connection established.");
/* Set SO_KEEPALIVE if requested. */
- if (options.tcp_keep_alive &&
+ if (want_keepalive &&
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
sizeof(on)) < 0)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
@@ -385,7 +418,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* identification string.
*/
static void
-ssh_exchange_identification(void)
+ssh_exchange_identification(int timeout_ms)
{
char buf[256], remote_version[256]; /* must be same size! */
int remote_major, remote_minor, mismatch;
@@ -393,16 +426,44 @@ ssh_exchange_identification(void)
int connection_out = packet_get_connection_out();
int minor1 = PROTOCOL_MINOR_1;
u_int i, n;
+ size_t len;
+ int fdsetsz, remaining, rc;
+ struct timeval t_start, t_remaining;
+ fd_set *fdset;
+
+ fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
+ fdset = xcalloc(1, fdsetsz);
/* Read other side's version identification. */
+ remaining = timeout_ms;
for (n = 0;;) {
for (i = 0; i < sizeof(buf) - 1; i++) {
- size_t len = atomicio(read, connection_in, &buf[i], 1);
+ if (timeout_ms > 0) {
+ gettimeofday(&t_start, NULL);
+ ms_to_timeval(&t_remaining, remaining);
+ FD_SET(connection_in, fdset);
+ rc = select(connection_in + 1, fdset, NULL,
+ fdset, &t_remaining);
+ ms_subtract_diff(&t_start, &remaining);
+ if (rc == 0 || remaining <= 0)
+ fatal("Connection timed out during "
+ "banner exchange");
+ if (rc == -1) {
+ if (errno == EINTR)
+ continue;
+ fatal("ssh_exchange_identification: "
+ "select: %s", strerror(errno));
+ }
+ }
+
+ len = atomicio(read, connection_in, &buf[i], 1);
if (len != 1 && errno == EPIPE)
- fatal("ssh_exchange_identification: Connection closed by remote host");
+ fatal("ssh_exchange_identification: "
+ "Connection closed by remote host");
else if (len != 1)
- fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
+ fatal("ssh_exchange_identification: "
+ "read: %.100s", strerror(errno));
if (buf[i] == '\r') {
buf[i] = '\n';
buf[i + 1] = 0;
@@ -413,7 +474,8 @@ ssh_exchange_identification(void)
break;
}
if (++n > 65536)
- fatal("ssh_exchange_identification: No banner received");
+ fatal("ssh_exchange_identification: "
+ "No banner received");
}
buf[sizeof(buf) - 1] = 0;
if (strncmp(buf, "SSH-", 4) == 0)
@@ -421,6 +483,7 @@ ssh_exchange_identification(void)
debug("ssh_exchange_identification: %s", buf);
}
server_version_string = xstrdup(buf);
+ xfree(fdset);
/*
* Check that the versions match. In future this might accept
@@ -929,7 +992,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
*/
void
ssh_login(Sensitive *sensitive, const char *orighost,
- struct sockaddr *hostaddr, struct passwd *pw)
+ struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms)
{
char *host, *cp;
char *server_user, *local_user;
@@ -944,7 +1007,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
*cp = (char)tolower(*cp);
/* Exchange protocol version identification strings with the server. */
- ssh_exchange_identification();
+ ssh_exchange_identification(timeout_ms);
/* Put the connection into non-blocking mode. */
packet_set_nonblocking();
diff --git a/usr.bin/ssh/sshconnect.h b/usr.bin/ssh/sshconnect.h
index 4e66bbffc97..75bde1a4db1 100644
--- a/usr.bin/ssh/sshconnect.h
+++ b/usr.bin/ssh/sshconnect.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.h,v 1.23 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: sshconnect.h,v 1.24 2007/09/04 11:15:56 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -33,10 +33,10 @@ struct Sensitive {
int
ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
- int, const char *);
+ int *, int, int, const char *);
void
-ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *);
+ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *, int);
int verify_host_key(char *, struct sockaddr *, Key *);