summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c105
1 files changed, 84 insertions, 21 deletions
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;
77static int show_other_keys(const char *, Key *); 77static int show_other_keys(const char *, Key *);
78static void warn_changed_key(Key *); 78static void warn_changed_key(Key *);
79 79
80static void
81ms_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
90static void
91ms_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
224static int 241static int
225timeout_connect(int sockfd, const struct sockaddr *serv_addr, 242timeout_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 */
302int 335int
303ssh_connect(const char *host, struct sockaddr_storage * hostaddr, 336ssh_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 */
400static void 433static void
401ssh_exchange_identification(void) 434ssh_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 */
947void 1010void
948ssh_login(Sensitive *sensitive, const char *orighost, 1011ssh_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();