summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2011-01-24 12:43:25 +0000
committerColin Watson <cjwatson@debian.org>2011-01-24 12:43:25 +0000
commit626f1d986ff72aa514da63e34744e1de9cf21b9a (patch)
treed215a5280bc2e57251e4a9e08bfd3674ad824a94 /sshconnect.c
parent6ed622cb6fe8f71bbe0d998cdd12280410bfb420 (diff)
parent0970072c89b079b022538e3c366fbfa2c53fc821 (diff)
* New upstream release (http://www.openssh.org/txt/release-5.7):
- Implement Elliptic Curve Cryptography modes for key exchange (ECDH) and host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA offer better performance than plain DH and DSA at the same equivalent symmetric key length, as well as much shorter keys. - sftp(1)/sftp-server(8): add a protocol extension to support a hard link operation. It is available through the "ln" command in the client. The old "ln" behaviour of creating a symlink is available using its "-s" option or through the preexisting "symlink" command. - scp(1): Add a new -3 option to scp: Copies between two remote hosts are transferred through the local host (closes: #508613). - ssh(1): "atomically" create the listening mux socket by binding it on a temporary name and then linking it into position after listen() has succeeded. This allows the mux clients to determine that the server socket is either ready or stale without races (closes: #454784). Stale server sockets are now automatically removed (closes: #523250). - ssh(1): install a SIGCHLD handler to reap expired child process (closes: #594687). - ssh(1)/ssh-agent(1): honour $TMPDIR for client xauth and ssh-agent temporary directories (closes: #357469, although only if you arrange for ssh-agent to actually see $TMPDIR since the setgid bit will cause it to be stripped off).
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c322
1 files changed, 177 insertions, 145 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 5b2da9136..1c066b641 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.224 2010/04/16 21:14:27 djm Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.232 2011/01/16 11:50:36 djm 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
@@ -34,6 +34,7 @@
34#include <paths.h> 34#include <paths.h>
35#endif 35#endif
36#include <pwd.h> 36#include <pwd.h>
37#include <signal.h>
37#include <stdarg.h> 38#include <stdarg.h>
38#include <stdio.h> 39#include <stdio.h>
39#include <stdlib.h> 40#include <stdlib.h>
@@ -66,14 +67,15 @@ char *server_version_string = NULL;
66 67
67static int matching_host_key_dns = 0; 68static int matching_host_key_dns = 0;
68 69
70static pid_t proxy_command_pid = 0;
71
69/* import */ 72/* import */
70extern Options options; 73extern Options options;
71extern char *__progname; 74extern char *__progname;
72extern uid_t original_real_uid; 75extern uid_t original_real_uid;
73extern uid_t original_effective_uid; 76extern uid_t original_effective_uid;
74extern pid_t proxy_command_pid;
75 77
76static int show_other_keys(const char *, Key *); 78static int show_other_keys(struct hostkeys *, Key *);
77static void warn_changed_key(Key *); 79static void warn_changed_key(Key *);
78 80
79/* 81/*
@@ -87,7 +89,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
87 pid_t pid; 89 pid_t pid;
88 char *shell, strport[NI_MAXSERV]; 90 char *shell, strport[NI_MAXSERV];
89 91
90 if ((shell = getenv("SHELL")) == NULL) 92 if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
91 shell = _PATH_BSHELL; 93 shell = _PATH_BSHELL;
92 94
93 /* Convert the port number into a string. */ 95 /* Convert the port number into a string. */
@@ -141,6 +143,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
141 143
142 /* Execute the proxy command. Note that we gave up any 144 /* Execute the proxy command. Note that we gave up any
143 extra privileges above. */ 145 extra privileges above. */
146 signal(SIGPIPE, SIG_DFL);
144 execvp(argv[0], argv); 147 execvp(argv[0], argv);
145 perror(argv[0]); 148 perror(argv[0]);
146 exit(1); 149 exit(1);
@@ -167,6 +170,17 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
167 return 0; 170 return 0;
168} 171}
169 172
173void
174ssh_kill_proxy_command(void)
175{
176 /*
177 * Send SIGHUP to proxy command if used. We don't wait() in
178 * case it hangs and instead rely on init to reap the child
179 */
180 if (proxy_command_pid > 1)
181 kill(proxy_command_pid, SIGHUP);
182}
183
170/* 184/*
171 * Creates a (possibly privileged) socket for use as the ssh connection. 185 * Creates a (possibly privileged) socket for use as the ssh connection.
172 */ 186 */
@@ -594,6 +608,79 @@ check_host_cert(const char *host, const Key *host_key)
594 return 1; 608 return 1;
595} 609}
596 610
611static int
612sockaddr_is_local(struct sockaddr *hostaddr)
613{
614 switch (hostaddr->sa_family) {
615 case AF_INET:
616 return (ntohl(((struct sockaddr_in *)hostaddr)->
617 sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
618 case AF_INET6:
619 return IN6_IS_ADDR_LOOPBACK(
620 &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
621 default:
622 return 0;
623 }
624}
625
626/*
627 * Prepare the hostname and ip address strings that are used to lookup
628 * host keys in known_hosts files. These may have a port number appended.
629 */
630void
631get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr,
632 u_short port, char **hostfile_hostname, char **hostfile_ipaddr)
633{
634 char ntop[NI_MAXHOST];
635 socklen_t addrlen;
636
637 switch (hostaddr == NULL ? -1 : hostaddr->sa_family) {
638 case -1:
639 addrlen = 0;
640 break;
641 case AF_INET:
642 addrlen = sizeof(struct sockaddr_in);
643 break;
644 case AF_INET6:
645 addrlen = sizeof(struct sockaddr_in6);
646 break;
647 default:
648 addrlen = sizeof(struct sockaddr);
649 break;
650 }
651
652 /*
653 * We don't have the remote ip-address for connections
654 * using a proxy command
655 */
656 if (hostfile_ipaddr != NULL) {
657 if (options.proxy_command == NULL) {
658 if (getnameinfo(hostaddr, addrlen,
659 ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0)
660 fatal("check_host_key: getnameinfo failed");
661 *hostfile_ipaddr = put_host_port(ntop, port);
662 } else {
663 *hostfile_ipaddr = xstrdup("<no hostip for proxy "
664 "command>");
665 }
666 }
667
668 /*
669 * Allow the user to record the key under a different name or
670 * differentiate a non-standard port. This is useful for ssh
671 * tunneling over forwarded connections or if you run multiple
672 * sshd's on different ports on the same machine.
673 */
674 if (hostfile_hostname != NULL) {
675 if (options.host_key_alias != NULL) {
676 *hostfile_hostname = xstrdup(options.host_key_alias);
677 debug("using hostkeyalias: %s", *hostfile_hostname);
678 } else {
679 *hostfile_hostname = put_host_port(hostname, port);
680 }
681 }
682}
683
597/* 684/*
598 * check whether the supplied host key is valid, return -1 if the key 685 * check whether the supplied host key is valid, return -1 if the key
599 * is not valid. the user_hostfile will not be updated if 'readonly' is true. 686 * is not valid. the user_hostfile will not be updated if 'readonly' is true.
@@ -603,21 +690,21 @@ check_host_cert(const char *host, const Key *host_key)
603#define ROQUIET 2 690#define ROQUIET 2
604static int 691static int
605check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, 692check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
606 Key *host_key, int readonly, const char *user_hostfile, 693 Key *host_key, int readonly, char *user_hostfile,
607 const char *system_hostfile) 694 char *system_hostfile)
608{ 695{
609 Key *file_key, *raw_key = NULL; 696 Key *raw_key = NULL;
610 const char *type; 697 const char *type;
611 char *ip = NULL, *host = NULL; 698 char *ip = NULL, *host = NULL;
612 char hostline[1000], *hostp, *fp, *ra; 699 char hostline[1000], *hostp, *fp, *ra;
613 HostStatus host_status; 700 HostStatus host_status;
614 HostStatus ip_status; 701 HostStatus ip_status;
615 int r, want_cert, local = 0, host_ip_differ = 0; 702 int r, want_cert = key_is_cert(host_key), host_ip_differ = 0;
616 int salen; 703 int local = sockaddr_is_local(hostaddr);
617 char ntop[NI_MAXHOST];
618 char msg[1024]; 704 char msg[1024];
619 int len, host_line, ip_line, cancelled_forwarding = 0; 705 int len, cancelled_forwarding = 0;
620 const char *host_file = NULL, *ip_file = NULL; 706 struct hostkeys *host_hostkeys, *ip_hostkeys;
707 const struct hostkey_entry *host_found, *ip_found;
621 708
622 /* 709 /*
623 * Force accepting of the host key for loopback/localhost. The 710 * Force accepting of the host key for loopback/localhost. The
@@ -627,23 +714,6 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
627 * essentially disables host authentication for localhost; however, 714 * essentially disables host authentication for localhost; however,
628 * this is probably not a real problem. 715 * this is probably not a real problem.
629 */ 716 */
630 /** hostaddr == 0! */
631 switch (hostaddr->sa_family) {
632 case AF_INET:
633 local = (ntohl(((struct sockaddr_in *)hostaddr)->
634 sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
635 salen = sizeof(struct sockaddr_in);
636 break;
637 case AF_INET6:
638 local = IN6_IS_ADDR_LOOPBACK(
639 &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
640 salen = sizeof(struct sockaddr_in6);
641 break;
642 default:
643 local = 0;
644 salen = sizeof(struct sockaddr_storage);
645 break;
646 }
647 if (options.no_host_authentication_for_localhost == 1 && local && 717 if (options.no_host_authentication_for_localhost == 1 && local &&
648 options.host_key_alias == NULL) { 718 options.host_key_alias == NULL) {
649 debug("Forcing accepting of host key for " 719 debug("Forcing accepting of host key for "
@@ -652,17 +722,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
652 } 722 }
653 723
654 /* 724 /*
655 * We don't have the remote ip-address for connections 725 * Prepare the hostname and address strings used for hostkey lookup.
656 * using a proxy command 726 * In some cases, these will have a port number appended.
657 */ 727 */
658 if (options.proxy_command == NULL) { 728 get_hostfile_hostname_ipaddr(hostname, hostaddr, port, &host, &ip);
659 if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
660 NULL, 0, NI_NUMERICHOST) != 0)
661 fatal("check_host_key: getnameinfo failed");
662 ip = put_host_port(ntop, port);
663 } else {
664 ip = xstrdup("<no hostip for proxy command>");
665 }
666 729
667 /* 730 /*
668 * Turn off check_host_ip if the connection is to localhost, via proxy 731 * Turn off check_host_ip if the connection is to localhost, via proxy
@@ -672,74 +735,52 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
672 strcmp(hostname, ip) == 0 || options.proxy_command != NULL)) 735 strcmp(hostname, ip) == 0 || options.proxy_command != NULL))
673 options.check_host_ip = 0; 736 options.check_host_ip = 0;
674 737
675 /* 738 host_hostkeys = init_hostkeys();
676 * Allow the user to record the key under a different name or 739 load_hostkeys(host_hostkeys, host, user_hostfile);
677 * differentiate a non-standard port. This is useful for ssh 740 load_hostkeys(host_hostkeys, host, system_hostfile);
678 * tunneling over forwarded connections or if you run multiple 741
679 * sshd's on different ports on the same machine. 742 ip_hostkeys = NULL;
680 */ 743 if (!want_cert && options.check_host_ip) {
681 if (options.host_key_alias != NULL) { 744 ip_hostkeys = init_hostkeys();
682 host = xstrdup(options.host_key_alias); 745 load_hostkeys(ip_hostkeys, ip, user_hostfile);
683 debug("using hostkeyalias: %s", host); 746 load_hostkeys(ip_hostkeys, ip, system_hostfile);
684 } else {
685 host = put_host_port(hostname, port);
686 } 747 }
687 748
688 retry: 749 retry:
750 /* Reload these as they may have changed on cert->key downgrade */
689 want_cert = key_is_cert(host_key); 751 want_cert = key_is_cert(host_key);
690 type = key_type(host_key); 752 type = key_type(host_key);
691 753
692 /* 754 /*
693 * Store the host key from the known host file in here so that we can
694 * compare it with the key for the IP address.
695 */
696 file_key = key_new(key_is_cert(host_key) ? KEY_UNSPEC : host_key->type);
697
698 /*
699 * Check if the host key is present in the user's list of known 755 * Check if the host key is present in the user's list of known
700 * hosts or in the systemwide list. 756 * hosts or in the systemwide list.
701 */ 757 */
702 host_file = user_hostfile; 758 host_status = check_key_in_hostkeys(host_hostkeys, host_key,
703 host_status = check_host_in_hostfile(host_file, host, host_key, 759 &host_found);
704 file_key, &host_line); 760
705 if (host_status == HOST_NEW) {
706 host_file = system_hostfile;
707 host_status = check_host_in_hostfile(host_file, host, host_key,
708 file_key, &host_line);
709 }
710 /* 761 /*
711 * Also perform check for the ip address, skip the check if we are 762 * Also perform check for the ip address, skip the check if we are
712 * localhost, looking for a certificate, or the hostname was an ip 763 * localhost, looking for a certificate, or the hostname was an ip
713 * address to begin with. 764 * address to begin with.
714 */ 765 */
715 if (!want_cert && options.check_host_ip) { 766 if (!want_cert && ip_hostkeys != NULL) {
716 Key *ip_key = key_new(host_key->type); 767 ip_status = check_key_in_hostkeys(ip_hostkeys, host_key,
717 768 &ip_found);
718 ip_file = user_hostfile;
719 ip_status = check_host_in_hostfile(ip_file, ip, host_key,
720 ip_key, &ip_line);
721 if (ip_status == HOST_NEW) {
722 ip_file = system_hostfile;
723 ip_status = check_host_in_hostfile(ip_file, ip,
724 host_key, ip_key, &ip_line);
725 }
726 if (host_status == HOST_CHANGED && 769 if (host_status == HOST_CHANGED &&
727 (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) 770 (ip_status != HOST_CHANGED ||
771 (ip_found != NULL &&
772 !key_equal(ip_found->key, host_found->key))))
728 host_ip_differ = 1; 773 host_ip_differ = 1;
729
730 key_free(ip_key);
731 } else 774 } else
732 ip_status = host_status; 775 ip_status = host_status;
733 776
734 key_free(file_key);
735
736 switch (host_status) { 777 switch (host_status) {
737 case HOST_OK: 778 case HOST_OK:
738 /* The host is known and the key matches. */ 779 /* The host is known and the key matches. */
739 debug("Host '%.200s' is known and matches the %s host %s.", 780 debug("Host '%.200s' is known and matches the %s host %s.",
740 host, type, want_cert ? "certificate" : "key"); 781 host, type, want_cert ? "certificate" : "key");
741 debug("Found %s in %s:%d", 782 debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
742 want_cert ? "CA key" : "key", host_file, host_line); 783 host_found->file, host_found->line);
743 if (want_cert && !check_host_cert(hostname, host_key)) 784 if (want_cert && !check_host_cert(hostname, host_key))
744 goto fail; 785 goto fail;
745 if (options.check_host_ip && ip_status == HOST_NEW) { 786 if (options.check_host_ip && ip_status == HOST_NEW) {
@@ -790,7 +831,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
790 } else if (options.strict_host_key_checking == 2) { 831 } else if (options.strict_host_key_checking == 2) {
791 char msg1[1024], msg2[1024]; 832 char msg1[1024], msg2[1024];
792 833
793 if (show_other_keys(host, host_key)) 834 if (show_other_keys(host_hostkeys, host_key))
794 snprintf(msg1, sizeof(msg1), 835 snprintf(msg1, sizeof(msg1),
795 "\nbut keys of different type are already" 836 "\nbut keys of different type are already"
796 " known for this host."); 837 " known for this host.");
@@ -831,8 +872,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
831 * local known_hosts file. 872 * local known_hosts file.
832 */ 873 */
833 if (options.check_host_ip && ip_status == HOST_NEW) { 874 if (options.check_host_ip && ip_status == HOST_NEW) {
834 snprintf(hostline, sizeof(hostline), "%s,%s", 875 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
835 host, ip);
836 hostp = hostline; 876 hostp = hostline;
837 if (options.hash_known_hosts) { 877 if (options.hash_known_hosts) {
838 /* Add hash of host and IP separately */ 878 /* Add hash of host and IP separately */
@@ -886,8 +926,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
886 * all hosts that one might visit. 926 * all hosts that one might visit.
887 */ 927 */
888 debug("Host certificate authority does not " 928 debug("Host certificate authority does not "
889 "match %s in %s:%d", CA_MARKER, 929 "match %s in %s:%lu", CA_MARKER,
890 host_file, host_line); 930 host_found->file, host_found->line);
891 goto fail; 931 goto fail;
892 } 932 }
893 if (readonly == ROQUIET) 933 if (readonly == ROQUIET)
@@ -909,13 +949,15 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
909 error("DNS SPOOFING is happening or the IP address for the host"); 949 error("DNS SPOOFING is happening or the IP address for the host");
910 error("and its host key have changed at the same time."); 950 error("and its host key have changed at the same time.");
911 if (ip_status != HOST_NEW) 951 if (ip_status != HOST_NEW)
912 error("Offending key for IP in %s:%d", ip_file, ip_line); 952 error("Offending key for IP in %s:%lu",
953 ip_found->file, ip_found->line);
913 } 954 }
914 /* The host key has changed. */ 955 /* The host key has changed. */
915 warn_changed_key(host_key); 956 warn_changed_key(host_key);
916 error("Add correct host key in %.100s to get rid of this message.", 957 error("Add correct host key in %.100s to get rid of this message.",
917 user_hostfile); 958 user_hostfile);
918 error("Offending key in %s:%d", host_file, host_line); 959 error("Offending %s key in %s:%lu", key_type(host_found->key),
960 host_found->file, host_found->line);
919 961
920 /* 962 /*
921 * If strict host key checking is in use, the user will have 963 * If strict host key checking is in use, the user will have
@@ -1000,13 +1042,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1000 snprintf(msg, sizeof(msg), 1042 snprintf(msg, sizeof(msg),
1001 "Warning: the %s host key for '%.200s' " 1043 "Warning: the %s host key for '%.200s' "
1002 "differs from the key for the IP address '%.128s'" 1044 "differs from the key for the IP address '%.128s'"
1003 "\nOffending key for IP in %s:%d", 1045 "\nOffending key for IP in %s:%lu",
1004 type, host, ip, ip_file, ip_line); 1046 type, host, ip, ip_found->file, ip_found->line);
1005 if (host_status == HOST_OK) { 1047 if (host_status == HOST_OK) {
1006 len = strlen(msg); 1048 len = strlen(msg);
1007 snprintf(msg + len, sizeof(msg) - len, 1049 snprintf(msg + len, sizeof(msg) - len,
1008 "\nMatching host key in %s:%d", 1050 "\nMatching host key in %s:%lu",
1009 host_file, host_line); 1051 host_found->file, host_found->line);
1010 } 1052 }
1011 if (options.strict_host_key_checking == 1) { 1053 if (options.strict_host_key_checking == 1) {
1012 logit("%s", msg); 1054 logit("%s", msg);
@@ -1024,6 +1066,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1024 1066
1025 xfree(ip); 1067 xfree(ip);
1026 xfree(host); 1068 xfree(host);
1069 if (host_hostkeys != NULL)
1070 free_hostkeys(host_hostkeys);
1071 if (ip_hostkeys != NULL)
1072 free_hostkeys(ip_hostkeys);
1027 return 0; 1073 return 0;
1028 1074
1029fail: 1075fail:
@@ -1043,6 +1089,10 @@ fail:
1043 key_free(raw_key); 1089 key_free(raw_key);
1044 xfree(ip); 1090 xfree(ip);
1045 xfree(host); 1091 xfree(host);
1092 if (host_hostkeys != NULL)
1093 free_hostkeys(host_hostkeys);
1094 if (ip_hostkeys != NULL)
1095 free_hostkeys(ip_hostkeys);
1046 return -1; 1096 return -1;
1047} 1097}
1048 1098
@@ -1052,6 +1102,11 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
1052{ 1102{
1053 struct stat st; 1103 struct stat st;
1054 int flags = 0; 1104 int flags = 0;
1105 char *fp;
1106
1107 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
1108 debug("Server host key: %s %s", key_type(host_key), fp);
1109 xfree(fp);
1055 1110
1056 /* XXX certs are not yet supported for DNS */ 1111 /* XXX certs are not yet supported for DNS */
1057 if (!key_is_cert(host_key) && options.verify_host_key_dns && 1112 if (!key_is_cert(host_key) && options.verify_host_key_dns &&
@@ -1095,7 +1150,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
1095 */ 1150 */
1096void 1151void
1097ssh_login(Sensitive *sensitive, const char *orighost, 1152ssh_login(Sensitive *sensitive, const char *orighost,
1098 struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms) 1153 struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
1099{ 1154{
1100 char *host, *cp; 1155 char *host, *cp;
1101 char *server_user, *local_user; 1156 char *server_user, *local_user;
@@ -1118,7 +1173,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
1118 /* key exchange */ 1173 /* key exchange */
1119 /* authenticate user */ 1174 /* authenticate user */
1120 if (compat20) { 1175 if (compat20) {
1121 ssh_kex2(host, hostaddr); 1176 ssh_kex2(host, hostaddr, port);
1122 ssh_userauth2(local_user, server_user, host, sensitive); 1177 ssh_userauth2(local_user, server_user, host, sensitive);
1123 } else { 1178 } else {
1124 ssh_kex(host, hostaddr); 1179 ssh_kex(host, hostaddr);
@@ -1145,68 +1200,41 @@ ssh_put_password(char *password)
1145 xfree(padded); 1200 xfree(padded);
1146} 1201}
1147 1202
1148static int
1149show_key_from_file(const char *file, const char *host, int keytype)
1150{
1151 Key *found;
1152 char *fp, *ra;
1153 int line, ret;
1154
1155 found = key_new(keytype);
1156 if ((ret = lookup_key_in_hostfile_by_type(file, host,
1157 keytype, found, &line))) {
1158 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
1159 ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART);
1160 logit("WARNING: %s key found for host %s\n"
1161 "in %s:%d\n"
1162 "%s key fingerprint %s.\n%s\n",
1163 key_type(found), host, file, line,
1164 key_type(found), fp, ra);
1165 xfree(ra);
1166 xfree(fp);
1167 }
1168 key_free(found);
1169 return (ret);
1170}
1171
1172/* print all known host keys for a given host, but skip keys of given type */ 1203/* print all known host keys for a given host, but skip keys of given type */
1173static int 1204static int
1174show_other_keys(const char *host, Key *key) 1205show_other_keys(struct hostkeys *hostkeys, Key *key)
1175{ 1206{
1176 int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; 1207 int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, -1};
1177 int i, found = 0; 1208 int i, ret = 0;
1209 char *fp, *ra;
1210 const struct hostkey_entry *found;
1178 1211
1179 for (i = 0; type[i] != -1; i++) { 1212 for (i = 0; type[i] != -1; i++) {
1180 if (type[i] == key->type) 1213 if (type[i] == key->type)
1181 continue; 1214 continue;
1182 if (type[i] != KEY_RSA1 && 1215 if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
1183 show_key_from_file(options.user_hostfile2, host, type[i])) {
1184 found = 1;
1185 continue;
1186 }
1187 if (type[i] != KEY_RSA1 &&
1188 show_key_from_file(options.system_hostfile2, host, type[i])) {
1189 found = 1;
1190 continue;
1191 }
1192 if (show_key_from_file(options.user_hostfile, host, type[i])) {
1193 found = 1;
1194 continue;
1195 }
1196 if (show_key_from_file(options.system_hostfile, host, type[i])) {
1197 found = 1;
1198 continue; 1216 continue;
1199 } 1217 fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
1200 debug2("no key of type %d for host %s", type[i], host); 1218 ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
1219 logit("WARNING: %s key found for host %s\n"
1220 "in %s:%lu\n"
1221 "%s key fingerprint %s.",
1222 key_type(found->key),
1223 found->host, found->file, found->line,
1224 key_type(found->key), fp);
1225 if (options.visual_host_key)
1226 logit("%s", ra);
1227 xfree(ra);
1228 xfree(fp);
1229 ret = 1;
1201 } 1230 }
1202 return (found); 1231 return ret;
1203} 1232}
1204 1233
1205static void 1234static void
1206warn_changed_key(Key *host_key) 1235warn_changed_key(Key *host_key)
1207{ 1236{
1208 char *fp; 1237 char *fp;
1209 const char *type = key_type(host_key);
1210 1238
1211 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 1239 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
1212 1240
@@ -1215,9 +1243,9 @@ warn_changed_key(Key *host_key)
1215 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1243 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1216 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 1244 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1217 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 1245 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1218 error("It is also possible that the %s host key has just been changed.", type); 1246 error("It is also possible that a host key has just been changed.");
1219 error("The fingerprint for the %s key sent by the remote host is\n%s.", 1247 error("The fingerprint for the %s key sent by the remote host is\n%s.",
1220 type, fp); 1248 key_type(host_key), fp);
1221 error("Please contact your system administrator."); 1249 error("Please contact your system administrator.");
1222 1250
1223 xfree(fp); 1251 xfree(fp);
@@ -1232,16 +1260,19 @@ ssh_local_cmd(const char *args)
1232 char *shell; 1260 char *shell;
1233 pid_t pid; 1261 pid_t pid;
1234 int status; 1262 int status;
1263 void (*osighand)(int);
1235 1264
1236 if (!options.permit_local_command || 1265 if (!options.permit_local_command ||
1237 args == NULL || !*args) 1266 args == NULL || !*args)
1238 return (1); 1267 return (1);
1239 1268
1240 if ((shell = getenv("SHELL")) == NULL) 1269 if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
1241 shell = _PATH_BSHELL; 1270 shell = _PATH_BSHELL;
1242 1271
1272 osighand = signal(SIGCHLD, SIG_DFL);
1243 pid = fork(); 1273 pid = fork();
1244 if (pid == 0) { 1274 if (pid == 0) {
1275 signal(SIGPIPE, SIG_DFL);
1245 debug3("Executing %s -c \"%s\"", shell, args); 1276 debug3("Executing %s -c \"%s\"", shell, args);
1246 execlp(shell, shell, "-c", args, (char *)NULL); 1277 execlp(shell, shell, "-c", args, (char *)NULL);
1247 error("Couldn't execute %s -c \"%s\": %s", 1278 error("Couldn't execute %s -c \"%s\": %s",
@@ -1252,6 +1283,7 @@ ssh_local_cmd(const char *args)
1252 while (waitpid(pid, &status, 0) == -1) 1283 while (waitpid(pid, &status, 0) == -1)
1253 if (errno != EINTR) 1284 if (errno != EINTR)
1254 fatal("Couldn't wait for child: %s", strerror(errno)); 1285 fatal("Couldn't wait for child: %s", strerror(errno));
1286 signal(SIGCHLD, osighand);
1255 1287
1256 if (!WIFEXITED(status)) 1288 if (!WIFEXITED(status))
1257 return (1); 1289 return (1);