summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
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 f55beffe4..74643a8c4 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 execv(argv[0], argv); 147 execv(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 execl(shell, shell, "-c", args, (char *)NULL); 1277 execl(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);