diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 57 |
1 files changed, 50 insertions, 7 deletions
diff --git a/sshconnect.c b/sshconnect.c index ba7b9b71e..10eaac35d 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -50,6 +50,13 @@ extern pid_t proxy_command_pid; | |||
50 | #define INET6_ADDRSTRLEN 46 | 50 | #define INET6_ADDRSTRLEN 46 |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | static sig_atomic_t banner_timedout; | ||
54 | |||
55 | static void banner_alarm_catch (int signum) | ||
56 | { | ||
57 | banner_timedout = 1; | ||
58 | } | ||
59 | |||
53 | static int show_other_keys(const char *, Key *); | 60 | static int show_other_keys(const char *, Key *); |
54 | static void warn_changed_key(Key *); | 61 | static void warn_changed_key(Key *); |
55 | 62 | ||
@@ -138,7 +145,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
138 | xfree(command_string); | 145 | xfree(command_string); |
139 | 146 | ||
140 | /* Set the connection file descriptors. */ | 147 | /* Set the connection file descriptors. */ |
141 | packet_set_connection(pout[0], pin[1]); | 148 | packet_set_connection(pout[0], pin[1], options.setuptimeout); |
142 | 149 | ||
143 | /* Indicate OK return */ | 150 | /* Indicate OK return */ |
144 | return 0; | 151 | return 0; |
@@ -380,7 +387,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
380 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); | 387 | error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); |
381 | 388 | ||
382 | /* Set the connection. */ | 389 | /* Set the connection. */ |
383 | packet_set_connection(sock, sock); | 390 | packet_set_connection(sock, sock, options.setuptimeout); |
384 | 391 | ||
385 | return 0; | 392 | return 0; |
386 | } | 393 | } |
@@ -398,16 +405,39 @@ ssh_exchange_identification(void) | |||
398 | int connection_out = packet_get_connection_out(); | 405 | int connection_out = packet_get_connection_out(); |
399 | int minor1 = PROTOCOL_MINOR_1; | 406 | int minor1 = PROTOCOL_MINOR_1; |
400 | u_int i; | 407 | u_int i; |
408 | struct sigaction sa, osa; | ||
401 | 409 | ||
402 | /* Read other side's version identification. */ | 410 | /* Read other side's version identification. |
411 | * If SetupTimeOut has been set, give up after | ||
412 | * the specified amount of time | ||
413 | */ | ||
414 | if(options.setuptimeout > 0){ | ||
415 | memset(&sa, 0, sizeof(sa)); | ||
416 | sa.sa_handler = banner_alarm_catch; | ||
417 | /*throw away any pending alarms, since we'd block otherwise*/ | ||
418 | alarm(0); | ||
419 | sigaction(SIGALRM, &sa, &osa); | ||
420 | alarm(options.setuptimeout); | ||
421 | } | ||
403 | for (;;) { | 422 | for (;;) { |
404 | for (i = 0; i < sizeof(buf) - 1; i++) { | 423 | for (i = 0; i < sizeof(buf) - 1; ) { |
405 | size_t len = atomicio(read, connection_in, &buf[i], 1); | 424 | ssize_t len = read(connection_in, &buf[i], 1); |
425 | if (banner_timedout) | ||
426 | fatal("ssh_exchange_identification: Timeout waiting for version information."); | ||
427 | if (len == 0) | ||
428 | errno = EPIPE; | ||
406 | 429 | ||
407 | if (len != 1 && errno == EPIPE) | 430 | if (len != 1 && errno == EPIPE) |
408 | fatal("ssh_exchange_identification: Connection closed by remote host"); | 431 | fatal("ssh_exchange_identification: Connection closed by remote host"); |
409 | else if (len != 1) | 432 | else if (len != 1) { |
433 | #ifdef EWOULDBLOCK | ||
434 | if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) | ||
435 | #else | ||
436 | if (errno == EINTR || errno == EAGAIN) | ||
437 | #endif | ||
438 | continue; | ||
410 | fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); | 439 | fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); |
440 | } | ||
411 | if (buf[i] == '\r') { | 441 | if (buf[i] == '\r') { |
412 | buf[i] = '\n'; | 442 | buf[i] = '\n'; |
413 | buf[i + 1] = 0; | 443 | buf[i + 1] = 0; |
@@ -417,6 +447,11 @@ ssh_exchange_identification(void) | |||
417 | buf[i + 1] = 0; | 447 | buf[i + 1] = 0; |
418 | break; | 448 | break; |
419 | } | 449 | } |
450 | if (buf[i] == '\r') { | ||
451 | buf[i] = '\n'; | ||
452 | buf[i + 1] = 0; /**XXX wait for \n */ | ||
453 | } | ||
454 | i++; | ||
420 | } | 455 | } |
421 | buf[sizeof(buf) - 1] = 0; | 456 | buf[sizeof(buf) - 1] = 0; |
422 | if (strncmp(buf, "SSH-", 4) == 0) | 457 | if (strncmp(buf, "SSH-", 4) == 0) |
@@ -425,6 +460,14 @@ ssh_exchange_identification(void) | |||
425 | } | 460 | } |
426 | server_version_string = xstrdup(buf); | 461 | server_version_string = xstrdup(buf); |
427 | 462 | ||
463 | /* If SetupTimeOut has been set, unset the alarm now, and | ||
464 | * put the correct handler for SIGALRM back. | ||
465 | */ | ||
466 | if (options.setuptimeout > 0) { | ||
467 | alarm(0); | ||
468 | sigaction(SIGALRM,&osa,NULL); | ||
469 | } | ||
470 | |||
428 | /* | 471 | /* |
429 | * Check that the versions match. In future this might accept | 472 | * Check that the versions match. In future this might accept |
430 | * several versions and set appropriate flags to handle them. | 473 | * several versions and set appropriate flags to handle them. |
@@ -480,7 +523,7 @@ ssh_exchange_identification(void) | |||
480 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", | 523 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", |
481 | compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, | 524 | compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, |
482 | compat20 ? PROTOCOL_MINOR_2 : minor1, | 525 | compat20 ? PROTOCOL_MINOR_2 : minor1, |
483 | SSH_VERSION); | 526 | SSH_RELEASE); |
484 | if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) | 527 | if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) |
485 | fatal("write: %.100s", strerror(errno)); | 528 | fatal("write: %.100s", strerror(errno)); |
486 | client_version_string = xstrdup(buf); | 529 | client_version_string = xstrdup(buf); |