summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c185
1 files changed, 157 insertions, 28 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 013a896b7..5c56f3178 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -13,7 +13,7 @@
13 */ 13 */
14 14
15#include "includes.h" 15#include "includes.h"
16RCSID("$OpenBSD: sshconnect.c,v 1.137 2002/11/21 23:03:51 deraadt Exp $"); 16RCSID("$OpenBSD: sshconnect.c,v 1.148 2003/09/18 07:52:54 markus Exp $");
17 17
18#include <openssl/bn.h> 18#include <openssl/bn.h>
19 19
@@ -33,9 +33,17 @@ RCSID("$OpenBSD: sshconnect.c,v 1.137 2002/11/21 23:03:51 deraadt Exp $");
33#include "misc.h" 33#include "misc.h"
34#include "readpass.h" 34#include "readpass.h"
35 35
36#ifdef DNS
37#include "dns.h"
38#endif
39
36char *client_version_string = NULL; 40char *client_version_string = NULL;
37char *server_version_string = NULL; 41char *server_version_string = NULL;
38 42
43#ifdef DNS
44int verified_host_key_dns = 0;
45#endif
46
39/* import */ 47/* import */
40extern Options options; 48extern Options options;
41extern char *__progname; 49extern char *__progname;
@@ -170,7 +178,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
170 * Creates a (possibly privileged) socket for use as the ssh connection. 178 * Creates a (possibly privileged) socket for use as the ssh connection.
171 */ 179 */
172static int 180static int
173ssh_create_socket(int privileged, int family) 181ssh_create_socket(int privileged, struct addrinfo *ai)
174{ 182{
175 int sock, gaierr; 183 int sock, gaierr;
176 struct addrinfo hints, *res; 184 struct addrinfo hints, *res;
@@ -182,15 +190,16 @@ ssh_create_socket(int privileged, int family)
182 if (privileged) { 190 if (privileged) {
183 int p = IPPORT_RESERVED - 1; 191 int p = IPPORT_RESERVED - 1;
184 PRIV_START; 192 PRIV_START;
185 sock = rresvport_af(&p, family); 193 sock = rresvport_af(&p, ai->ai_family);
186 PRIV_END; 194 PRIV_END;
187 if (sock < 0) 195 if (sock < 0)
188 error("rresvport: af=%d %.100s", family, strerror(errno)); 196 error("rresvport: af=%d %.100s", ai->ai_family,
197 strerror(errno));
189 else 198 else
190 debug("Allocated local port %d.", p); 199 debug("Allocated local port %d.", p);
191 return sock; 200 return sock;
192 } 201 }
193 sock = socket(family, SOCK_STREAM, 0); 202 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
194 if (sock < 0) 203 if (sock < 0)
195 error("socket: %.100s", strerror(errno)); 204 error("socket: %.100s", strerror(errno));
196 205
@@ -199,8 +208,9 @@ ssh_create_socket(int privileged, int family)
199 return sock; 208 return sock;
200 209
201 memset(&hints, 0, sizeof(hints)); 210 memset(&hints, 0, sizeof(hints));
202 hints.ai_family = family; 211 hints.ai_family = ai->ai_family;
203 hints.ai_socktype = SOCK_STREAM; 212 hints.ai_socktype = ai->ai_socktype;
213 hints.ai_protocol = ai->ai_protocol;
204 hints.ai_flags = AI_PASSIVE; 214 hints.ai_flags = AI_PASSIVE;
205 gaierr = getaddrinfo(options.bind_address, "0", &hints, &res); 215 gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
206 if (gaierr) { 216 if (gaierr) {
@@ -219,6 +229,74 @@ ssh_create_socket(int privileged, int family)
219 return sock; 229 return sock;
220} 230}
221 231
232static int
233timeout_connect(int sockfd, const struct sockaddr *serv_addr,
234 socklen_t addrlen, int timeout)
235{
236 fd_set *fdset;
237 struct timeval tv;
238 socklen_t optlen;
239 int fdsetsz, optval, rc, result = -1;
240
241 if (timeout <= 0)
242 return (connect(sockfd, serv_addr, addrlen));
243
244 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)
245 return (-1);
246
247 rc = connect(sockfd, serv_addr, addrlen);
248 if (rc == 0)
249 return (0);
250 if (errno != EINPROGRESS)
251 return (-1);
252
253 fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask);
254 fdset = (fd_set *)xmalloc(fdsetsz);
255
256 memset(fdset, 0, fdsetsz);
257 FD_SET(sockfd, fdset);
258 tv.tv_sec = timeout;
259 tv.tv_usec = 0;
260
261 for(;;) {
262 rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
263 if (rc != -1 || errno != EINTR)
264 break;
265 }
266
267 switch(rc) {
268 case 0:
269 /* Timed out */
270 errno = ETIMEDOUT;
271 break;
272 case -1:
273 /* Select error */
274 debug("select: %s", strerror(errno));
275 break;
276 case 1:
277 /* Completed or failed */
278 optval = 0;
279 optlen = sizeof(optval);
280 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
281 &optlen) == -1) {
282 debug("getsockopt: %s", strerror(errno));
283 break;
284 }
285 if (optval != 0) {
286 errno = optval;
287 break;
288 }
289 result = 0;
290 break;
291 default:
292 /* Should not occur */
293 fatal("Bogus return (%d) from select()", rc);
294 }
295
296 xfree(fdset);
297 return (result);
298}
299
222/* 300/*
223 * Opens a TCP/IP connection to the remote server on the given host. 301 * Opens a TCP/IP connection to the remote server on the given host.
224 * The address of the remote host will be returned in hostaddr. 302 * The address of the remote host will be returned in hostaddr.
@@ -302,12 +380,13 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
302 host, ntop, strport); 380 host, ntop, strport);
303 381
304 /* Create a socket for connecting. */ 382 /* Create a socket for connecting. */
305 sock = ssh_create_socket(needpriv, ai->ai_family); 383 sock = ssh_create_socket(needpriv, ai);
306 if (sock < 0) 384 if (sock < 0)
307 /* Any error is already output */ 385 /* Any error is already output */
308 continue; 386 continue;
309 387
310 if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { 388 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
389 options.connection_timeout) >= 0) {
311 /* Successful connection. */ 390 /* Successful connection. */
312 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 391 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
313 break; 392 break;
@@ -339,7 +418,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
339 418
340 /* Return failure if we didn't get a successful connection. */ 419 /* Return failure if we didn't get a successful connection. */
341 if (attempt >= connection_attempts) { 420 if (attempt >= connection_attempts) {
342 log("ssh: connect to host %s port %s: %s", 421 logit("ssh: connect to host %s port %s: %s",
343 host, strport, strerror(errno)); 422 host, strport, strerror(errno));
344 return full_failure ? ECONNABORTED : ECONNREFUSED; 423 return full_failure ? ECONNABORTED : ECONNREFUSED;
345 } 424 }
@@ -453,7 +532,7 @@ ssh_exchange_identification(void)
453 enable_compat13(); 532 enable_compat13();
454 minor1 = 3; 533 minor1 = 3;
455 if (options.forward_agent) { 534 if (options.forward_agent) {
456 log("Agent forwarding disabled for protocol 1.3"); 535 logit("Agent forwarding disabled for protocol 1.3");
457 options.forward_agent = 0; 536 options.forward_agent = 0;
458 } 537 }
459 } 538 }
@@ -477,7 +556,7 @@ ssh_exchange_identification(void)
477 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 556 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
478 compat20 ? PROTOCOL_MINOR_2 : minor1, 557 compat20 ? PROTOCOL_MINOR_2 : minor1,
479 SSH_VERSION); 558 SSH_VERSION);
480 if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf)) 559 if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf))
481 fatal("write: %.100s", strerror(errno)); 560 fatal("write: %.100s", strerror(errno));
482 client_version_string = xstrdup(buf); 561 client_version_string = xstrdup(buf);
483 chop(client_version_string); 562 chop(client_version_string);
@@ -528,7 +607,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
528 int salen; 607 int salen;
529 char ntop[NI_MAXHOST]; 608 char ntop[NI_MAXHOST];
530 char msg[1024]; 609 char msg[1024];
531 int len, host_line, ip_line, has_keys; 610 int len, host_line, ip_line;
532 const char *host_file = NULL, *ip_file = NULL; 611 const char *host_file = NULL, *ip_file = NULL;
533 612
534 /* 613 /*
@@ -644,16 +723,16 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
644 debug("Found key in %s:%d", host_file, host_line); 723 debug("Found key in %s:%d", host_file, host_line);
645 if (options.check_host_ip && ip_status == HOST_NEW) { 724 if (options.check_host_ip && ip_status == HOST_NEW) {
646 if (readonly) 725 if (readonly)
647 log("%s host key for IP address " 726 logit("%s host key for IP address "
648 "'%.128s' not in list of known hosts.", 727 "'%.128s' not in list of known hosts.",
649 type, ip); 728 type, ip);
650 else if (!add_host_to_hostfile(user_hostfile, ip, 729 else if (!add_host_to_hostfile(user_hostfile, ip,
651 host_key)) 730 host_key))
652 log("Failed to add the %s host key for IP " 731 logit("Failed to add the %s host key for IP "
653 "address '%.128s' to the list of known " 732 "address '%.128s' to the list of known "
654 "hosts (%.30s).", type, ip, user_hostfile); 733 "hosts (%.30s).", type, ip, user_hostfile);
655 else 734 else
656 log("Warning: Permanently added the %s host " 735 logit("Warning: Permanently added the %s host "
657 "key for IP address '%.128s' to the list " 736 "key for IP address '%.128s' to the list "
658 "of known hosts.", type, ip); 737 "of known hosts.", type, ip);
659 } 738 }
@@ -672,19 +751,36 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
672 "have requested strict checking.", type, host); 751 "have requested strict checking.", type, host);
673 goto fail; 752 goto fail;
674 } else if (options.strict_host_key_checking == 2) { 753 } else if (options.strict_host_key_checking == 2) {
675 has_keys = show_other_keys(host, host_key); 754 char msg1[1024], msg2[1024];
755
756 if (show_other_keys(host, host_key))
757 snprintf(msg1, sizeof(msg1),
758 "\nbut keys of different type are already"
759 " known for this host.");
760 else
761 snprintf(msg1, sizeof(msg1), ".");
676 /* The default */ 762 /* The default */
677 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 763 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
764 msg2[0] = '\0';
765#ifdef DNS
766 if (options.verify_host_key_dns) {
767 if (verified_host_key_dns)
768 snprintf(msg2, sizeof(msg2),
769 "Matching host key fingerprint"
770 " found in DNS.\n");
771 else
772 snprintf(msg2, sizeof(msg2),
773 "No matching host key fingerprint"
774 " found in DNS.\n");
775 }
776#endif
678 snprintf(msg, sizeof(msg), 777 snprintf(msg, sizeof(msg),
679 "The authenticity of host '%.200s (%s)' can't be " 778 "The authenticity of host '%.200s (%s)' can't be "
680 "established%s\n" 779 "established%s\n"
681 "%s key fingerprint is %s.\n" 780 "%s key fingerprint is %s.\n%s"
682 "Are you sure you want to continue connecting " 781 "Are you sure you want to continue connecting "
683 "(yes/no)? ", 782 "(yes/no)? ",
684 host, ip, 783 host, ip, msg1, type, fp, msg2);
685 has_keys ? ",\nbut keys of different type are already "
686 "known for this host." : ".",
687 type, fp);
688 xfree(fp); 784 xfree(fp);
689 if (!confirm(msg)) 785 if (!confirm(msg))
690 goto fail; 786 goto fail;
@@ -700,10 +796,10 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
700 * local known_hosts file. 796 * local known_hosts file.
701 */ 797 */
702 if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) 798 if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
703 log("Failed to add the host to the list of known " 799 logit("Failed to add the host to the list of known "
704 "hosts (%.500s).", user_hostfile); 800 "hosts (%.500s).", user_hostfile);
705 else 801 else
706 log("Warning: Permanently added '%.200s' (%s) to the " 802 logit("Warning: Permanently added '%.200s' (%s) to the "
707 "list of known hosts.", hostp, type); 803 "list of known hosts.", hostp, type);
708 break; 804 break;
709 case HOST_CHANGED: 805 case HOST_CHANGED:
@@ -754,7 +850,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
754 850
755 /* 851 /*
756 * If strict host key checking has not been requested, allow 852 * If strict host key checking has not been requested, allow
757 * the connection but without password authentication or 853 * the connection but without MITM-able authentication or
758 * agent forwarding. 854 * agent forwarding.
759 */ 855 */
760 if (options.password_authentication) { 856 if (options.password_authentication) {
@@ -762,6 +858,17 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
762 "man-in-the-middle attacks."); 858 "man-in-the-middle attacks.");
763 options.password_authentication = 0; 859 options.password_authentication = 0;
764 } 860 }
861 if (options.kbd_interactive_authentication) {
862 error("Keyboard-interactive authentication is disabled"
863 " to avoid man-in-the-middle attacks.");
864 options.kbd_interactive_authentication = 0;
865 options.challenge_response_authentication = 0;
866 }
867 if (options.challenge_response_authentication) {
868 error("Challenge/response authentication is disabled"
869 " to avoid man-in-the-middle attacks.");
870 options.challenge_response_authentication = 0;
871 }
765 if (options.forward_agent) { 872 if (options.forward_agent) {
766 error("Agent forwarding is disabled to avoid " 873 error("Agent forwarding is disabled to avoid "
767 "man-in-the-middle attacks."); 874 "man-in-the-middle attacks.");
@@ -806,7 +913,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
806 host_file, host_line); 913 host_file, host_line);
807 } 914 }
808 if (options.strict_host_key_checking == 1) { 915 if (options.strict_host_key_checking == 1) {
809 log(msg); 916 logit("%s", msg);
810 error("Exiting, you have requested strict checking."); 917 error("Exiting, you have requested strict checking.");
811 goto fail; 918 goto fail;
812 } else if (options.strict_host_key_checking == 2) { 919 } else if (options.strict_host_key_checking == 2) {
@@ -815,7 +922,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
815 if (!confirm(msg)) 922 if (!confirm(msg))
816 goto fail; 923 goto fail;
817 } else { 924 } else {
818 log(msg); 925 logit("%s", msg);
819 } 926 }
820 } 927 }
821 928
@@ -827,11 +934,33 @@ fail:
827 return -1; 934 return -1;
828} 935}
829 936
937/* returns 0 if key verifies or -1 if key does NOT verify */
830int 938int
831verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 939verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
832{ 940{
833 struct stat st; 941 struct stat st;
834 942
943#ifdef DNS
944 if (options.verify_host_key_dns) {
945 switch(verify_host_key_dns(host, hostaddr, host_key)) {
946 case DNS_VERIFY_OK:
947#ifdef DNSSEC
948 return 0;
949#else
950 verified_host_key_dns = 1;
951 break;
952#endif
953 case DNS_VERIFY_FAILED:
954 return -1;
955 case DNS_VERIFY_ERROR:
956 break;
957 default:
958 debug3("bad return value from verify_host_key_dns");
959 break;
960 }
961 }
962#endif /* DNS */
963
835 /* return ok if the key can be found in an old keyfile */ 964 /* return ok if the key can be found in an old keyfile */
836 if (stat(options.system_hostfile2, &st) == 0 || 965 if (stat(options.system_hostfile2, &st) == 0 ||
837 stat(options.user_hostfile2, &st) == 0) { 966 stat(options.user_hostfile2, &st) == 0) {
@@ -913,7 +1042,7 @@ show_key_from_file(const char *file, const char *host, int keytype)
913 if ((ret = lookup_key_in_hostfile_by_type(file, host, 1042 if ((ret = lookup_key_in_hostfile_by_type(file, host,
914 keytype, found, &line))) { 1043 keytype, found, &line))) {
915 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); 1044 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
916 log("WARNING: %s key found for host %s\n" 1045 logit("WARNING: %s key found for host %s\n"
917 "in %s:%d\n" 1046 "in %s:%d\n"
918 "%s key fingerprint %s.", 1047 "%s key fingerprint %s.",
919 key_type(found), host, file, line, 1048 key_type(found), host, file, line,