|
Lines 26-31
Link Here
|
| 26 |
#include <netinet/in.h> |
26 |
#include <netinet/in.h> |
| 27 |
#include <arpa/inet.h> |
27 |
#include <arpa/inet.h> |
| 28 |
|
28 |
|
|
|
29 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 30 |
# include <validator/validator.h> |
| 31 |
#endif |
| 32 |
|
| 29 |
#include <ctype.h> |
33 |
#include <ctype.h> |
| 30 |
#include <errno.h> |
34 |
#include <errno.h> |
| 31 |
#include <netdb.h> |
35 |
#include <netdb.h> |
|
Lines 63-68
char *client_version_string = NULL;
Link Here
|
| 63 |
char *server_version_string = NULL; |
67 |
char *server_version_string = NULL; |
| 64 |
|
68 |
|
| 65 |
static int matching_host_key_dns = 0; |
69 |
static int matching_host_key_dns = 0; |
|
|
70 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 71 |
static int validated_host_key_dns = 0; |
| 72 |
#endif |
| 66 |
|
73 |
|
| 67 |
/* import */ |
74 |
/* import */ |
| 68 |
extern Options options; |
75 |
extern Options options; |
|
Lines 73-78
extern pid_t proxy_command_pid;
Link Here
|
| 73 |
|
80 |
|
| 74 |
static int show_other_keys(const char *, Key *); |
81 |
static int show_other_keys(const char *, Key *); |
| 75 |
static void warn_changed_key(Key *); |
82 |
static void warn_changed_key(Key *); |
|
|
83 |
static int confirm(const char *prompt); |
| 76 |
|
84 |
|
| 77 |
/* |
85 |
/* |
| 78 |
* Connect to the given ssh server using a proxy command. |
86 |
* Connect to the given ssh server using a proxy command. |
|
Lines 323-329
ssh_connect(const char *host, struct soc
Link Here
|
| 323 |
int on = 1; |
331 |
int on = 1; |
| 324 |
int sock = -1, attempt; |
332 |
int sock = -1, attempt; |
| 325 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
333 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
| 326 |
struct addrinfo hints, *ai, *aitop; |
334 |
struct addrinfo hints; |
|
|
335 |
struct addrinfo *ai, *aitop = NULL; |
| 336 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 337 |
val_status_t val_status; |
| 338 |
#endif |
| 327 |
|
339 |
|
| 328 |
debug2("ssh_connect: needpriv %d", needpriv); |
340 |
debug2("ssh_connect: needpriv %d", needpriv); |
| 329 |
|
341 |
|
|
Lines 337-345
ssh_connect(const char *host, struct soc
Link Here
|
| 337 |
hints.ai_family = family; |
349 |
hints.ai_family = family; |
| 338 |
hints.ai_socktype = SOCK_STREAM; |
350 |
hints.ai_socktype = SOCK_STREAM; |
| 339 |
snprintf(strport, sizeof strport, "%u", port); |
351 |
snprintf(strport, sizeof strport, "%u", port); |
|
|
352 |
#ifndef DNSSEC_LOCAL_VALIDATION |
| 340 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
353 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
| 341 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
354 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
| 342 |
host, ssh_gai_strerror(gaierr)); |
355 |
host, ssh_gai_strerror(gaierr)); |
|
|
356 |
#else |
| 357 |
gaierr = val_getaddrinfo(NULL, host, strport, &hints, &aitop, |
| 358 |
&val_status); |
| 359 |
debug2("ssh_connect: gaierr %d, val_status %d / %s; trusted: %d", |
| 360 |
gaierr, val_status, p_val_status(val_status), |
| 361 |
val_istrusted(val_status)); |
| 362 |
if (gaierr != 0) { |
| 363 |
if (VAL_GETADDRINFO_HAS_STATUS(gaierr) && |
| 364 |
!val_istrusted(val_status)) { |
| 365 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 366 |
error("@ WARNING: UNTRUSTED ERROR IN DNS RESOLUTION FOR HOST! @"); |
| 367 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 368 |
error("The authenticity of DNS response is not trusted (%s).", |
| 369 |
p_val_status(val_status)); |
| 370 |
} |
| 371 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
| 372 |
host, ssh_gai_strerror(gaierr)); |
| 373 |
} |
| 374 |
if (!val_istrusted(val_status)) { |
| 375 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 376 |
error("@ WARNING: UNTRUSTED DNS RESOLUTION FOR HOST IP ADRRESS! @"); |
| 377 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 378 |
error("The authenticity of DNS data for the host '%.200s' " |
| 379 |
"can't be established.", host); |
| 380 |
if (options.strict_dnssec_checking == 1) { |
| 381 |
fatal("DNS resolution is not trusted (%s) " |
| 382 |
"and you have requested strict checking", |
| 383 |
p_val_status(val_status)); |
| 384 |
} else if (options.strict_dnssec_checking == 2) { |
| 385 |
char msg[1024]; |
| 386 |
for (ai = aitop; ai; ai = ai->ai_next) { |
| 387 |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
| 388 |
continue; |
| 389 |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, |
| 390 |
ntop, sizeof(ntop), strport, sizeof(strport), |
| 391 |
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
| 392 |
error("ssh_connect: getnameinfo failed"); |
| 393 |
continue; |
| 394 |
} |
| 395 |
error(" IP address %s port %s", ntop, strport); |
| 396 |
} |
| 397 |
snprintf(msg,sizeof(msg), |
| 398 |
"Are you sure you want to attempt to connect " |
| 399 |
"(yes/no)? "); |
| 400 |
if (!confirm(msg)) |
| 401 |
return (-1); |
| 402 |
} |
| 403 |
} |
| 404 |
#endif /* DNSSEC_LOCAL_VALIDATION */ |
| 343 |
|
405 |
|
| 344 |
for (attempt = 0; attempt < connection_attempts; attempt++) { |
406 |
for (attempt = 0; attempt < connection_attempts; attempt++) { |
| 345 |
if (attempt > 0) { |
407 |
if (attempt > 0) { |
|
Lines 736-741
check_host_key(char *hostname, struct so
Link Here
|
| 736 |
} |
798 |
} |
| 737 |
break; |
799 |
break; |
| 738 |
case HOST_NEW: |
800 |
case HOST_NEW: |
|
|
801 |
debug("Host '%.200s' new.", host); |
| 739 |
if (options.host_key_alias == NULL && port != 0 && |
802 |
if (options.host_key_alias == NULL && port != 0 && |
| 740 |
port != SSH_DEFAULT_PORT) { |
803 |
port != SSH_DEFAULT_PORT) { |
| 741 |
debug("checking without port identifier"); |
804 |
debug("checking without port identifier"); |
|
Lines 781-786
check_host_key(char *hostname, struct so
Link Here
|
| 781 |
"No matching host key fingerprint" |
844 |
"No matching host key fingerprint" |
| 782 |
" found in DNS.\n"); |
845 |
" found in DNS.\n"); |
| 783 |
} |
846 |
} |
|
|
847 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 848 |
if (options.autoanswer_validated_keys && |
| 849 |
validated_host_key_dns && matching_host_key_dns) { |
| 850 |
snprintf(msg, sizeof(msg), |
| 851 |
"The authenticity of host '%.200s (%s)' was " |
| 852 |
" validated via DNSSEC%s", |
| 853 |
host, ip, msg1); |
| 854 |
logit(msg); |
| 855 |
xfree(fp); |
| 856 |
} else { |
| 857 |
#endif |
| 784 |
snprintf(msg, sizeof(msg), |
858 |
snprintf(msg, sizeof(msg), |
| 785 |
"The authenticity of host '%.200s (%s)' can't be " |
859 |
"The authenticity of host '%.200s (%s)' can't be " |
| 786 |
"established%s\n" |
860 |
"established%s\n" |
|
Lines 795-800
check_host_key(char *hostname, struct so
Link Here
|
| 795 |
xfree(fp); |
869 |
xfree(fp); |
| 796 |
if (!confirm(msg)) |
870 |
if (!confirm(msg)) |
| 797 |
goto fail; |
871 |
goto fail; |
|
|
872 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 873 |
} |
| 874 |
#endif |
| 798 |
} |
875 |
} |
| 799 |
/* |
876 |
/* |
| 800 |
* If not in strict mode, add the key automatically to the |
877 |
* If not in strict mode, add the key automatically to the |
|
Lines 830-835
check_host_key(char *hostname, struct so
Link Here
|
| 830 |
"list of known hosts.", hostp, type); |
907 |
"list of known hosts.", hostp, type); |
| 831 |
break; |
908 |
break; |
| 832 |
case HOST_CHANGED: |
909 |
case HOST_CHANGED: |
|
|
910 |
debug("Host '%.200s' changed.", host); |
| 833 |
if (readonly == ROQUIET) |
911 |
if (readonly == ROQUIET) |
| 834 |
goto fail; |
912 |
goto fail; |
| 835 |
if (options.check_host_ip && host_ip_differ) { |
913 |
if (options.check_host_ip && host_ip_differ) { |
|
Lines 840-845
check_host_key(char *hostname, struct so
Link Here
|
| 840 |
key_msg = "is unchanged"; |
918 |
key_msg = "is unchanged"; |
| 841 |
else |
919 |
else |
| 842 |
key_msg = "has a different value"; |
920 |
key_msg = "has a different value"; |
|
|
921 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 922 |
if (!validated_host_key_dns) { |
| 843 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
923 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 844 |
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); |
924 |
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); |
| 845 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
925 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
|
Lines 848-853
check_host_key(char *hostname, struct so
Link Here
|
| 848 |
error("%s. This could either mean that", key_msg); |
928 |
error("%s. This could either mean that", key_msg); |
| 849 |
error("DNS SPOOFING is happening or the IP address for the host"); |
929 |
error("DNS SPOOFING is happening or the IP address for the host"); |
| 850 |
error("and its host key have changed at the same time."); |
930 |
error("and its host key have changed at the same time."); |
|
|
931 |
} |
| 932 |
else { |
| 933 |
#endif |
| 934 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 935 |
error("@ WARNING: HOST IP ADDRESS HAS CHANGED! @"); |
| 936 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 937 |
error("The %s host key for %s has changed,", type, host); |
| 938 |
error("and the key for the according IP address %s", ip); |
| 939 |
error("%s. The IP address for the host", key_msg); |
| 940 |
error("and its host key have changed at the same time."); |
| 941 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 942 |
} |
| 943 |
#endif |
| 851 |
if (ip_status != HOST_NEW) |
944 |
if (ip_status != HOST_NEW) |
| 852 |
error("Offending key for IP in %s:%d", ip_file, ip_line); |
945 |
error("Offending key for IP in %s:%d", ip_file, ip_line); |
| 853 |
} |
946 |
} |
|
Lines 861-872
check_host_key(char *hostname, struct so
Link Here
|
| 861 |
* If strict host key checking is in use, the user will have |
954 |
* If strict host key checking is in use, the user will have |
| 862 |
* to edit the key manually and we can only abort. |
955 |
* to edit the key manually and we can only abort. |
| 863 |
*/ |
956 |
*/ |
|
|
957 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 958 |
if ((options.strict_host_key_checking == 2) && |
| 959 |
options.autoanswer_validated_keys && |
| 960 |
matching_host_key_dns && validated_host_key_dns) { |
| 961 |
logit("The authenticity of host '%.200s (%s)' was " |
| 962 |
" validated via DNSSEC.", |
| 963 |
host, ip); |
| 964 |
/* |
| 965 |
* If not in strict mode, add the key automatically to the |
| 966 |
* local known_hosts file. |
| 967 |
*/ |
| 968 |
if (options.check_host_ip && ip_status == HOST_NEW) { |
| 969 |
snprintf(hostline, sizeof(hostline), "%s,%s", |
| 970 |
host, ip); |
| 971 |
hostp = hostline; |
| 972 |
if (options.hash_known_hosts) { |
| 973 |
/* Add hash of host and IP separately */ |
| 974 |
r = add_host_to_hostfile(user_hostfile, host, |
| 975 |
host_key, options.hash_known_hosts) && |
| 976 |
add_host_to_hostfile(user_hostfile, ip, |
| 977 |
host_key, options.hash_known_hosts); |
| 978 |
} else { |
| 979 |
/* Add unhashed "host,ip" */ |
| 980 |
r = add_host_to_hostfile(user_hostfile, |
| 981 |
hostline, host_key, |
| 982 |
options.hash_known_hosts); |
| 983 |
} |
| 984 |
} else { |
| 985 |
r = add_host_to_hostfile(user_hostfile, host, host_key, |
| 986 |
options.hash_known_hosts); |
| 987 |
hostp = host; |
| 988 |
} |
| 989 |
|
| 990 |
if (!r) |
| 991 |
logit("Failed to add the host to the list of known " |
| 992 |
"hosts (%.500s).", user_hostfile); |
| 993 |
else |
| 994 |
logit("Warning: Permanently added '%.200s' (%s) to the " |
| 995 |
"list of known hosts.", hostp, type); |
| 996 |
} |
| 997 |
else |
| 998 |
#endif |
| 864 |
if (options.strict_host_key_checking) { |
999 |
if (options.strict_host_key_checking) { |
| 865 |
error("%s host key for %.200s has changed and you have " |
1000 |
error("%s host key for %.200s has changed and you have " |
| 866 |
"requested strict checking.", type, host); |
1001 |
"requested strict checking.", type, host); |
| 867 |
goto fail; |
1002 |
goto fail; |
| 868 |
} |
1003 |
} |
| 869 |
|
1004 |
else { |
| 870 |
/* |
1005 |
/* |
| 871 |
* If strict host key checking has not been requested, allow |
1006 |
* If strict host key checking has not been requested, allow |
| 872 |
* the connection but without MITM-able authentication or |
1007 |
* the connection but without MITM-able authentication or |
|
Lines 925-933
check_host_key(char *hostname, struct so
Link Here
|
| 925 |
* XXX Should permit the user to change to use the new id. |
1060 |
* XXX Should permit the user to change to use the new id. |
| 926 |
* This could be done by converting the host key to an |
1061 |
* This could be done by converting the host key to an |
| 927 |
* identifying sentence, tell that the host identifies itself |
1062 |
* identifying sentence, tell that the host identifies itself |
| 928 |
* by that sentence, and ask the user if he/she whishes to |
1063 |
* by that sentence, and ask the user if he/she wishes to |
| 929 |
* accept the authentication. |
1064 |
* accept the authentication. |
| 930 |
*/ |
1065 |
*/ |
|
|
1066 |
} |
| 931 |
break; |
1067 |
break; |
| 932 |
case HOST_FOUND: |
1068 |
case HOST_FOUND: |
| 933 |
fatal("internal error"); |
1069 |
fatal("internal error"); |
|
Lines 952-961
check_host_key(char *hostname, struct so
Link Here
|
| 952 |
error("Exiting, you have requested strict checking."); |
1088 |
error("Exiting, you have requested strict checking."); |
| 953 |
goto fail; |
1089 |
goto fail; |
| 954 |
} else if (options.strict_host_key_checking == 2) { |
1090 |
} else if (options.strict_host_key_checking == 2) { |
|
|
1091 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1092 |
if (options.autoanswer_validated_keys && |
| 1093 |
matching_host_key_dns && validated_host_key_dns) { |
| 1094 |
logit("%s", msg); |
| 1095 |
} else { |
| 1096 |
#endif |
| 955 |
strlcat(msg, "\nAre you sure you want " |
1097 |
strlcat(msg, "\nAre you sure you want " |
| 956 |
"to continue connecting (yes/no)? ", sizeof(msg)); |
1098 |
"to continue connecting (yes/no)? ", sizeof(msg)); |
| 957 |
if (!confirm(msg)) |
1099 |
if (!confirm(msg)) |
| 958 |
goto fail; |
1100 |
goto fail; |
|
|
1101 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1102 |
} |
| 1103 |
#endif |
| 959 |
} else { |
1104 |
} else { |
| 960 |
logit("%s", msg); |
1105 |
logit("%s", msg); |
| 961 |
} |
1106 |
} |
|
Lines 981-992
verify_host_key(char *host, struct socka
Link Here
|
| 981 |
if (options.verify_host_key_dns && |
1126 |
if (options.verify_host_key_dns && |
| 982 |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
1127 |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
| 983 |
|
1128 |
|
|
|
1129 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1130 |
/* |
| 1131 |
* local validation can result in a non-secure, but trusted |
| 1132 |
* response. For example, in a corporate network the authoritative |
| 1133 |
* server for internal DNS may be on the internal network, behind |
| 1134 |
* a firewall. Local validation policy can be configured to trust |
| 1135 |
* these results without using DNSSEC to validate them. |
| 1136 |
*/ |
| 1137 |
if (!(flags & DNS_VERIFY_TRUSTED)) { |
| 1138 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1139 |
error("@ WARNING: UNTRUSTED DNS RESOLUTION FOR HOST KEY! @"); |
| 1140 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1141 |
} |
| 1142 |
if (flags & DNS_VERIFY_SECURE) |
| 1143 |
validated_host_key_dns = 1; |
| 1144 |
#endif |
| 984 |
if (flags & DNS_VERIFY_FOUND) { |
1145 |
if (flags & DNS_VERIFY_FOUND) { |
| 985 |
|
1146 |
|
| 986 |
if (options.verify_host_key_dns == 1 && |
1147 |
if (options.verify_host_key_dns == 1 && |
| 987 |
flags & DNS_VERIFY_MATCH && |
1148 |
flags & DNS_VERIFY_MATCH && |
| 988 |
flags & DNS_VERIFY_SECURE) |
1149 |
flags & DNS_VERIFY_SECURE) |
|
|
1150 |
#ifndef DNSSEC_LOCAL_VALIDATION |
| 1151 |
return 0; |
| 1152 |
#else |
| 1153 |
{ |
| 1154 |
if (flags & DNS_VERIFY_MATCH) |
| 1155 |
matching_host_key_dns = 1; |
| 1156 |
if (options.autoanswer_validated_keys) |
| 1157 |
return check_host_key(host, hostaddr, options.port, |
| 1158 |
host_key, RDRW, |
| 1159 |
options.user_hostfile, |
| 1160 |
options.system_hostfile); |
| 1161 |
else |
| 989 |
return 0; |
1162 |
return 0; |
|
|
1163 |
} |
| 1164 |
#endif |
| 990 |
|
1165 |
|
| 991 |
if (flags & DNS_VERIFY_MATCH) { |
1166 |
if (flags & DNS_VERIFY_MATCH) { |
| 992 |
matching_host_key_dns = 1; |
1167 |
matching_host_key_dns = 1; |
|
Lines 1137-1145
warn_changed_key(Key *host_key)
Link Here
|
| 1137 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1312 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1138 |
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); |
1313 |
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); |
| 1139 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1314 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
|
|
1315 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1316 |
if (matching_host_key_dns && validated_host_key_dns) { |
| 1317 |
error("Howerver, a matching host key, validated by DNSSEC, was found."); |
| 1318 |
} |
| 1319 |
else { |
| 1320 |
#endif |
| 1140 |
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); |
1321 |
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); |
| 1141 |
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); |
1322 |
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); |
| 1142 |
error("It is also possible that the %s host key has just been changed.", type); |
1323 |
error("It is also possible that the %s host key has just been changed.", type); |
|
|
1324 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1325 |
} |
| 1326 |
#endif |
| 1143 |
error("The fingerprint for the %s key sent by the remote host is\n%s.", |
1327 |
error("The fingerprint for the %s key sent by the remote host is\n%s.", |
| 1144 |
type, fp); |
1328 |
type, fp); |
| 1145 |
error("Please contact your system administrator."); |
1329 |
error("Please contact your system administrator."); |