summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c152
1 files changed, 93 insertions, 59 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 64ffec240..a222233d0 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,3 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.200 2006/10/10 10:12:45 markus Exp $ */
1/* 2/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -13,12 +14,35 @@
13 */ 14 */
14 15
15#include "includes.h" 16#include "includes.h"
16RCSID("$OpenBSD: sshconnect.c,v 1.171 2005/12/06 22:38:27 reyk Exp $");
17 17
18#include <openssl/bn.h> 18#include <sys/types.h>
19#include <sys/wait.h>
20#include <sys/stat.h>
21#include <sys/socket.h>
22#ifdef HAVE_SYS_TIME_H
23# include <sys/time.h>
24#endif
25
26#include <netinet/in.h>
27#include <arpa/inet.h>
28
29#include <ctype.h>
30#include <errno.h>
31#include <netdb.h>
32#ifdef HAVE_PATHS_H
33#include <paths.h>
34#endif
35#include <pwd.h>
36#include <stdarg.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
19 41
20#include "ssh.h"
21#include "xmalloc.h" 42#include "xmalloc.h"
43#include "key.h"
44#include "hostfile.h"
45#include "ssh.h"
22#include "rsa.h" 46#include "rsa.h"
23#include "buffer.h" 47#include "buffer.h"
24#include "packet.h" 48#include "packet.h"
@@ -32,6 +56,7 @@ RCSID("$OpenBSD: sshconnect.c,v 1.171 2005/12/06 22:38:27 reyk Exp $");
32#include "atomicio.h" 56#include "atomicio.h"
33#include "misc.h" 57#include "misc.h"
34#include "dns.h" 58#include "dns.h"
59#include "version.h"
35 60
36char *client_version_string = NULL; 61char *client_version_string = NULL;
37char *server_version_string = NULL; 62char *server_version_string = NULL;
@@ -62,7 +87,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
62 int pin[2], pout[2]; 87 int pin[2], pout[2];
63 pid_t pid; 88 pid_t pid;
64 char strport[NI_MAXSERV]; 89 char strport[NI_MAXSERV];
65 size_t len;
66 90
67 /* Convert the port number into a string. */ 91 /* Convert the port number into a string. */
68 snprintf(strport, sizeof strport, "%hu", port); 92 snprintf(strport, sizeof strport, "%hu", port);
@@ -74,10 +98,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
74 * Use "exec" to avoid "sh -c" processes on some platforms 98 * Use "exec" to avoid "sh -c" processes on some platforms
75 * (e.g. Solaris) 99 * (e.g. Solaris)
76 */ 100 */
77 len = strlen(proxy_command) + 6; 101 xasprintf(&tmp, "exec %s", proxy_command);
78 tmp = xmalloc(len);
79 strlcpy(tmp, "exec ", len);
80 strlcat(tmp, proxy_command, len);
81 command_string = percent_expand(tmp, "h", host, 102 command_string = percent_expand(tmp, "h", host,
82 "p", strport, (char *)NULL); 103 "p", strport, (char *)NULL);
83 xfree(tmp); 104 xfree(tmp);
@@ -94,8 +115,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
94 char *argv[10]; 115 char *argv[10];
95 116
96 /* Child. Permanently give up superuser privileges. */ 117 /* Child. Permanently give up superuser privileges. */
97 seteuid(original_real_uid); 118 permanently_drop_suid(original_real_uid);
98 setuid(original_real_uid);
99 119
100 /* Redirect stdin and stdout. */ 120 /* Redirect stdin and stdout. */
101 close(pin[1]); 121 close(pin[1]);
@@ -205,7 +225,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
205 fd_set *fdset; 225 fd_set *fdset;
206 struct timeval tv; 226 struct timeval tv;
207 socklen_t optlen; 227 socklen_t optlen;
208 int fdsetsz, optval, rc, result = -1; 228 int optval, rc, result = -1;
209 229
210 if (timeout <= 0) 230 if (timeout <= 0)
211 return (connect(sockfd, serv_addr, addrlen)); 231 return (connect(sockfd, serv_addr, addrlen));
@@ -219,10 +239,8 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
219 if (errno != EINPROGRESS) 239 if (errno != EINPROGRESS)
220 return (-1); 240 return (-1);
221 241
222 fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask); 242 fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
223 fdset = (fd_set *)xmalloc(fdsetsz); 243 sizeof(fd_mask));
224
225 memset(fdset, 0, fdsetsz);
226 FD_SET(sockfd, fdset); 244 FD_SET(sockfd, fdset);
227 tv.tv_sec = timeout; 245 tv.tv_sec = timeout;
228 tv.tv_usec = 0; 246 tv.tv_usec = 0;
@@ -305,17 +323,16 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
305 fatal("%s: %.100s: %s", __progname, host, 323 fatal("%s: %.100s: %s", __progname, host,
306 gai_strerror(gaierr)); 324 gai_strerror(gaierr));
307 325
308 /* 326 for (attempt = 0; attempt < connection_attempts; attempt++) {
309 * Try to connect several times. On some machines, the first time 327 if (attempt > 0) {
310 * will sometimes fail. In general socket code appears to behave 328 /* Sleep a moment before retrying. */
311 * quite magically on many machines. 329 sleep(1);
312 */
313 for (attempt = 0; ;) {
314 if (attempt > 0)
315 debug("Trying again..."); 330 debug("Trying again...");
316 331 }
317 /* Loop through addresses for this host, and try each one in 332 /*
318 sequence until the connection succeeds. */ 333 * Loop through addresses for this host, and try each one in
334 * sequence until the connection succeeds.
335 */
319 for (ai = aitop; ai; ai = ai->ai_next) { 336 for (ai = aitop; ai; ai = ai->ai_next) {
320 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 337 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
321 continue; 338 continue;
@@ -342,29 +359,18 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
342 } else { 359 } else {
343 debug("connect to address %s port %s: %s", 360 debug("connect to address %s port %s: %s",
344 ntop, strport, strerror(errno)); 361 ntop, strport, strerror(errno));
345 /*
346 * Close the failed socket; there appear to
347 * be some problems when reusing a socket for
348 * which connect() has already returned an
349 * error.
350 */
351 close(sock); 362 close(sock);
363 sock = -1;
352 } 364 }
353 } 365 }
354 if (ai) 366 if (sock != -1)
355 break; /* Successful connection. */ 367 break; /* Successful connection. */
356
357 attempt++;
358 if (attempt >= connection_attempts)
359 break;
360 /* Sleep a moment before retrying. */
361 sleep(1);
362 } 368 }
363 369
364 freeaddrinfo(aitop); 370 freeaddrinfo(aitop);
365 371
366 /* Return failure if we didn't get a successful connection. */ 372 /* Return failure if we didn't get a successful connection. */
367 if (attempt >= connection_attempts) { 373 if (sock == -1) {
368 error("ssh: connect to host %s port %s: %s", 374 error("ssh: connect to host %s port %s: %s",
369 host, strport, strerror(errno)); 375 host, strport, strerror(errno));
370 return (-1); 376 return (-1);
@@ -396,10 +402,10 @@ ssh_exchange_identification(void)
396 int connection_in = packet_get_connection_in(); 402 int connection_in = packet_get_connection_in();
397 int connection_out = packet_get_connection_out(); 403 int connection_out = packet_get_connection_out();
398 int minor1 = PROTOCOL_MINOR_1; 404 int minor1 = PROTOCOL_MINOR_1;
399 u_int i; 405 u_int i, n;
400 406
401 /* Read other side's version identification. */ 407 /* Read other side's version identification. */
402 for (;;) { 408 for (n = 0;;) {
403 for (i = 0; i < sizeof(buf) - 1; i++) { 409 for (i = 0; i < sizeof(buf) - 1; i++) {
404 size_t len = atomicio(read, connection_in, &buf[i], 1); 410 size_t len = atomicio(read, connection_in, &buf[i], 1);
405 411
@@ -416,6 +422,8 @@ ssh_exchange_identification(void)
416 buf[i + 1] = 0; 422 buf[i + 1] = 0;
417 break; 423 break;
418 } 424 }
425 if (++n > 65536)
426 fatal("ssh_exchange_identification: No banner received");
419 } 427 }
420 buf[sizeof(buf) - 1] = 0; 428 buf[sizeof(buf) - 1] = 0;
421 if (strncmp(buf, "SSH-", 4) == 0) 429 if (strncmp(buf, "SSH-", 4) == 0)
@@ -517,13 +525,17 @@ confirm(const char *prompt)
517 * check whether the supplied host key is valid, return -1 if the key 525 * check whether the supplied host key is valid, return -1 if the key
518 * is not valid. the user_hostfile will not be updated if 'readonly' is true. 526 * is not valid. the user_hostfile will not be updated if 'readonly' is true.
519 */ 527 */
528#define RDRW 0
529#define RDONLY 1
530#define ROQUIET 2
520static int 531static int
521check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, 532check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
522 int readonly, const char *user_hostfile, const char *system_hostfile) 533 Key *host_key, int readonly, const char *user_hostfile,
534 const char *system_hostfile)
523{ 535{
524 Key *file_key; 536 Key *file_key;
525 const char *type = key_type(host_key); 537 const char *type = key_type(host_key);
526 char *ip = NULL; 538 char *ip = NULL, *host = NULL;
527 char hostline[1000], *hostp, *fp; 539 char hostline[1000], *hostp, *fp;
528 HostStatus host_status; 540 HostStatus host_status;
529 HostStatus ip_status; 541 HostStatus ip_status;
@@ -574,7 +586,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
574 if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop), 586 if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
575 NULL, 0, NI_NUMERICHOST) != 0) 587 NULL, 0, NI_NUMERICHOST) != 0)
576 fatal("check_host_key: getnameinfo failed"); 588 fatal("check_host_key: getnameinfo failed");
577 ip = xstrdup(ntop); 589 ip = put_host_port(ntop, port);
578 } else { 590 } else {
579 ip = xstrdup("<no hostip for proxy command>"); 591 ip = xstrdup("<no hostip for proxy command>");
580 } 592 }
@@ -582,18 +594,21 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
582 * Turn off check_host_ip if the connection is to localhost, via proxy 594 * Turn off check_host_ip if the connection is to localhost, via proxy
583 * command or if we don't have a hostname to compare with 595 * command or if we don't have a hostname to compare with
584 */ 596 */
585 if (options.check_host_ip && 597 if (options.check_host_ip && (local ||
586 (local || strcmp(host, ip) == 0 || options.proxy_command != NULL)) 598 strcmp(hostname, ip) == 0 || options.proxy_command != NULL))
587 options.check_host_ip = 0; 599 options.check_host_ip = 0;
588 600
589 /* 601 /*
590 * Allow the user to record the key under a different name. This is 602 * Allow the user to record the key under a different name or
591 * useful for ssh tunneling over forwarded connections or if you run 603 * differentiate a non-standard port. This is useful for ssh
592 * multiple sshd's on different ports on the same machine. 604 * tunneling over forwarded connections or if you run multiple
605 * sshd's on different ports on the same machine.
593 */ 606 */
594 if (options.host_key_alias != NULL) { 607 if (options.host_key_alias != NULL) {
595 host = options.host_key_alias; 608 host = xstrdup(options.host_key_alias);
596 debug("using hostkeyalias: %s", host); 609 debug("using hostkeyalias: %s", host);
610 } else {
611 host = put_host_port(hostname, port);
597 } 612 }
598 613
599 /* 614 /*
@@ -662,6 +677,15 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
662 } 677 }
663 break; 678 break;
664 case HOST_NEW: 679 case HOST_NEW:
680 if (options.host_key_alias == NULL && port != 0 &&
681 port != SSH_DEFAULT_PORT) {
682 debug("checking without port identifier");
683 if (check_host_key(hostname, hostaddr, 0, host_key, 2,
684 user_hostfile, system_hostfile) == 0) {
685 debug("found matching key w/out port");
686 break;
687 }
688 }
665 if (readonly) 689 if (readonly)
666 goto fail; 690 goto fail;
667 /* The host is new. */ 691 /* The host is new. */
@@ -741,6 +765,8 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
741 "list of known hosts.", hostp, type); 765 "list of known hosts.", hostp, type);
742 break; 766 break;
743 case HOST_CHANGED: 767 case HOST_CHANGED:
768 if (readonly == ROQUIET)
769 goto fail;
744 if (options.check_host_ip && host_ip_differ) { 770 if (options.check_host_ip && host_ip_differ) {
745 char *key_msg; 771 char *key_msg;
746 if (ip_status == HOST_NEW) 772 if (ip_status == HOST_NEW)
@@ -779,7 +805,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
779 /* 805 /*
780 * If strict host key checking has not been requested, allow 806 * If strict host key checking has not been requested, allow
781 * the connection but without MITM-able authentication or 807 * the connection but without MITM-able authentication or
782 * agent forwarding. 808 * forwarding.
783 */ 809 */
784 if (options.password_authentication) { 810 if (options.password_authentication) {
785 error("Password authentication is disabled to avoid " 811 error("Password authentication is disabled to avoid "
@@ -814,6 +840,11 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
814 options.num_local_forwards = 840 options.num_local_forwards =
815 options.num_remote_forwards = 0; 841 options.num_remote_forwards = 0;
816 } 842 }
843 if (options.tun_open != SSH_TUNMODE_NO) {
844 error("Tunnel forwarding is disabled to avoid "
845 "man-in-the-middle attacks.");
846 options.tun_open = SSH_TUNMODE_NO;
847 }
817 /* 848 /*
818 * XXX Should permit the user to change to use the new id. 849 * XXX Should permit the user to change to use the new id.
819 * This could be done by converting the host key to an 850 * This could be done by converting the host key to an
@@ -855,10 +886,12 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
855 } 886 }
856 887
857 xfree(ip); 888 xfree(ip);
889 xfree(host);
858 return 0; 890 return 0;
859 891
860fail: 892fail:
861 xfree(ip); 893 xfree(ip);
894 xfree(host);
862 return -1; 895 return -1;
863} 896}
864 897
@@ -892,12 +925,13 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
892 /* return ok if the key can be found in an old keyfile */ 925 /* return ok if the key can be found in an old keyfile */
893 if (stat(options.system_hostfile2, &st) == 0 || 926 if (stat(options.system_hostfile2, &st) == 0 ||
894 stat(options.user_hostfile2, &st) == 0) { 927 stat(options.user_hostfile2, &st) == 0) {
895 if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1, 928 if (check_host_key(host, hostaddr, options.port, host_key,
896 options.user_hostfile2, options.system_hostfile2) == 0) 929 RDONLY, options.user_hostfile2,
930 options.system_hostfile2) == 0)
897 return 0; 931 return 0;
898 } 932 }
899 return check_host_key(host, hostaddr, host_key, /*readonly*/ 0, 933 return check_host_key(host, hostaddr, options.port, host_key,
900 options.user_hostfile, options.system_hostfile); 934 RDRW, options.user_hostfile, options.system_hostfile);
901} 935}
902 936
903/* 937/*
@@ -921,7 +955,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
921 host = xstrdup(orighost); 955 host = xstrdup(orighost);
922 for (cp = host; *cp; cp++) 956 for (cp = host; *cp; cp++)
923 if (isupper(*cp)) 957 if (isupper(*cp))
924 *cp = tolower(*cp); 958 *cp = (char)tolower(*cp);
925 959
926 /* Exchange protocol version identification strings with the server. */ 960 /* Exchange protocol version identification strings with the server. */
927 ssh_exchange_identification(); 961 ssh_exchange_identification();
@@ -938,6 +972,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
938 ssh_kex(host, hostaddr); 972 ssh_kex(host, hostaddr);
939 ssh_userauth1(local_user, server_user, host, sensitive); 973 ssh_userauth1(local_user, server_user, host, sensitive);
940 } 974 }
975 xfree(local_user);
941} 976}
942 977
943void 978void
@@ -951,8 +986,7 @@ ssh_put_password(char *password)
951 return; 986 return;
952 } 987 }
953 size = roundup(strlen(password) + 1, 32); 988 size = roundup(strlen(password) + 1, 32);
954 padded = xmalloc(size); 989 padded = xcalloc(1, size);
955 memset(padded, 0, size);
956 strlcpy(padded, password, size); 990 strlcpy(padded, password, size);
957 packet_put_string(padded, size); 991 packet_put_string(padded, size);
958 memset(padded, 0, size); 992 memset(padded, 0, size);