|
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 66-71
char *client_version_string = NULL;
Link Here
|
| 66 |
char *server_version_string = NULL; |
70 |
char *server_version_string = NULL; |
| 67 |
|
71 |
|
| 68 |
static int matching_host_key_dns = 0; |
72 |
static int matching_host_key_dns = 0; |
|
|
73 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 74 |
static int validated_host_key_dns = 0; |
| 75 |
#endif |
| 69 |
|
76 |
|
| 70 |
static pid_t proxy_command_pid = 0; |
77 |
static pid_t proxy_command_pid = 0; |
| 71 |
|
78 |
|
|
Lines 77-82
extern uid_t original_effective_uid;
Link Here
|
| 77 |
|
84 |
|
| 78 |
static int show_other_keys(struct hostkeys *, Key *); |
85 |
static int show_other_keys(struct hostkeys *, 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 342-348
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
Link Here
|
| 342 |
int on = 1; |
350 |
int on = 1; |
| 343 |
int sock = -1, attempt; |
351 |
int sock = -1, attempt; |
| 344 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
352 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
| 345 |
struct addrinfo hints, *ai, *aitop; |
353 |
struct addrinfo hints; |
|
|
354 |
struct addrinfo *ai, *aitop = NULL; |
| 355 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 356 |
val_status_t val_status; |
| 357 |
#endif |
| 346 |
|
358 |
|
| 347 |
debug2("ssh_connect: needpriv %d", needpriv); |
359 |
debug2("ssh_connect: needpriv %d", needpriv); |
| 348 |
|
360 |
|
|
Lines 356-364
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
Link Here
|
| 356 |
hints.ai_family = family; |
368 |
hints.ai_family = family; |
| 357 |
hints.ai_socktype = SOCK_STREAM; |
369 |
hints.ai_socktype = SOCK_STREAM; |
| 358 |
snprintf(strport, sizeof strport, "%u", port); |
370 |
snprintf(strport, sizeof strport, "%u", port); |
|
|
371 |
#ifndef DNSSEC_LOCAL_VALIDATION |
| 359 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
372 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) |
| 360 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
373 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
| 361 |
host, ssh_gai_strerror(gaierr)); |
374 |
host, ssh_gai_strerror(gaierr)); |
|
|
375 |
#else |
| 376 |
gaierr = val_getaddrinfo(NULL, host, strport, &hints, &aitop, |
| 377 |
&val_status); |
| 378 |
debug2("ssh_connect: gaierr %d, val_status %d / %s; trusted: %d", |
| 379 |
gaierr, val_status, p_val_status(val_status), |
| 380 |
val_istrusted(val_status)); |
| 381 |
if (gaierr != 0) { |
| 382 |
if (VAL_GETADDRINFO_HAS_STATUS(gaierr) && |
| 383 |
!val_istrusted(val_status)) { |
| 384 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 385 |
error("@ WARNING: UNTRUSTED ERROR IN DNS RESOLUTION FOR HOST! @"); |
| 386 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 387 |
error("The authenticity of DNS response is not trusted (%s).", |
| 388 |
p_val_status(val_status)); |
| 389 |
} |
| 390 |
fatal("%s: Could not resolve hostname %.100s: %s", __progname, |
| 391 |
host, ssh_gai_strerror(gaierr)); |
| 392 |
} |
| 393 |
if (!val_istrusted(val_status)) { |
| 394 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 395 |
error("@ WARNING: UNTRUSTED DNS RESOLUTION FOR HOST IP ADRRESS! @"); |
| 396 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 397 |
error("The authenticity of DNS data for the host '%.200s' " |
| 398 |
"can't be established.", host); |
| 399 |
if (options.strict_dnssec_checking == 1) { |
| 400 |
fatal("DNS resolution is not trusted (%s) " |
| 401 |
"and you have requested strict checking", |
| 402 |
p_val_status(val_status)); |
| 403 |
} else if (options.strict_dnssec_checking == 2) { |
| 404 |
char msg[1024]; |
| 405 |
for (ai = aitop; ai; ai = ai->ai_next) { |
| 406 |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
| 407 |
continue; |
| 408 |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, |
| 409 |
ntop, sizeof(ntop), strport, sizeof(strport), |
| 410 |
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
| 411 |
error("ssh_connect: getnameinfo failed"); |
| 412 |
continue; |
| 413 |
} |
| 414 |
error(" IP address %s port %s", ntop, strport); |
| 415 |
} |
| 416 |
snprintf(msg,sizeof(msg), |
| 417 |
"Are you sure you want to attempt to connect " |
| 418 |
"(yes/no)? "); |
| 419 |
if (!confirm(msg)) |
| 420 |
return (-1); |
| 421 |
} |
| 422 |
} |
| 423 |
#endif /* DNSSEC_LOCAL_VALIDATION */ |
| 362 |
|
424 |
|
| 363 |
for (attempt = 0; attempt < connection_attempts; attempt++) { |
425 |
for (attempt = 0; attempt < connection_attempts; attempt++) { |
| 364 |
if (attempt > 0) { |
426 |
if (attempt > 0) { |
|
Lines 814-819
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 814 |
} |
876 |
} |
| 815 |
break; |
877 |
break; |
| 816 |
case HOST_NEW: |
878 |
case HOST_NEW: |
|
|
879 |
debug("Host '%.200s' new.", host); |
| 817 |
if (options.host_key_alias == NULL && port != 0 && |
880 |
if (options.host_key_alias == NULL && port != 0 && |
| 818 |
port != SSH_DEFAULT_PORT) { |
881 |
port != SSH_DEFAULT_PORT) { |
| 819 |
debug("checking without port identifier"); |
882 |
debug("checking without port identifier"); |
|
Lines 860-865
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 860 |
"No matching host key fingerprint" |
923 |
"No matching host key fingerprint" |
| 861 |
" found in DNS.\n"); |
924 |
" found in DNS.\n"); |
| 862 |
} |
925 |
} |
|
|
926 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 927 |
if (options.autoanswer_validated_keys && |
| 928 |
validated_host_key_dns && matching_host_key_dns) { |
| 929 |
snprintf(msg, sizeof(msg), |
| 930 |
"The authenticity of host '%.200s (%s)' was " |
| 931 |
" validated via DNSSEC%s", |
| 932 |
host, ip, msg1); |
| 933 |
logit(msg); |
| 934 |
xfree(fp); |
| 935 |
} else { |
| 936 |
#endif |
| 863 |
snprintf(msg, sizeof(msg), |
937 |
snprintf(msg, sizeof(msg), |
| 864 |
"The authenticity of host '%.200s (%s)' can't be " |
938 |
"The authenticity of host '%.200s (%s)' can't be " |
| 865 |
"established%s\n" |
939 |
"established%s\n" |
|
Lines 874-879
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 874 |
xfree(fp); |
948 |
xfree(fp); |
| 875 |
if (!confirm(msg)) |
949 |
if (!confirm(msg)) |
| 876 |
goto fail; |
950 |
goto fail; |
|
|
951 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 952 |
} |
| 953 |
#endif |
| 877 |
} |
954 |
} |
| 878 |
/* |
955 |
/* |
| 879 |
* If not in strict mode, add the key automatically to the |
956 |
* If not in strict mode, add the key automatically to the |
|
Lines 948-953
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 948 |
key_msg = "is unchanged"; |
1025 |
key_msg = "is unchanged"; |
| 949 |
else |
1026 |
else |
| 950 |
key_msg = "has a different value"; |
1027 |
key_msg = "has a different value"; |
|
|
1028 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1029 |
if (!validated_host_key_dns) { |
| 951 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1030 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 952 |
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); |
1031 |
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); |
| 953 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1032 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
|
Lines 956-961
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 956 |
error("%s. This could either mean that", key_msg); |
1035 |
error("%s. This could either mean that", key_msg); |
| 957 |
error("DNS SPOOFING is happening or the IP address for the host"); |
1036 |
error("DNS SPOOFING is happening or the IP address for the host"); |
| 958 |
error("and its host key have changed at the same time."); |
1037 |
error("and its host key have changed at the same time."); |
|
|
1038 |
} |
| 1039 |
else { |
| 1040 |
#endif |
| 1041 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1042 |
error("@ WARNING: HOST IP ADDRESS HAS CHANGED! @"); |
| 1043 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1044 |
error("The %s host key for %s has changed,", type, host); |
| 1045 |
error("and the key for the according IP address %s", ip); |
| 1046 |
error("%s. The IP address for the host", key_msg); |
| 1047 |
error("and its host key have changed at the same time."); |
| 1048 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1049 |
} |
| 1050 |
#endif |
| 959 |
if (ip_status != HOST_NEW) |
1051 |
if (ip_status != HOST_NEW) |
| 960 |
error("Offending key for IP in %s:%lu", |
1052 |
error("Offending key for IP in %s:%lu", |
| 961 |
ip_found->file, ip_found->line); |
1053 |
ip_found->file, ip_found->line); |
|
Lines 971-981
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 971 |
* If strict host key checking is in use, the user will have |
1063 |
* If strict host key checking is in use, the user will have |
| 972 |
* to edit the key manually and we can only abort. |
1064 |
* to edit the key manually and we can only abort. |
| 973 |
*/ |
1065 |
*/ |
|
|
1066 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1067 |
if ((options.strict_host_key_checking == 2) && |
| 1068 |
options.autoanswer_validated_keys && |
| 1069 |
matching_host_key_dns && validated_host_key_dns) { |
| 1070 |
logit("The authenticity of host '%.200s (%s)' was " |
| 1071 |
" validated via DNSSEC.", |
| 1072 |
host, ip); |
| 1073 |
/* |
| 1074 |
* If not in strict mode, add the key automatically to the |
| 1075 |
* local known_hosts file. |
| 1076 |
*/ |
| 1077 |
if (options.check_host_ip && ip_status == HOST_NEW) { |
| 1078 |
snprintf(hostline, sizeof(hostline), "%s,%s", |
| 1079 |
host, ip); |
| 1080 |
hostp = hostline; |
| 1081 |
if (options.hash_known_hosts) { |
| 1082 |
/* Add hash of host and IP separately */ |
| 1083 |
r = add_host_to_hostfile(user_hostfile, host, |
| 1084 |
host_key, options.hash_known_hosts) && |
| 1085 |
add_host_to_hostfile(user_hostfile, ip, |
| 1086 |
host_key, options.hash_known_hosts); |
| 1087 |
} else { |
| 1088 |
/* Add unhashed "host,ip" */ |
| 1089 |
r = add_host_to_hostfile(user_hostfile, |
| 1090 |
hostline, host_key, |
| 1091 |
options.hash_known_hosts); |
| 1092 |
} |
| 1093 |
} else { |
| 1094 |
r = add_host_to_hostfile(user_hostfile, host, host_key, |
| 1095 |
options.hash_known_hosts); |
| 1096 |
hostp = host; |
| 1097 |
} |
| 1098 |
|
| 1099 |
if (!r) |
| 1100 |
logit("Failed to add the host to the list of known " |
| 1101 |
"hosts (%.500s).", user_hostfile); |
| 1102 |
else |
| 1103 |
logit("Warning: Permanently added '%.200s' (%s) to the " |
| 1104 |
"list of known hosts.", hostp, type); |
| 1105 |
} |
| 1106 |
else |
| 1107 |
#endif |
| 974 |
if (options.strict_host_key_checking) { |
1108 |
if (options.strict_host_key_checking) { |
| 975 |
error("%s host key for %.200s has changed and you have " |
1109 |
error("%s host key for %.200s has changed and you have " |
| 976 |
"requested strict checking.", type, host); |
1110 |
"requested strict checking.", type, host); |
| 977 |
goto fail; |
1111 |
goto fail; |
| 978 |
} |
1112 |
} else { |
| 979 |
|
1113 |
|
| 980 |
continue_unsafe: |
1114 |
continue_unsafe: |
| 981 |
/* |
1115 |
/* |
|
Lines 1039-1044
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 1039 |
* by that sentence, and ask the user if he/she wishes to |
1173 |
* by that sentence, and ask the user if he/she wishes to |
| 1040 |
* accept the authentication. |
1174 |
* accept the authentication. |
| 1041 |
*/ |
1175 |
*/ |
|
|
1176 |
} |
| 1042 |
break; |
1177 |
break; |
| 1043 |
case HOST_FOUND: |
1178 |
case HOST_FOUND: |
| 1044 |
fatal("internal error"); |
1179 |
fatal("internal error"); |
|
Lines 1063-1072
check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
Link Here
|
| 1063 |
error("Exiting, you have requested strict checking."); |
1198 |
error("Exiting, you have requested strict checking."); |
| 1064 |
goto fail; |
1199 |
goto fail; |
| 1065 |
} else if (options.strict_host_key_checking == 2) { |
1200 |
} else if (options.strict_host_key_checking == 2) { |
|
|
1201 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1202 |
if (options.autoanswer_validated_keys && |
| 1203 |
matching_host_key_dns && validated_host_key_dns) { |
| 1204 |
logit("%s", msg); |
| 1205 |
} else { |
| 1206 |
#endif |
| 1066 |
strlcat(msg, "\nAre you sure you want " |
1207 |
strlcat(msg, "\nAre you sure you want " |
| 1067 |
"to continue connecting (yes/no)? ", sizeof(msg)); |
1208 |
"to continue connecting (yes/no)? ", sizeof(msg)); |
| 1068 |
if (!confirm(msg)) |
1209 |
if (!confirm(msg)) |
| 1069 |
goto fail; |
1210 |
goto fail; |
|
|
1211 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1212 |
} |
| 1213 |
#endif |
| 1070 |
} else { |
1214 |
} else { |
| 1071 |
logit("%s", msg); |
1215 |
logit("%s", msg); |
| 1072 |
} |
1216 |
} |
|
Lines 1118-1129
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
Link Here
|
| 1118 |
/* XXX certs are not yet supported for DNS */ |
1262 |
/* XXX certs are not yet supported for DNS */ |
| 1119 |
if (!key_is_cert(host_key) && options.verify_host_key_dns && |
1263 |
if (!key_is_cert(host_key) && options.verify_host_key_dns && |
| 1120 |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
1264 |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
|
|
1265 |
|
| 1266 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1267 |
/* |
| 1268 |
* local validation can result in a non-secure, but trusted |
| 1269 |
* response. For example, in a corporate network the authoritative |
| 1270 |
* server for internal DNS may be on the internal network, behind |
| 1271 |
* a firewall. Local validation policy can be configured to trust |
| 1272 |
* these results without using DNSSEC to validate them. |
| 1273 |
*/ |
| 1274 |
if (!(flags & DNS_VERIFY_TRUSTED)) { |
| 1275 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1276 |
error("@ WARNING: UNTRUSTED DNS RESOLUTION FOR HOST KEY! @"); |
| 1277 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1278 |
} |
| 1279 |
if (flags & DNS_VERIFY_SECURE) |
| 1280 |
validated_host_key_dns = 1; |
| 1281 |
#endif |
| 1282 |
|
| 1121 |
if (flags & DNS_VERIFY_FOUND) { |
1283 |
if (flags & DNS_VERIFY_FOUND) { |
| 1122 |
|
1284 |
|
| 1123 |
if (options.verify_host_key_dns == 1 && |
1285 |
if (options.verify_host_key_dns == 1 && |
| 1124 |
flags & DNS_VERIFY_MATCH && |
1286 |
flags & DNS_VERIFY_MATCH && |
| 1125 |
flags & DNS_VERIFY_SECURE) |
1287 |
flags & DNS_VERIFY_SECURE) |
|
|
1288 |
#ifndef DNSSEC_LOCAL_VALIDATION |
| 1126 |
return 0; |
1289 |
return 0; |
|
|
1290 |
#else |
| 1291 |
{ |
| 1292 |
if (flags & DNS_VERIFY_MATCH) |
| 1293 |
matching_host_key_dns = 1; |
| 1294 |
if (options.autoanswer_validated_keys) |
| 1295 |
return check_host_key(host, hostaddr, options.port, |
| 1296 |
host_key, RDRW, |
| 1297 |
options.user_hostfile, |
| 1298 |
options.system_hostfile); |
| 1299 |
else |
| 1300 |
return 0; |
| 1301 |
} |
| 1302 |
#endif |
| 1127 |
|
1303 |
|
| 1128 |
if (flags & DNS_VERIFY_MATCH) { |
1304 |
if (flags & DNS_VERIFY_MATCH) { |
| 1129 |
matching_host_key_dns = 1; |
1305 |
matching_host_key_dns = 1; |
|
Lines 1240-1248
warn_changed_key(Key *host_key)
Link Here
|
| 1240 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1416 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
| 1241 |
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); |
1417 |
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); |
| 1242 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1418 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
|
|
1419 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1420 |
if (matching_host_key_dns && validated_host_key_dns) { |
| 1421 |
error("Howerver, a matching host key, validated by DNSSEC, was found."); |
| 1422 |
} |
| 1423 |
else { |
| 1424 |
#endif |
| 1243 |
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); |
1425 |
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); |
| 1244 |
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); |
1426 |
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); |
| 1245 |
error("It is also possible that a host key has just been changed."); |
1427 |
error("It is also possible that a host key has just been changed."); |
|
|
1428 |
#ifdef DNSSEC_LOCAL_VALIDATION |
| 1429 |
} |
| 1430 |
#endif |
| 1246 |
error("The fingerprint for the %s key sent by the remote host is\n%s.", |
1431 |
error("The fingerprint for the %s key sent by the remote host is\n%s.", |
| 1247 |
key_type(host_key), fp); |
1432 |
key_type(host_key), fp); |
| 1248 |
error("Please contact your system administrator."); |
1433 |
error("Please contact your system administrator."); |