summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c278
1 files changed, 63 insertions, 215 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 6d819279e..fdcdcd855 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.305 2018/09/20 03:30:44 djm Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.314 2019/02/27 19:37:01 markus 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
@@ -68,9 +68,8 @@
68#include "authfile.h" 68#include "authfile.h"
69#include "ssherr.h" 69#include "ssherr.h"
70#include "authfd.h" 70#include "authfd.h"
71#include "kex.h"
71 72
72char *client_version_string = NULL;
73char *server_version_string = NULL;
74struct sshkey *previous_host_key = NULL; 73struct sshkey *previous_host_key = NULL;
75 74
76static int matching_host_key_dns = 0; 75static int matching_host_key_dns = 0;
@@ -78,6 +77,7 @@ static int matching_host_key_dns = 0;
78static pid_t proxy_command_pid = 0; 77static pid_t proxy_command_pid = 0;
79 78
80/* import */ 79/* import */
80extern int debug_flag;
81extern Options options; 81extern Options options;
82extern char *__progname; 82extern char *__progname;
83 83
@@ -99,6 +99,24 @@ expand_proxy_command(const char *proxy_command, const char *user,
99 return ret; 99 return ret;
100} 100}
101 101
102static void
103stderr_null(void)
104{
105 int devnull;
106
107 if ((devnull = open(_PATH_DEVNULL, O_WRONLY)) == -1) {
108 error("Can't open %s for stderr redirection: %s",
109 _PATH_DEVNULL, strerror(errno));
110 return;
111 }
112 if (devnull == STDERR_FILENO)
113 return;
114 if (dup2(devnull, STDERR_FILENO) == -1)
115 error("Cannot redirect stderr to %s", _PATH_DEVNULL);
116 if (devnull > STDERR_FILENO)
117 close(devnull);
118}
119
102/* 120/*
103 * Connect to the given ssh server using a proxy command that passes a 121 * Connect to the given ssh server using a proxy command that passes a
104 * a connected fd back to us. 122 * a connected fd back to us.
@@ -141,9 +159,13 @@ ssh_proxy_fdpass_connect(struct ssh *ssh, const char *host, u_short port,
141 close(sp[0]); 159 close(sp[0]);
142 160
143 /* 161 /*
144 * Stderr is left as it is so that error messages get 162 * Stderr is left for non-ControlPersist connections is so
145 * printed on the user's terminal. 163 * error messages may be printed on the user's terminal.
146 */ 164 */
165 if (!debug_flag && options.control_path != NULL &&
166 options.control_persist)
167 stderr_null();
168
147 argv[0] = shell; 169 argv[0] = shell;
148 argv[1] = "-c"; 170 argv[1] = "-c";
149 argv[2] = command_string; 171 argv[2] = command_string;
@@ -219,8 +241,14 @@ ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port,
219 /* Cannot be 1 because pin allocated two descriptors. */ 241 /* Cannot be 1 because pin allocated two descriptors. */
220 close(pout[1]); 242 close(pout[1]);
221 243
222 /* Stderr is left as it is so that error messages get 244 /*
223 printed on the user's terminal. */ 245 * Stderr is left for non-ControlPersist connections is so
246 * error messages may be printed on the user's terminal.
247 */
248 if (!debug_flag && options.control_path != NULL &&
249 options.control_persist)
250 stderr_null();
251
224 argv[0] = shell; 252 argv[0] = shell;
225 argv[1] = "-c"; 253 argv[1] = "-c";
226 argv[2] = command_string; 254 argv[2] = command_string;
@@ -369,10 +397,6 @@ ssh_create_socket(struct addrinfo *ai)
369 error("getaddrinfo: no addrs"); 397 error("getaddrinfo: no addrs");
370 goto fail; 398 goto fail;
371 } 399 }
372 if (res->ai_addrlen > sizeof(bindaddr)) {
373 error("%s: addr doesn't fit", __func__);
374 goto fail;
375 }
376 memcpy(&bindaddr, res->ai_addr, res->ai_addrlen); 400 memcpy(&bindaddr, res->ai_addr, res->ai_addrlen);
377 bindaddrlen = res->ai_addrlen; 401 bindaddrlen = res->ai_addrlen;
378 } else if (options.bind_interface != NULL) { 402 } else if (options.bind_interface != NULL) {
@@ -420,73 +444,6 @@ fail:
420} 444}
421 445
422/* 446/*
423 * Wait up to *timeoutp milliseconds for fd to be readable. Updates
424 * *timeoutp with time remaining.
425 * Returns 0 if fd ready or -1 on timeout or error (see errno).
426 */
427static int
428waitrfd(int fd, int *timeoutp)
429{
430 struct pollfd pfd;
431 struct timeval t_start;
432 int oerrno, r;
433
434 monotime_tv(&t_start);
435 pfd.fd = fd;
436 pfd.events = POLLIN;
437 for (; *timeoutp >= 0;) {
438 r = poll(&pfd, 1, *timeoutp);
439 oerrno = errno;
440 ms_subtract_diff(&t_start, timeoutp);
441 errno = oerrno;
442 if (r > 0)
443 return 0;
444 else if (r == -1 && errno != EAGAIN)
445 return -1;
446 else if (r == 0)
447 break;
448 }
449 /* timeout */
450 errno = ETIMEDOUT;
451 return -1;
452}
453
454static int
455timeout_connect(int sockfd, const struct sockaddr *serv_addr,
456 socklen_t addrlen, int *timeoutp)
457{
458 int optval = 0;
459 socklen_t optlen = sizeof(optval);
460
461 /* No timeout: just do a blocking connect() */
462 if (*timeoutp <= 0)
463 return connect(sockfd, serv_addr, addrlen);
464
465 set_nonblock(sockfd);
466 if (connect(sockfd, serv_addr, addrlen) == 0) {
467 /* Succeeded already? */
468 unset_nonblock(sockfd);
469 return 0;
470 } else if (errno != EINPROGRESS)
471 return -1;
472
473 if (waitrfd(sockfd, timeoutp) == -1)
474 return -1;
475
476 /* Completed or failed */
477 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
478 debug("getsockopt: %s", strerror(errno));
479 return -1;
480 }
481 if (optval != 0) {
482 errno = optval;
483 return -1;
484 }
485 unset_nonblock(sockfd);
486 return 0;
487}
488
489/*
490 * Opens a TCP/IP connection to the remote server on the given host. 447 * Opens a TCP/IP connection to the remote server on the given host.
491 * The address of the remote host will be returned in hostaddr. 448 * The address of the remote host will be returned in hostaddr.
492 * If port is 0, the default port will be used. 449 * If port is 0, the default port will be used.
@@ -500,7 +457,7 @@ ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
500 struct sockaddr_storage *hostaddr, u_short port, int family, 457 struct sockaddr_storage *hostaddr, u_short port, int family,
501 int connection_attempts, int *timeout_ms, int want_keepalive) 458 int connection_attempts, int *timeout_ms, int want_keepalive)
502{ 459{
503 int on = 1; 460 int on = 1, saved_timeout_ms = *timeout_ms;
504 int oerrno, sock = -1, attempt; 461 int oerrno, sock = -1, attempt;
505 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 462 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
506 struct addrinfo *ai; 463 struct addrinfo *ai;
@@ -544,6 +501,7 @@ ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
544 continue; 501 continue;
545 } 502 }
546 503
504 *timeout_ms = saved_timeout_ms;
547 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 505 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
548 timeout_ms) >= 0) { 506 timeout_ms) >= 0) {
549 /* Successful connection. */ 507 /* Successful connection. */
@@ -589,12 +547,20 @@ ssh_connect(struct ssh *ssh, const char *host, struct addrinfo *addrs,
589 struct sockaddr_storage *hostaddr, u_short port, int family, 547 struct sockaddr_storage *hostaddr, u_short port, int family,
590 int connection_attempts, int *timeout_ms, int want_keepalive) 548 int connection_attempts, int *timeout_ms, int want_keepalive)
591{ 549{
550 int in, out;
551
592 if (options.proxy_command == NULL) { 552 if (options.proxy_command == NULL) {
593 return ssh_connect_direct(ssh, host, addrs, hostaddr, port, 553 return ssh_connect_direct(ssh, host, addrs, hostaddr, port,
594 family, connection_attempts, timeout_ms, want_keepalive); 554 family, connection_attempts, timeout_ms, want_keepalive);
595 } else if (strcmp(options.proxy_command, "-") == 0) { 555 } else if (strcmp(options.proxy_command, "-") == 0) {
596 if ((ssh_packet_set_connection(ssh, 556 if ((in = dup(STDIN_FILENO)) < 0 ||
597 STDIN_FILENO, STDOUT_FILENO)) == NULL) 557 (out = dup(STDOUT_FILENO)) < 0) {
558 if (in >= 0)
559 close(in);
560 error("%s: dup() in/out failed", __func__);
561 return -1; /* ssh_packet_set_connection logs error */
562 }
563 if ((ssh_packet_set_connection(ssh, in, out)) == NULL)
598 return -1; /* ssh_packet_set_connection logs error */ 564 return -1; /* ssh_packet_set_connection logs error */
599 return 0; 565 return 0;
600 } else if (options.proxy_use_fdpass) { 566 } else if (options.proxy_use_fdpass) {
@@ -604,128 +570,26 @@ ssh_connect(struct ssh *ssh, const char *host, struct addrinfo *addrs,
604 return ssh_proxy_connect(ssh, host, port, options.proxy_command); 570 return ssh_proxy_connect(ssh, host, port, options.proxy_command);
605} 571}
606 572
607static void
608send_client_banner(int connection_out, int minor1)
609{
610 /* Send our own protocol version identification. */
611 xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
612 PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
613 if (atomicio(vwrite, connection_out, client_version_string,
614 strlen(client_version_string)) != strlen(client_version_string))
615 fatal("write: %.100s", strerror(errno));
616 chop(client_version_string);
617 debug("Local version string %.100s", client_version_string);
618}
619
620/*
621 * Waits for the server identification string, and sends our own
622 * identification string.
623 */
624void
625ssh_exchange_identification(int timeout_ms)
626{
627 char buf[256], remote_version[256]; /* must be same size! */
628 int remote_major, remote_minor, mismatch;
629 int connection_in = packet_get_connection_in();
630 int connection_out = packet_get_connection_out();
631 u_int i, n;
632 size_t len;
633 int rc;
634
635 send_client_banner(connection_out, 0);
636
637 /* Read other side's version identification. */
638 for (n = 0;;) {
639 for (i = 0; i < sizeof(buf) - 1; i++) {
640 if (timeout_ms > 0) {
641 rc = waitrfd(connection_in, &timeout_ms);
642 if (rc == -1 && errno == ETIMEDOUT) {
643 fatal("Connection timed out during "
644 "banner exchange");
645 } else if (rc == -1) {
646 fatal("%s: %s",
647 __func__, strerror(errno));
648 }
649 }
650
651 len = atomicio(read, connection_in, &buf[i], 1);
652 if (len != 1 && errno == EPIPE)
653 fatal("ssh_exchange_identification: "
654 "Connection closed by remote host");
655 else if (len != 1)
656 fatal("ssh_exchange_identification: "
657 "read: %.100s", strerror(errno));
658 if (buf[i] == '\r') {
659 buf[i] = '\n';
660 buf[i + 1] = 0;
661 continue; /**XXX wait for \n */
662 }
663 if (buf[i] == '\n') {
664 buf[i + 1] = 0;
665 break;
666 }
667 if (++n > 65536)
668 fatal("ssh_exchange_identification: "
669 "No banner received");
670 }
671 buf[sizeof(buf) - 1] = 0;
672 if (strncmp(buf, "SSH-", 4) == 0)
673 break;
674 debug("ssh_exchange_identification: %s", buf);
675 }
676 server_version_string = xstrdup(buf);
677
678 /*
679 * Check that the versions match. In future this might accept
680 * several versions and set appropriate flags to handle them.
681 */
682 if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
683 &remote_major, &remote_minor, remote_version) != 3)
684 fatal("Bad remote protocol version identification: '%.100s'", buf);
685 debug("Remote protocol version %d.%d, remote software version %.100s",
686 remote_major, remote_minor, remote_version);
687
688 active_state->compat = compat_datafellows(remote_version);
689 mismatch = 0;
690
691 switch (remote_major) {
692 case 2:
693 break;
694 case 1:
695 if (remote_minor != 99)
696 mismatch = 1;
697 break;
698 default:
699 mismatch = 1;
700 break;
701 }
702 if (mismatch)
703 fatal("Protocol major versions differ: %d vs. %d",
704 PROTOCOL_MAJOR_2, remote_major);
705 if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
706 logit("Server version \"%.100s\" uses unsafe RSA signature "
707 "scheme; disabling use of RSA keys", remote_version);
708 chop(server_version_string);
709}
710
711/* defaults to 'no' */ 573/* defaults to 'no' */
712static int 574static int
713confirm(const char *prompt) 575confirm(const char *prompt, const char *fingerprint)
714{ 576{
715 const char *msg, *again = "Please type 'yes' or 'no': "; 577 const char *msg, *again = "Please type 'yes' or 'no': ";
578 const char *again_fp = "Please type 'yes', 'no' or the fingerprint: ";
716 char *p; 579 char *p;
717 int ret = -1; 580 int ret = -1;
718 581
719 if (options.batch_mode) 582 if (options.batch_mode)
720 return 0; 583 return 0;
721 for (msg = prompt;;msg = again) { 584 for (msg = prompt;;msg = fingerprint ? again_fp : again) {
722 p = read_passphrase(msg, RP_ECHO); 585 p = read_passphrase(msg, RP_ECHO);
723 if (p == NULL) 586 if (p == NULL)
724 return 0; 587 return 0;
725 p[strcspn(p, "\n")] = '\0'; 588 p[strcspn(p, "\n")] = '\0';
726 if (p[0] == '\0' || strcasecmp(p, "no") == 0) 589 if (p[0] == '\0' || strcasecmp(p, "no") == 0)
727 ret = 0; 590 ret = 0;
728 else if (strcasecmp(p, "yes") == 0) 591 else if (strcasecmp(p, "yes") == 0 || (fingerprint != NULL &&
592 strcasecmp(p, fingerprint) == 0))
729 ret = 1; 593 ret = 1;
730 free(p); 594 free(p);
731 if (ret != -1) 595 if (ret != -1)
@@ -853,7 +717,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
853 char msg[1024]; 717 char msg[1024];
854 const char *type; 718 const char *type;
855 const struct hostkey_entry *host_found, *ip_found; 719 const struct hostkey_entry *host_found, *ip_found;
856 int len, cancelled_forwarding = 0; 720 int len, cancelled_forwarding = 0, confirmed;
857 int local = sockaddr_is_local(hostaddr); 721 int local = sockaddr_is_local(hostaddr);
858 int r, want_cert = sshkey_is_cert(host_key), host_ip_differ = 0; 722 int r, want_cert = sshkey_is_cert(host_key), host_ip_differ = 0;
859 int hostkey_trusted = 0; /* Known or explicitly accepted by user */ 723 int hostkey_trusted = 0; /* Known or explicitly accepted by user */
@@ -1028,14 +892,15 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1028 "established%s\n" 892 "established%s\n"
1029 "%s key fingerprint is %s.%s%s\n%s" 893 "%s key fingerprint is %s.%s%s\n%s"
1030 "Are you sure you want to continue connecting " 894 "Are you sure you want to continue connecting "
1031 "(yes/no)? ", 895 "(yes/no/[fingerprint])? ",
1032 host, ip, msg1, type, fp, 896 host, ip, msg1, type, fp,
1033 options.visual_host_key ? "\n" : "", 897 options.visual_host_key ? "\n" : "",
1034 options.visual_host_key ? ra : "", 898 options.visual_host_key ? ra : "",
1035 msg2); 899 msg2);
1036 free(ra); 900 free(ra);
901 confirmed = confirm(msg, fp);
1037 free(fp); 902 free(fp);
1038 if (!confirm(msg)) 903 if (!confirmed)
1039 goto fail; 904 goto fail;
1040 hostkey_trusted = 1; /* user explicitly confirmed */ 905 hostkey_trusted = 1; /* user explicitly confirmed */
1041 } 906 }
@@ -1229,7 +1094,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1229 SSH_STRICT_HOSTKEY_ASK) { 1094 SSH_STRICT_HOSTKEY_ASK) {
1230 strlcat(msg, "\nAre you sure you want " 1095 strlcat(msg, "\nAre you sure you want "
1231 "to continue connecting (yes/no)? ", sizeof(msg)); 1096 "to continue connecting (yes/no)? ", sizeof(msg));
1232 if (!confirm(msg)) 1097 if (!confirm(msg, NULL))
1233 goto fail; 1098 goto fail;
1234 } else if (options.strict_host_key_checking != 1099 } else if (options.strict_host_key_checking !=
1235 SSH_STRICT_HOSTKEY_OFF) { 1100 SSH_STRICT_HOSTKEY_OFF) {
@@ -1401,7 +1266,7 @@ out:
1401 * This function does not require super-user privileges. 1266 * This function does not require super-user privileges.
1402 */ 1267 */
1403void 1268void
1404ssh_login(Sensitive *sensitive, const char *orighost, 1269ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost,
1405 struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms) 1270 struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
1406{ 1271{
1407 char *host; 1272 char *host;
@@ -1415,37 +1280,20 @@ ssh_login(Sensitive *sensitive, const char *orighost,
1415 lowercase(host); 1280 lowercase(host);
1416 1281
1417 /* Exchange protocol version identification strings with the server. */ 1282 /* Exchange protocol version identification strings with the server. */
1418 ssh_exchange_identification(timeout_ms); 1283 if (kex_exchange_identification(ssh, timeout_ms, NULL) != 0)
1284 cleanup_exit(255); /* error already logged */
1419 1285
1420 /* Put the connection into non-blocking mode. */ 1286 /* Put the connection into non-blocking mode. */
1421 packet_set_nonblocking(); 1287 ssh_packet_set_nonblocking(ssh);
1422 1288
1423 /* key exchange */ 1289 /* key exchange */
1424 /* authenticate user */ 1290 /* authenticate user */
1425 debug("Authenticating to %s:%d as '%s'", host, port, server_user); 1291 debug("Authenticating to %s:%d as '%s'", host, port, server_user);
1426 ssh_kex2(host, hostaddr, port); 1292 ssh_kex2(ssh, host, hostaddr, port);
1427 ssh_userauth2(local_user, server_user, host, sensitive); 1293 ssh_userauth2(ssh, local_user, server_user, host, sensitive);
1428 free(local_user); 1294 free(local_user);
1429} 1295}
1430 1296
1431void
1432ssh_put_password(char *password)
1433{
1434 int size;
1435 char *padded;
1436
1437 if (datafellows & SSH_BUG_PASSWORDPAD) {
1438 packet_put_cstring(password);
1439 return;
1440 }
1441 size = ROUNDUP(strlen(password) + 1, 32);
1442 padded = xcalloc(1, size);
1443 strlcpy(padded, password, size);
1444 packet_put_string(padded, size);
1445 explicit_bzero(padded, size);
1446 free(padded);
1447}
1448
1449/* print all known host keys for a given host, but skip keys of given type */ 1297/* print all known host keys for a given host, but skip keys of given type */
1450static int 1298static int
1451show_other_keys(struct hostkeys *hostkeys, struct sshkey *key) 1299show_other_keys(struct hostkeys *hostkeys, struct sshkey *key)