summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c185
1 files changed, 28 insertions, 157 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 5c56f3178..013a896b7 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.148 2003/09/18 07:52:54 markus Exp $"); 16RCSID("$OpenBSD: sshconnect.c,v 1.137 2002/11/21 23:03:51 deraadt Exp $");
17 17
18#include <openssl/bn.h> 18#include <openssl/bn.h>
19 19
@@ -33,17 +33,9 @@ RCSID("$OpenBSD: sshconnect.c,v 1.148 2003/09/18 07:52:54 markus 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
40char *client_version_string = NULL; 36char *client_version_string = NULL;
41char *server_version_string = NULL; 37char *server_version_string = NULL;
42 38
43#ifdef DNS
44int verified_host_key_dns = 0;
45#endif
46
47/* import */ 39/* import */
48extern Options options; 40extern Options options;
49extern char *__progname; 41extern char *__progname;
@@ -178,7 +170,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
178 * Creates a (possibly privileged) socket for use as the ssh connection. 170 * Creates a (possibly privileged) socket for use as the ssh connection.
179 */ 171 */
180static int 172static int
181ssh_create_socket(int privileged, struct addrinfo *ai) 173ssh_create_socket(int privileged, int family)
182{ 174{
183 int sock, gaierr; 175 int sock, gaierr;
184 struct addrinfo hints, *res; 176 struct addrinfo hints, *res;
@@ -190,16 +182,15 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
190 if (privileged) { 182 if (privileged) {
191 int p = IPPORT_RESERVED - 1; 183 int p = IPPORT_RESERVED - 1;
192 PRIV_START; 184 PRIV_START;
193 sock = rresvport_af(&p, ai->ai_family); 185 sock = rresvport_af(&p, family);
194 PRIV_END; 186 PRIV_END;
195 if (sock < 0) 187 if (sock < 0)
196 error("rresvport: af=%d %.100s", ai->ai_family, 188 error("rresvport: af=%d %.100s", family, strerror(errno));
197 strerror(errno));
198 else 189 else
199 debug("Allocated local port %d.", p); 190 debug("Allocated local port %d.", p);
200 return sock; 191 return sock;
201 } 192 }
202 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 193 sock = socket(family, SOCK_STREAM, 0);
203 if (sock < 0) 194 if (sock < 0)
204 error("socket: %.100s", strerror(errno)); 195 error("socket: %.100s", strerror(errno));
205 196
@@ -208,9 +199,8 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
208 return sock; 199 return sock;
209 200
210 memset(&hints, 0, sizeof(hints)); 201 memset(&hints, 0, sizeof(hints));
211 hints.ai_family = ai->ai_family; 202 hints.ai_family = family;
212 hints.ai_socktype = ai->ai_socktype; 203 hints.ai_socktype = SOCK_STREAM;
213 hints.ai_protocol = ai->ai_protocol;
214 hints.ai_flags = AI_PASSIVE; 204 hints.ai_flags = AI_PASSIVE;
215 gaierr = getaddrinfo(options.bind_address, "0", &hints, &res); 205 gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
216 if (gaierr) { 206 if (gaierr) {
@@ -229,74 +219,6 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
229 return sock; 219 return sock;
230} 220}
231 221
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
300/* 222/*
301 * Opens a TCP/IP connection to the remote server on the given host. 223 * Opens a TCP/IP connection to the remote server on the given host.
302 * The address of the remote host will be returned in hostaddr. 224 * The address of the remote host will be returned in hostaddr.
@@ -380,13 +302,12 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
380 host, ntop, strport); 302 host, ntop, strport);
381 303
382 /* Create a socket for connecting. */ 304 /* Create a socket for connecting. */
383 sock = ssh_create_socket(needpriv, ai); 305 sock = ssh_create_socket(needpriv, ai->ai_family);
384 if (sock < 0) 306 if (sock < 0)
385 /* Any error is already output */ 307 /* Any error is already output */
386 continue; 308 continue;
387 309
388 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 310 if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
389 options.connection_timeout) >= 0) {
390 /* Successful connection. */ 311 /* Successful connection. */
391 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 312 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
392 break; 313 break;
@@ -418,7 +339,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
418 339
419 /* Return failure if we didn't get a successful connection. */ 340 /* Return failure if we didn't get a successful connection. */
420 if (attempt >= connection_attempts) { 341 if (attempt >= connection_attempts) {
421 logit("ssh: connect to host %s port %s: %s", 342 log("ssh: connect to host %s port %s: %s",
422 host, strport, strerror(errno)); 343 host, strport, strerror(errno));
423 return full_failure ? ECONNABORTED : ECONNREFUSED; 344 return full_failure ? ECONNABORTED : ECONNREFUSED;
424 } 345 }
@@ -532,7 +453,7 @@ ssh_exchange_identification(void)
532 enable_compat13(); 453 enable_compat13();
533 minor1 = 3; 454 minor1 = 3;
534 if (options.forward_agent) { 455 if (options.forward_agent) {
535 logit("Agent forwarding disabled for protocol 1.3"); 456 log("Agent forwarding disabled for protocol 1.3");
536 options.forward_agent = 0; 457 options.forward_agent = 0;
537 } 458 }
538 } 459 }
@@ -556,7 +477,7 @@ ssh_exchange_identification(void)
556 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 477 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
557 compat20 ? PROTOCOL_MINOR_2 : minor1, 478 compat20 ? PROTOCOL_MINOR_2 : minor1,
558 SSH_VERSION); 479 SSH_VERSION);
559 if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) 480 if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
560 fatal("write: %.100s", strerror(errno)); 481 fatal("write: %.100s", strerror(errno));
561 client_version_string = xstrdup(buf); 482 client_version_string = xstrdup(buf);
562 chop(client_version_string); 483 chop(client_version_string);
@@ -607,7 +528,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
607 int salen; 528 int salen;
608 char ntop[NI_MAXHOST]; 529 char ntop[NI_MAXHOST];
609 char msg[1024]; 530 char msg[1024];
610 int len, host_line, ip_line; 531 int len, host_line, ip_line, has_keys;
611 const char *host_file = NULL, *ip_file = NULL; 532 const char *host_file = NULL, *ip_file = NULL;
612 533
613 /* 534 /*
@@ -723,16 +644,16 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
723 debug("Found key in %s:%d", host_file, host_line); 644 debug("Found key in %s:%d", host_file, host_line);
724 if (options.check_host_ip && ip_status == HOST_NEW) { 645 if (options.check_host_ip && ip_status == HOST_NEW) {
725 if (readonly) 646 if (readonly)
726 logit("%s host key for IP address " 647 log("%s host key for IP address "
727 "'%.128s' not in list of known hosts.", 648 "'%.128s' not in list of known hosts.",
728 type, ip); 649 type, ip);
729 else if (!add_host_to_hostfile(user_hostfile, ip, 650 else if (!add_host_to_hostfile(user_hostfile, ip,
730 host_key)) 651 host_key))
731 logit("Failed to add the %s host key for IP " 652 log("Failed to add the %s host key for IP "
732 "address '%.128s' to the list of known " 653 "address '%.128s' to the list of known "
733 "hosts (%.30s).", type, ip, user_hostfile); 654 "hosts (%.30s).", type, ip, user_hostfile);
734 else 655 else
735 logit("Warning: Permanently added the %s host " 656 log("Warning: Permanently added the %s host "
736 "key for IP address '%.128s' to the list " 657 "key for IP address '%.128s' to the list "
737 "of known hosts.", type, ip); 658 "of known hosts.", type, ip);
738 } 659 }
@@ -751,36 +672,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
751 "have requested strict checking.", type, host); 672 "have requested strict checking.", type, host);
752 goto fail; 673 goto fail;
753 } else if (options.strict_host_key_checking == 2) { 674 } else if (options.strict_host_key_checking == 2) {
754 char msg1[1024], msg2[1024]; 675 has_keys = show_other_keys(host, host_key);
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), ".");
762 /* The default */ 676 /* The default */
763 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 677 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
777 snprintf(msg, sizeof(msg), 678 snprintf(msg, sizeof(msg),
778 "The authenticity of host '%.200s (%s)' can't be " 679 "The authenticity of host '%.200s (%s)' can't be "
779 "established%s\n" 680 "established%s\n"
780 "%s key fingerprint is %s.\n%s" 681 "%s key fingerprint is %s.\n"
781 "Are you sure you want to continue connecting " 682 "Are you sure you want to continue connecting "
782 "(yes/no)? ", 683 "(yes/no)? ",
783 host, ip, msg1, type, fp, msg2); 684 host, ip,
685 has_keys ? ",\nbut keys of different type are already "
686 "known for this host." : ".",
687 type, fp);
784 xfree(fp); 688 xfree(fp);
785 if (!confirm(msg)) 689 if (!confirm(msg))
786 goto fail; 690 goto fail;
@@ -796,10 +700,10 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
796 * local known_hosts file. 700 * local known_hosts file.
797 */ 701 */
798 if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) 702 if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
799 logit("Failed to add the host to the list of known " 703 log("Failed to add the host to the list of known "
800 "hosts (%.500s).", user_hostfile); 704 "hosts (%.500s).", user_hostfile);
801 else 705 else
802 logit("Warning: Permanently added '%.200s' (%s) to the " 706 log("Warning: Permanently added '%.200s' (%s) to the "
803 "list of known hosts.", hostp, type); 707 "list of known hosts.", hostp, type);
804 break; 708 break;
805 case HOST_CHANGED: 709 case HOST_CHANGED:
@@ -850,7 +754,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
850 754
851 /* 755 /*
852 * If strict host key checking has not been requested, allow 756 * If strict host key checking has not been requested, allow
853 * the connection but without MITM-able authentication or 757 * the connection but without password authentication or
854 * agent forwarding. 758 * agent forwarding.
855 */ 759 */
856 if (options.password_authentication) { 760 if (options.password_authentication) {
@@ -858,17 +762,6 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
858 "man-in-the-middle attacks."); 762 "man-in-the-middle attacks.");
859 options.password_authentication = 0; 763 options.password_authentication = 0;
860 } 764 }
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 }
872 if (options.forward_agent) { 765 if (options.forward_agent) {
873 error("Agent forwarding is disabled to avoid " 766 error("Agent forwarding is disabled to avoid "
874 "man-in-the-middle attacks."); 767 "man-in-the-middle attacks.");
@@ -913,7 +806,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
913 host_file, host_line); 806 host_file, host_line);
914 } 807 }
915 if (options.strict_host_key_checking == 1) { 808 if (options.strict_host_key_checking == 1) {
916 logit("%s", msg); 809 log(msg);
917 error("Exiting, you have requested strict checking."); 810 error("Exiting, you have requested strict checking.");
918 goto fail; 811 goto fail;
919 } else if (options.strict_host_key_checking == 2) { 812 } else if (options.strict_host_key_checking == 2) {
@@ -922,7 +815,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
922 if (!confirm(msg)) 815 if (!confirm(msg))
923 goto fail; 816 goto fail;
924 } else { 817 } else {
925 logit("%s", msg); 818 log(msg);
926 } 819 }
927 } 820 }
928 821
@@ -934,33 +827,11 @@ fail:
934 return -1; 827 return -1;
935} 828}
936 829
937/* returns 0 if key verifies or -1 if key does NOT verify */
938int 830int
939verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 831verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
940{ 832{
941 struct stat st; 833 struct stat st;
942 834
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
964 /* return ok if the key can be found in an old keyfile */ 835 /* return ok if the key can be found in an old keyfile */
965 if (stat(options.system_hostfile2, &st) == 0 || 836 if (stat(options.system_hostfile2, &st) == 0 ||
966 stat(options.user_hostfile2, &st) == 0) { 837 stat(options.user_hostfile2, &st) == 0) {
@@ -1042,7 +913,7 @@ show_key_from_file(const char *file, const char *host, int keytype)
1042 if ((ret = lookup_key_in_hostfile_by_type(file, host, 913 if ((ret = lookup_key_in_hostfile_by_type(file, host,
1043 keytype, found, &line))) { 914 keytype, found, &line))) {
1044 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); 915 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
1045 logit("WARNING: %s key found for host %s\n" 916 log("WARNING: %s key found for host %s\n"
1046 "in %s:%d\n" 917 "in %s:%d\n"
1047 "%s key fingerprint %s.", 918 "%s key fingerprint %s.",
1048 key_type(found), host, file, line, 919 key_type(found), host, file, line,