|
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 <fcntl.h> |
35 |
#include <fcntl.h> |
|
Lines 67-72
Link Here
|
| 67 |
char *server_version_string = NULL; |
71 |
char *server_version_string = NULL; |
| 68 |
|
72 |
|
| 69 |
static int matching_host_key_dns = 0; |
73 |
static int matching_host_key_dns = 0; |
|
|
74 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 75 |
static int validated_host_key_dns = 0; |
| 76 |
#endif |
| 70 |
|
77 |
|
| 71 |
/* import */ |
78 |
/* import */ |
| 72 |
extern Options options; |
79 |
extern Options options; |
|
Lines 77-82
Link Here
|
| 77 |
|
84 |
|
| 78 |
static int show_other_keys(const char *, Key *); |
85 |
static int show_other_keys(const char *, Key *); |
| 79 |
static void warn_changed_key(Key *); |
86 |
static void warn_changed_key(Key *); |
|
|
87 |
static int confirm(const char *prompt); |
| 80 |
|
88 |
|
| 81 |
/* |
89 |
/* |
| 82 |
* Connect to the given ssh server using a proxy command. |
90 |
* Connect to the given ssh server using a proxy command. |
|
Lines 330-336
Link Here
|
| 330 |
int on = 1; |
338 |
int on = 1; |
| 331 |
int sock = -1, attempt; |
339 |
int sock = -1, attempt; |
| 332 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
340 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
| 333 |
struct addrinfo hints, *ai, *aitop; |
341 |
struct addrinfo hints; |
|
|
342 |
struct addrinfo *ai, *aitop = NULL; |
| 343 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 344 |
val_status_t val_status; |
| 345 |
#endif |
| 334 |
|
346 |
|
| 335 |
debug2("ssh_connect: needpriv %d", needpriv); |
347 |
debug2("ssh_connect: needpriv %d", needpriv); |
| 336 |
|
348 |
|
|
Lines 344-352
Link Here
|
| 344 |
hints.ai_family = family; |
356 |
hints.ai_family = family; |
| 345 |
hints.ai_socktype = SOCK_STREAM; |
357 |
hints.ai_socktype = SOCK_STREAM; |
| 346 |
snprintf(strport, sizeof strport, "%u", port); |
358 |
snprintf(strport, sizeof strport, "%u", port); |
|
|
359 |
#ifndef DNSSEC_LOCAL_VALIDATION |
| 347 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
360 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
| 348 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
361 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
| 349 |
host, ssh_gai_strerror(gaierr)); |
362 |
host, ssh_gai_strerror(gaierr)); |
|
|
363 |
#else |
| 364 |
gaierr = val_getaddrinfo(NULL, host, strport, &hints, &aitop, |
| 365 |
&val_status); |
| 366 |
debug2("ssh_connect: gaierr %d, val_status %d / %s; trusted: %d", |
| 367 |
gaierr, val_status, p_val_status(val_status), |
| 368 |
val_istrusted(val_status)); |
| 369 |
if (gaierr != 0) { |
| 370 |
if (VAL_GETADDRINFO_HAS_STATUS(gaierr) && |
| 371 |
!val_istrusted(val_status)) { |
| 372 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 373 |
error("@ WARNING: UNTRUSTED ERROR IN DNS RESOLUTION FOR HOST! @"); |
| 374 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 375 |
error("The authenticity of DNS response is not trusted (%s).", |
| 376 |
p_val_status(val_status)); |
| 377 |
} |
| 378 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
| 379 |
host, ssh_gai_strerror(gaierr)); |
| 380 |
} |
| 381 |
if (!val_istrusted(val_status)) { |
| 382 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 383 |
error("@ WARNING: UNTRUSTED DNS RESOLUTION FOR HOST IP ADRRESS! @"); |
| 384 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 385 |
error("The authenticity of DNS data for the host '%.200s' " |
| 386 |
"can't be established.", host); |
| 387 |
if (options.strict_dnssec_checking == 1) { |
| 388 |
fatal("DNS resolution is not trusted (%s) " |
| 389 |
"and you have requested strict checking", |
| 390 |
p_val_status(val_status)); |
| 391 |
} else if (options.strict_dnssec_checking == 2) { |
| 392 |
char msg[1024]; |
| 393 |
for (ai = aitop; ai; ai = ai->ai_next) { |
| 394 |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
| 395 |
continue; |
| 396 |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, |
| 397 |
ntop, sizeof(ntop), strport, sizeof(strport), |
| 398 |
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
| 399 |
error("ssh_connect: getnameinfo failed"); |
| 400 |
continue; |
| 401 |
} |
| 402 |
error(" IP address %s port %s", ntop, strport); |
| 403 |
} |
| 404 |
snprintf(msg,sizeof(msg), |
| 405 |
"Are you sure you want to attempt to connect " |
| 406 |
"(yes/no)? "); |
| 407 |
if (!confirm(msg)) |
| 408 |
return (-1); |
| 409 |
} |
| 410 |
} |
| 411 |
#endif /* DNSSEC_LOCAL_VALIDATION */ |
| 350 |
|
412 |
|
| 351 |
for (attempt = 0; attempt < connection_attempts; attempt++) { |
413 |
for (attempt = 0; attempt < connection_attempts; attempt++) { |
| 352 |
if (attempt > 0) { |
414 |
if (attempt > 0) { |
|
Lines 768-773
Link Here
|
| 768 |
} |
830 |
} |
| 769 |
break; |
831 |
break; |
| 770 |
case HOST_NEW: |
832 |
case HOST_NEW: |
|
|
833 |
debug("Host '%.200s' new.", host); |
| 771 |
if (options.host_key_alias == NULL && port != 0 && |
834 |
if (options.host_key_alias == NULL && port != 0 && |
| 772 |
port != SSH_DEFAULT_PORT) { |
835 |
port != SSH_DEFAULT_PORT) { |
| 773 |
debug("checking without port identifier"); |
836 |
debug("checking without port identifier"); |
|
Lines 814-819
Link Here
|
| 814 |
"No matching host key fingerprint" |
877 |
"No matching host key fingerprint" |
| 815 |
" found in DNS.\n"); |
878 |
" found in DNS.\n"); |
| 816 |
} |
879 |
} |
|
|
880 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 881 |
if (options.autoanswer_validated_keys && |
| 882 |
validated_host_key_dns && matching_host_key_dns) { |
| 883 |
snprintf(msg, sizeof(msg), |
| 884 |
"The authenticity of host '%.200s (%s)' was " |
| 885 |
" validated via DNSSEC%s", |
| 886 |
host, ip, msg1); |
| 887 |
logit(msg); |
| 888 |
xfree(fp); |
| 889 |
} else { |
| 890 |
#endif |
| 817 |
snprintf(msg, sizeof(msg), |
891 |
snprintf(msg, sizeof(msg), |
| 818 |
"The authenticity of host '%.200s (%s)' can't be " |
892 |
"The authenticity of host '%.200s (%s)' can't be " |
| 819 |
"established%s\n" |
893 |
"established%s\n" |
|
Lines 828-833
Link Here
|
| 828 |
xfree(fp); |
902 |
xfree(fp); |
| 829 |
if (!confirm(msg)) |
903 |
if (!confirm(msg)) |
| 830 |
goto fail; |
904 |
goto fail; |
|
|
905 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 906 |
} |
| 907 |
#endif |
| 831 |
} |
908 |
} |
| 832 |
/* |
909 |
/* |
| 833 |
* If not in strict mode, add the key automatically to the |
910 |
* If not in strict mode, add the key automatically to the |
|
Lines 903-908
Link Here
|
| 903 |
key_msg = "is unchanged"; |
980 |
key_msg = "is unchanged"; |
| 904 |
else |
981 |
else |
| 905 |
key_msg = "has a different value"; |
982 |
key_msg = "has a different value"; |
|
|
983 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 984 |
if (!validated_host_key_dns) { |
| 906 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
985 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 907 |
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); |
986 |
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); |
| 908 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
987 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
|
Lines 911-916
Link Here
|
| 911 |
error("%s. This could either mean that", key_msg); |
990 |
error("%s. This could either mean that", key_msg); |
| 912 |
error("DNS SPOOFING is happening or the IP address for the host"); |
991 |
error("DNS SPOOFING is happening or the IP address for the host"); |
| 913 |
error("and its host key have changed at the same time."); |
992 |
error("and its host key have changed at the same time."); |
|
|
993 |
} |
| 994 |
else { |
| 995 |
#endif |
| 996 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 997 |
error("@ WARNING: HOST IP ADDRESS HAS CHANGED! @"); |
| 998 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 999 |
error("The %s host key for %s has changed,", type, host); |
| 1000 |
error("and the key for the according IP address %s", ip); |
| 1001 |
error("%s. The IP address for the host", key_msg); |
| 1002 |
error("and its host key have changed at the same time."); |
| 1003 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1004 |
} |
| 1005 |
#endif |
| 914 |
if (ip_status != HOST_NEW) |
1006 |
if (ip_status != HOST_NEW) |
| 915 |
error("Offending key for IP in %s:%d", ip_file, ip_line); |
1007 |
error("Offending key for IP in %s:%d", ip_file, ip_line); |
| 916 |
} |
1008 |
} |
|
Lines 924-934
Link Here
|
| 924 |
* If strict host key checking is in use, the user will have |
1016 |
* If strict host key checking is in use, the user will have |
| 925 |
* to edit the key manually and we can only abort. |
1017 |
* to edit the key manually and we can only abort. |
| 926 |
*/ |
1018 |
*/ |
|
|
1019 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1020 |
if ((options.strict_host_key_checking == 2) && |
| 1021 |
options.autoanswer_validated_keys && |
| 1022 |
matching_host_key_dns && validated_host_key_dns) { |
| 1023 |
logit("The authenticity of host '%.200s (%s)' was " |
| 1024 |
" validated via DNSSEC.", |
| 1025 |
host, ip); |
| 1026 |
/* |
| 1027 |
* If not in strict mode, add the key automatically to the |
| 1028 |
* local known_hosts file. |
| 1029 |
*/ |
| 1030 |
if (options.check_host_ip && ip_status == HOST_NEW) { |
| 1031 |
snprintf(hostline, sizeof(hostline), "%s,%s", |
| 1032 |
host, ip); |
| 1033 |
hostp = hostline; |
| 1034 |
if (options.hash_known_hosts) { |
| 1035 |
/* Add hash of host and IP separately */ |
| 1036 |
r = add_host_to_hostfile(user_hostfile, host, |
| 1037 |
host_key, options.hash_known_hosts) && |
| 1038 |
add_host_to_hostfile(user_hostfile, ip, |
| 1039 |
host_key, options.hash_known_hosts); |
| 1040 |
} else { |
| 1041 |
/* Add unhashed "host,ip" */ |
| 1042 |
r = add_host_to_hostfile(user_hostfile, |
| 1043 |
hostline, host_key, |
| 1044 |
options.hash_known_hosts); |
| 1045 |
} |
| 1046 |
} else { |
| 1047 |
r = add_host_to_hostfile(user_hostfile, host, host_key, |
| 1048 |
options.hash_known_hosts); |
| 1049 |
hostp = host; |
| 1050 |
} |
| 1051 |
|
| 1052 |
if (!r) |
| 1053 |
logit("Failed to add the host to the list of known " |
| 1054 |
"hosts (%.500s).", user_hostfile); |
| 1055 |
else |
| 1056 |
logit("Warning: Permanently added '%.200s' (%s) to the " |
| 1057 |
"list of known hosts.", hostp, type); |
| 1058 |
} |
| 1059 |
else |
| 1060 |
#endif |
| 927 |
if (options.strict_host_key_checking) { |
1061 |
if (options.strict_host_key_checking) { |
| 928 |
error("%s host key for %.200s has changed and you have " |
1062 |
error("%s host key for %.200s has changed and you have " |
| 929 |
"requested strict checking.", type, host); |
1063 |
"requested strict checking.", type, host); |
| 930 |
goto fail; |
1064 |
goto fail; |
| 931 |
} |
1065 |
} else { |
| 932 |
|
1066 |
|
| 933 |
continue_unsafe: |
1067 |
continue_unsafe: |
| 934 |
/* |
1068 |
/* |
|
Lines 992-997
Link Here
|
| 992 |
* by that sentence, and ask the user if he/she wishes to |
1126 |
* by that sentence, and ask the user if he/she wishes to |
| 993 |
* accept the authentication. |
1127 |
* accept the authentication. |
| 994 |
*/ |
1128 |
*/ |
|
|
1129 |
} |
| 995 |
break; |
1130 |
break; |
| 996 |
case HOST_FOUND: |
1131 |
case HOST_FOUND: |
| 997 |
fatal("internal error"); |
1132 |
fatal("internal error"); |
|
Lines 1016-1025
Link Here
|
| 1016 |
error("Exiting, you have requested strict checking."); |
1151 |
error("Exiting, you have requested strict checking."); |
| 1017 |
goto fail; |
1152 |
goto fail; |
| 1018 |
} else if (options.strict_host_key_checking == 2) { |
1153 |
} else if (options.strict_host_key_checking == 2) { |
|
|
1154 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1155 |
if (options.autoanswer_validated_keys && |
| 1156 |
matching_host_key_dns && validated_host_key_dns) { |
| 1157 |
logit("%s", msg); |
| 1158 |
} else { |
| 1159 |
#endif |
| 1019 |
strlcat(msg, "\nAre you sure you want " |
1160 |
strlcat(msg, "\nAre you sure you want " |
| 1020 |
"to continue connecting (yes/no)? ", sizeof(msg)); |
1161 |
"to continue connecting (yes/no)? ", sizeof(msg)); |
| 1021 |
if (!confirm(msg)) |
1162 |
if (!confirm(msg)) |
| 1022 |
goto fail; |
1163 |
goto fail; |
|
|
1164 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1165 |
} |
| 1166 |
#endif |
| 1023 |
} else { |
1167 |
} else { |
| 1024 |
logit("%s", msg); |
1168 |
logit("%s", msg); |
| 1025 |
} |
1169 |
} |
|
Lines 1060-1071
Link Here
|
| 1060 |
if (!key_is_cert(host_key) && options.verify_host_key_dns && |
1204 |
if (!key_is_cert(host_key) && options.verify_host_key_dns && |
| 1061 |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
1205 |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
| 1062 |
|
1206 |
|
|
|
1207 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1208 |
/* |
| 1209 |
* local validation can result in a non-secure, but trusted |
| 1210 |
* response. For example, in a corporate network the authoritative |
| 1211 |
* server for internal DNS may be on the internal network, behind |
| 1212 |
* a firewall. Local validation policy can be configured to trust |
| 1213 |
* these results without using DNSSEC to validate them. |
| 1214 |
*/ |
| 1215 |
if (!(flags & DNS_VERIFY_TRUSTED)) { |
| 1216 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1217 |
error("@ WARNING: UNTRUSTED DNS RESOLUTION FOR HOST KEY! @"); |
| 1218 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1219 |
} |
| 1220 |
if (flags & DNS_VERIFY_SECURE) |
| 1221 |
validated_host_key_dns = 1; |
| 1222 |
#endif |
| 1223 |
|
| 1063 |
if (flags & DNS_VERIFY_FOUND) { |
1224 |
if (flags & DNS_VERIFY_FOUND) { |
| 1064 |
|
1225 |
|
| 1065 |
if (options.verify_host_key_dns == 1 && |
1226 |
if (options.verify_host_key_dns == 1 && |
| 1066 |
flags & DNS_VERIFY_MATCH && |
1227 |
flags & DNS_VERIFY_MATCH && |
| 1067 |
flags & DNS_VERIFY_SECURE) |
1228 |
flags & DNS_VERIFY_SECURE) |
|
|
1229 |
#ifndef DNSSEC_LOCAL_VALIDATION |
| 1068 |
return 0; |
1230 |
return 0; |
|
|
1231 |
#else |
| 1232 |
{ |
| 1233 |
if (flags & DNS_VERIFY_MATCH) |
| 1234 |
matching_host_key_dns = 1; |
| 1235 |
if (options.autoanswer_validated_keys) |
| 1236 |
return check_host_key(host, hostaddr, options.port, |
| 1237 |
host_key, RDRW, |
| 1238 |
options.user_hostfile, |
| 1239 |
options.system_hostfile); |
| 1240 |
else |
| 1241 |
return 0; |
| 1242 |
} |
| 1243 |
#endif |
| 1069 |
|
1244 |
|
| 1070 |
if (flags & DNS_VERIFY_MATCH) { |
1245 |
if (flags & DNS_VERIFY_MATCH) { |
| 1071 |
matching_host_key_dns = 1; |
1246 |
matching_host_key_dns = 1; |
|
Lines 1218-1226
Link Here
|
| 1218 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1393 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1219 |
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); |
1394 |
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); |
| 1220 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1395 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
|
|
1396 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1397 |
if (matching_host_key_dns && validated_host_key_dns) { |
| 1398 |
error("Howerver, a matching host key, validated by DNSSEC, was found."); |
| 1399 |
} |
| 1400 |
else { |
| 1401 |
#endif |
| 1221 |
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); |
1402 |
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); |
| 1222 |
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); |
1403 |
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); |
| 1223 |
error("It is also possible that the %s host key has just been changed.", type); |
1404 |
error("It is also possible that the %s host key has just been changed.", type); |
|
|
1405 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1406 |
} |
| 1407 |
#endif |
| 1224 |
error("The %sfingerprint for the %s key sent by the remote host is\n%s.", |
1408 |
error("The %sfingerprint for the %s key sent by the remote host is\n%s.", |
| 1225 |
fips_on ? "SHA1 ":"", type, fp); |
1409 |
fips_on ? "SHA1 ":"", type, fp); |
| 1226 |
error("Please contact your system administrator."); |
1410 |
error("Please contact your system administrator."); |