diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 110 |
1 files changed, 82 insertions, 28 deletions
diff --git a/sshconnect.c b/sshconnect.c index 563405ecb..a6c9e20ed 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.259 2015/01/28 22:36:00 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 |
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include "includes.h" | 16 | #include "includes.h" |
17 | 17 | ||
18 | #include <sys/param.h> /* roundup */ | ||
18 | #include <sys/types.h> | 19 | #include <sys/types.h> |
19 | #include <sys/wait.h> | 20 | #include <sys/wait.h> |
20 | #include <sys/stat.h> | 21 | #include <sys/stat.h> |
@@ -62,6 +63,8 @@ | |||
62 | #include "monitor_fdpass.h" | 63 | #include "monitor_fdpass.h" |
63 | #include "ssh2.h" | 64 | #include "ssh2.h" |
64 | #include "version.h" | 65 | #include "version.h" |
66 | #include "authfile.h" | ||
67 | #include "ssherr.h" | ||
65 | 68 | ||
66 | char *client_version_string = NULL; | 69 | char *client_version_string = NULL; |
67 | char *server_version_string = NULL; | 70 | char *server_version_string = NULL; |
@@ -625,7 +628,7 @@ ssh_exchange_identification(int timeout_ms) | |||
625 | debug("Remote protocol version %d.%d, remote software version %.100s", | 628 | debug("Remote protocol version %d.%d, remote software version %.100s", |
626 | remote_major, remote_minor, remote_version); | 629 | remote_major, remote_minor, remote_version); |
627 | 630 | ||
628 | compat_datafellows(remote_version); | 631 | active_state->compat = compat_datafellows(remote_version); |
629 | mismatch = 0; | 632 | mismatch = 0; |
630 | 633 | ||
631 | switch (remote_major) { | 634 | switch (remote_major) { |
@@ -767,7 +770,7 @@ get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr, | |||
767 | if (options.proxy_command == NULL) { | 770 | if (options.proxy_command == NULL) { |
768 | if (getnameinfo(hostaddr, addrlen, | 771 | if (getnameinfo(hostaddr, addrlen, |
769 | ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) | 772 | ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) |
770 | fatal("check_host_key: getnameinfo failed"); | 773 | fatal("%s: getnameinfo failed", __func__); |
771 | *hostfile_ipaddr = put_host_port(ntop, port); | 774 | *hostfile_ipaddr = put_host_port(ntop, port); |
772 | } else { | 775 | } else { |
773 | *hostfile_ipaddr = xstrdup("<no hostip for proxy " | 776 | *hostfile_ipaddr = xstrdup("<no hostip for proxy " |
@@ -815,6 +818,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
815 | int len, cancelled_forwarding = 0; | 818 | int len, cancelled_forwarding = 0; |
816 | int local = sockaddr_is_local(hostaddr); | 819 | int local = sockaddr_is_local(hostaddr); |
817 | int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; | 820 | int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; |
821 | int hostkey_trusted = 0; /* Known or explicitly accepted by user */ | ||
818 | struct hostkeys *host_hostkeys, *ip_hostkeys; | 822 | struct hostkeys *host_hostkeys, *ip_hostkeys; |
819 | u_int i; | 823 | u_int i; |
820 | 824 | ||
@@ -915,13 +919,17 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
915 | "key for IP address '%.128s' to the list " | 919 | "key for IP address '%.128s' to the list " |
916 | "of known hosts.", type, ip); | 920 | "of known hosts.", type, ip); |
917 | } else if (options.visual_host_key) { | 921 | } else if (options.visual_host_key) { |
918 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 922 | fp = sshkey_fingerprint(host_key, |
919 | ra = key_fingerprint(host_key, SSH_FP_MD5, | 923 | options.fingerprint_hash, SSH_FP_DEFAULT); |
920 | SSH_FP_RANDOMART); | 924 | ra = sshkey_fingerprint(host_key, |
925 | options.fingerprint_hash, SSH_FP_RANDOMART); | ||
926 | if (fp == NULL || ra == NULL) | ||
927 | fatal("%s: sshkey_fingerprint fail", __func__); | ||
921 | logit("Host key fingerprint is %s\n%s\n", fp, ra); | 928 | logit("Host key fingerprint is %s\n%s\n", fp, ra); |
922 | free(ra); | 929 | free(ra); |
923 | free(fp); | 930 | free(fp); |
924 | } | 931 | } |
932 | hostkey_trusted = 1; | ||
925 | break; | 933 | break; |
926 | case HOST_NEW: | 934 | case HOST_NEW: |
927 | if (options.host_key_alias == NULL && port != 0 && | 935 | if (options.host_key_alias == NULL && port != 0 && |
@@ -956,9 +964,12 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
956 | else | 964 | else |
957 | snprintf(msg1, sizeof(msg1), "."); | 965 | snprintf(msg1, sizeof(msg1), "."); |
958 | /* The default */ | 966 | /* The default */ |
959 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 967 | fp = sshkey_fingerprint(host_key, |
960 | ra = key_fingerprint(host_key, SSH_FP_MD5, | 968 | options.fingerprint_hash, SSH_FP_DEFAULT); |
961 | SSH_FP_RANDOMART); | 969 | ra = sshkey_fingerprint(host_key, |
970 | options.fingerprint_hash, SSH_FP_RANDOMART); | ||
971 | if (fp == NULL || ra == NULL) | ||
972 | fatal("%s: sshkey_fingerprint fail", __func__); | ||
962 | msg2[0] = '\0'; | 973 | msg2[0] = '\0'; |
963 | if (options.verify_host_key_dns) { | 974 | if (options.verify_host_key_dns) { |
964 | if (matching_host_key_dns) | 975 | if (matching_host_key_dns) |
@@ -984,6 +995,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
984 | free(fp); | 995 | free(fp); |
985 | if (!confirm(msg)) | 996 | if (!confirm(msg)) |
986 | goto fail; | 997 | goto fail; |
998 | hostkey_trusted = 1; /* user explicitly confirmed */ | ||
987 | } | 999 | } |
988 | /* | 1000 | /* |
989 | * If not in strict mode, add the key automatically to the | 1001 | * If not in strict mode, add the key automatically to the |
@@ -1187,6 +1199,12 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
1187 | } | 1199 | } |
1188 | } | 1200 | } |
1189 | 1201 | ||
1202 | if (!hostkey_trusted && options.update_hostkeys) { | ||
1203 | debug("%s: hostkey not known or explicitly trusted: " | ||
1204 | "disabling UpdateHostkeys", __func__); | ||
1205 | options.update_hostkeys = 0; | ||
1206 | } | ||
1207 | |||
1190 | free(ip); | 1208 | free(ip); |
1191 | free(host); | 1209 | free(host); |
1192 | if (host_hostkeys != NULL) | 1210 | if (host_hostkeys != NULL) |
@@ -1224,16 +1242,45 @@ int | |||
1224 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 1242 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) |
1225 | { | 1243 | { |
1226 | int r = -1, flags = 0; | 1244 | int r = -1, flags = 0; |
1227 | char *fp; | 1245 | char *fp = NULL; |
1228 | Key *plain = NULL; | 1246 | struct sshkey *plain = NULL; |
1247 | |||
1248 | if ((fp = sshkey_fingerprint(host_key, | ||
1249 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { | ||
1250 | error("%s: fingerprint host key: %s", __func__, ssh_err(r)); | ||
1251 | r = -1; | ||
1252 | goto out; | ||
1253 | } | ||
1229 | 1254 | ||
1230 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 1255 | debug("Server host key: %s %s", |
1231 | debug("Server host key: %s %s", key_type(host_key), fp); | 1256 | compat20 ? sshkey_ssh_name(host_key) : sshkey_type(host_key), fp); |
1232 | free(fp); | ||
1233 | 1257 | ||
1234 | if (key_equal(previous_host_key, host_key)) { | 1258 | if (sshkey_equal(previous_host_key, host_key)) { |
1235 | debug("%s: server host key matches cached key", __func__); | 1259 | debug2("%s: server host key %s %s matches cached key", |
1236 | return 0; | 1260 | __func__, sshkey_type(host_key), fp); |
1261 | r = 0; | ||
1262 | goto out; | ||
1263 | } | ||
1264 | |||
1265 | /* Check in RevokedHostKeys file if specified */ | ||
1266 | if (options.revoked_host_keys != NULL) { | ||
1267 | r = sshkey_check_revoked(host_key, options.revoked_host_keys); | ||
1268 | switch (r) { | ||
1269 | case 0: | ||
1270 | break; /* not revoked */ | ||
1271 | case SSH_ERR_KEY_REVOKED: | ||
1272 | error("Host key %s %s revoked by file %s", | ||
1273 | sshkey_type(host_key), fp, | ||
1274 | options.revoked_host_keys); | ||
1275 | r = -1; | ||
1276 | goto out; | ||
1277 | default: | ||
1278 | error("Error checking host key %s %s in " | ||
1279 | "revoked keys file %s: %s", sshkey_type(host_key), | ||
1280 | fp, options.revoked_host_keys, ssh_err(r)); | ||
1281 | r = -1; | ||
1282 | goto out; | ||
1283 | } | ||
1237 | } | 1284 | } |
1238 | 1285 | ||
1239 | if (options.verify_host_key_dns) { | 1286 | if (options.verify_host_key_dns) { |
@@ -1241,17 +1288,17 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1241 | * XXX certs are not yet supported for DNS, so downgrade | 1288 | * XXX certs are not yet supported for DNS, so downgrade |
1242 | * them and try the plain key. | 1289 | * them and try the plain key. |
1243 | */ | 1290 | */ |
1244 | plain = key_from_private(host_key); | 1291 | if ((r = sshkey_from_private(host_key, &plain)) != 0) |
1245 | if (key_is_cert(plain)) | 1292 | goto out; |
1246 | key_drop_cert(plain); | 1293 | if (sshkey_is_cert(plain)) |
1294 | sshkey_drop_cert(plain); | ||
1247 | if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { | 1295 | if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { |
1248 | if (flags & DNS_VERIFY_FOUND) { | 1296 | if (flags & DNS_VERIFY_FOUND) { |
1249 | if (options.verify_host_key_dns == 1 && | 1297 | if (options.verify_host_key_dns == 1 && |
1250 | flags & DNS_VERIFY_MATCH && | 1298 | flags & DNS_VERIFY_MATCH && |
1251 | flags & DNS_VERIFY_SECURE) { | 1299 | flags & DNS_VERIFY_SECURE) { |
1252 | key_free(plain); | ||
1253 | r = 0; | 1300 | r = 0; |
1254 | goto done; | 1301 | goto out; |
1255 | } | 1302 | } |
1256 | if (flags & DNS_VERIFY_MATCH) { | 1303 | if (flags & DNS_VERIFY_MATCH) { |
1257 | matching_host_key_dns = 1; | 1304 | matching_host_key_dns = 1; |
@@ -1263,14 +1310,14 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1263 | } | 1310 | } |
1264 | } | 1311 | } |
1265 | } | 1312 | } |
1266 | key_free(plain); | ||
1267 | } | 1313 | } |
1268 | |||
1269 | r = check_host_key(host, hostaddr, options.port, host_key, RDRW, | 1314 | r = check_host_key(host, hostaddr, options.port, host_key, RDRW, |
1270 | options.user_hostfiles, options.num_user_hostfiles, | 1315 | options.user_hostfiles, options.num_user_hostfiles, |
1271 | options.system_hostfiles, options.num_system_hostfiles); | 1316 | options.system_hostfiles, options.num_system_hostfiles); |
1272 | 1317 | ||
1273 | done: | 1318 | out: |
1319 | sshkey_free(plain); | ||
1320 | free(fp); | ||
1274 | if (r == 0 && host_key != NULL) { | 1321 | if (r == 0 && host_key != NULL) { |
1275 | key_free(previous_host_key); | 1322 | key_free(previous_host_key); |
1276 | previous_host_key = key_from_private(host_key); | 1323 | previous_host_key = key_from_private(host_key); |
@@ -1361,8 +1408,12 @@ show_other_keys(struct hostkeys *hostkeys, Key *key) | |||
1361 | continue; | 1408 | continue; |
1362 | if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) | 1409 | if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) |
1363 | continue; | 1410 | continue; |
1364 | fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX); | 1411 | fp = sshkey_fingerprint(found->key, |
1365 | ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART); | 1412 | options.fingerprint_hash, SSH_FP_DEFAULT); |
1413 | ra = sshkey_fingerprint(found->key, | ||
1414 | options.fingerprint_hash, SSH_FP_RANDOMART); | ||
1415 | if (fp == NULL || ra == NULL) | ||
1416 | fatal("%s: sshkey_fingerprint fail", __func__); | ||
1366 | logit("WARNING: %s key found for host %s\n" | 1417 | logit("WARNING: %s key found for host %s\n" |
1367 | "in %s:%lu\n" | 1418 | "in %s:%lu\n" |
1368 | "%s key fingerprint %s.", | 1419 | "%s key fingerprint %s.", |
@@ -1383,7 +1434,10 @@ warn_changed_key(Key *host_key) | |||
1383 | { | 1434 | { |
1384 | char *fp; | 1435 | char *fp; |
1385 | 1436 | ||
1386 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 1437 | fp = sshkey_fingerprint(host_key, options.fingerprint_hash, |
1438 | SSH_FP_DEFAULT); | ||
1439 | if (fp == NULL) | ||
1440 | fatal("%s: sshkey_fingerprint fail", __func__); | ||
1387 | 1441 | ||
1388 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); | 1442 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1389 | error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); | 1443 | error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); |