diff options
author | 1999-10-03 21:50:03 +0000 | |
---|---|---|
committer | 1999-10-03 21:50:03 +0000 | |
commit | f375c68b464ee4113713486e82750c66f3773333 (patch) | |
tree | 1f467a795fc386ed2fd30ec01734573c54f4bdb6 | |
parent | Remove commented out sample of SHMMAXPGS setting with machine-specific (diff) | |
download | wireguard-openbsd-f375c68b464ee4113713486e82750c66f3773333.tar.xz wireguard-openbsd-f375c68b464ee4113713486e82750c66f3773333.zip |
add code to detect DNS spoofing:
the main idea is to not only store the host key for the hostname but
also for the according IP address. When we check the host key in the
known_hosts file, we also check the key against the according IP address.
When the server key changes, host_status = HOST_CHANGED. If
check_host_in_hostfile() returns differing status for the IP address
that means that either DNS was spoofed or that the IP address
for the host and the host key changed at the same time.
-rw-r--r-- | usr.bin/ssh/auth-rh-rsa.c | 27 | ||||
-rw-r--r-- | usr.bin/ssh/hostfile.c | 14 | ||||
-rw-r--r-- | usr.bin/ssh/readconf.c | 10 | ||||
-rw-r--r-- | usr.bin/ssh/readconf.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/ssh.1 | 11 | ||||
-rw-r--r-- | usr.bin/ssh/ssh.c | 9 | ||||
-rw-r--r-- | usr.bin/ssh/ssh.h | 15 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect.c | 217 |
8 files changed, 200 insertions, 106 deletions
diff --git a/usr.bin/ssh/auth-rh-rsa.c b/usr.bin/ssh/auth-rh-rsa.c index bcb43126488..5f3edfab75b 100644 --- a/usr.bin/ssh/auth-rh-rsa.c +++ b/usr.bin/ssh/auth-rh-rsa.c @@ -15,7 +15,7 @@ authentication. */ #include "includes.h" -RCSID("$Id: auth-rh-rsa.c,v 1.1 1999/09/28 04:45:35 provos Exp $"); +RCSID("$Id: auth-rh-rsa.c,v 1.2 1999/10/03 21:50:03 provos Exp $"); #include "packet.h" #include "ssh.h" @@ -32,6 +32,8 @@ int auth_rhosts_rsa(struct passwd *pw, const char *client_user, int ignore_rhosts, int strict_modes) { const char *canonical_hostname; + HostStatus host_status; + BIGNUM *ke, *kn; debug("Trying rhosts with RSA host authentication for %.100s", client_user); @@ -46,15 +48,20 @@ int auth_rhosts_rsa(struct passwd *pw, const char *client_user, /* Check if we know the host and its host key. */ /* Check system-wide host file. */ - if (check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, - client_host_key_bits, client_host_key_e, - client_host_key_n) != HOST_OK) - { - /* The host key was not found. */ - debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); - packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); - return 0; - } + ke = BN_new(); + kn = BN_new(); + host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, + client_host_key_bits, client_host_key_e, + client_host_key_n, ke, kn); + BN_free(ke); + BN_free(kn); + if (host_status != HOST_OK) { + /* The host key was not found. */ + debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); + packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); + return 0; + } + /* A matching host key was found and is known. */ /* Perform the challenge-response dialog with the client for the host key. */ diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c index 9b36e39e828..6982899dec6 100644 --- a/usr.bin/ssh/hostfile.c +++ b/usr.bin/ssh/hostfile.c @@ -14,7 +14,7 @@ Functions for manipulating the known hosts files. */ #include "includes.h" -RCSID("$Id: hostfile.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); +RCSID("$Id: hostfile.c,v 1.3 1999/10/03 21:50:03 provos Exp $"); #include "packet.h" #include "ssh.h" @@ -168,7 +168,8 @@ match_hostname(const char *host, const char *pattern, unsigned int len) HostStatus check_host_in_hostfile(const char *filename, const char *host, unsigned int bits, - BIGNUM *e, BIGNUM *n) + BIGNUM *e, BIGNUM *n, + BIGNUM *ke, BIGNUM *kn) { FILE *f; char line[8192]; @@ -176,7 +177,6 @@ check_host_in_hostfile(const char *filename, char *cp, *cp2; HostStatus end_return; struct stat st; - BIGNUM *ke, *kn; /* Open the file containing the list of known hosts. */ f = fopen(filename, "r"); @@ -190,10 +190,6 @@ check_host_in_hostfile(const char *filename, return HOST_NEW; } - /* Initialize mp-int variables. */ - ke = BN_new(); - kn = BN_new(); - /* Cache the length of the host name. */ hostlen = strlen(host); @@ -235,8 +231,6 @@ check_host_in_hostfile(const char *filename, if (kbits == bits && BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) { /* Ok, they match. */ - BN_clear_free(ke); - BN_clear_free(kn); fclose(f); return HOST_OK; } @@ -246,8 +240,6 @@ check_host_in_hostfile(const char *filename, end_return = HOST_CHANGED; } /* Clear variables and close the file. */ - BN_clear_free(ke); - BN_clear_free(kn); fclose(f); /* Return either HOST_NEW or HOST_CHANGED, depending on whether we saw a diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index 91cd876705f..3b98588c87f 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/readconf.c @@ -14,7 +14,7 @@ Functions for reading the configuration files. */ #include "includes.h" -RCSID("$Id: readconf.c,v 1.7 1999/09/30 08:03:39 deraadt Exp $"); +RCSID("$Id: readconf.c,v 1.8 1999/10/03 21:50:03 provos Exp $"); #include "ssh.h" #include "cipher.h" @@ -99,8 +99,8 @@ typedef enum oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, - oBatchMode, oStrictHostKeyChecking, oCompression, oCompressionLevel, - oKeepAlives, oTISAuthentication + oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, + oCompressionLevel, oKeepAlives, oTISAuthentication } OpCodes; /* Textual representations of the tokens. */ @@ -141,6 +141,7 @@ static struct { "userknownhostsfile", oUserKnownHostsFile }, { "connectionattempts", oConnectionAttempts }, { "batchmode", oBatchMode }, + { "checkhostip", oCheckHostIP }, { "stricthostkeychecking", oStrictHostKeyChecking }, { "compression", oCompression }, { "compressionlevel", oCompressionLevel }, @@ -572,6 +573,7 @@ void initialize_options(Options *options) options->fallback_to_rsh = -1; options->use_rsh = -1; options->batch_mode = -1; + options->check_host_ip = -1; options->strict_host_key_checking = -1; options->compression = -1; options->keepalives = -1; @@ -625,6 +627,8 @@ void fill_default_options(Options *options) options->use_rsh = 0; if (options->batch_mode == -1) options->batch_mode = 0; + if (options->check_host_ip == -1) + options->check_host_ip = 1; if (options->strict_host_key_checking == -1) options->strict_host_key_checking = 2; /* 2 is default */ if (options->compression == -1) diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h index 61e1ecf09a1..f0cff751511 100644 --- a/usr.bin/ssh/readconf.h +++ b/usr.bin/ssh/readconf.h @@ -13,7 +13,7 @@ Functions for reading the configuration file. */ -/* RCSID("$Id: readconf.h,v 1.4 1999/09/30 05:03:05 deraadt Exp $"); */ +/* RCSID("$Id: readconf.h,v 1.5 1999/10/03 21:50:03 provos Exp $"); */ #ifndef READCONF_H #define READCONF_H @@ -48,6 +48,7 @@ typedef struct int fallback_to_rsh; /* Use rsh if cannot connect with ssh. */ int use_rsh; /* Always use rsh (don\'t try ssh). */ int batch_mode; /* Batch mode: do not ask for passwords. */ + int check_host_ip; /* Also keep track of keys for IP address */ int strict_host_key_checking; /* Strict host key checking. */ int compression; /* Compress packets in both directions. */ int compression_level; /* Compression level 1 (fast) to 9 (best). */ diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1 index 064d1ed344f..ffff1050c82 100644 --- a/usr.bin/ssh/ssh.1 +++ b/usr.bin/ssh/ssh.1 @@ -9,7 +9,7 @@ .\" .\" Created: Sat Apr 22 21:55:14 1995 ylo .\" -.\" $Id: ssh.1,v 1.12 1999/10/03 18:46:12 aaron Exp $ +.\" $Id: ssh.1,v 1.13 1999/10/03 21:50:04 provos Exp $ .\" .Dd September 25, 1999 .Dt SSH 1 @@ -640,6 +640,15 @@ or RSA authentication will only be attempted if the identity file exists, or an authentication agent is running. +.It Cm CheckHostIP +If this flag is set to +.Dq yes , +ssh will additionally check the host ip address in the +.Pa known_hosts +file. This allows ssh to detect if a host key changed due to DNS spoofing. +If the option is set to +.Dq no , +the check will not be executed. .It Cm StrictHostKeyChecking If this flag is set to .Dq yes , diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index 21f96348c54..bf9dc850276 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -18,7 +18,7 @@ Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada. */ #include "includes.h" -RCSID("$Id: ssh.c,v 1.21 1999/09/30 20:39:08 deraadt Exp $"); +RCSID("$Id: ssh.c,v 1.22 1999/10/03 21:50:04 provos Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -58,6 +58,9 @@ Options options; in a configuration file. */ char *host; +/* socket address the host resolves to */ +struct sockaddr_in hostaddr; + /* Flag to indicate that we have received a window change signal which has not yet been processed. This will cause a message indicating the new window size to be sent to the server a little later. This is volatile @@ -520,7 +523,7 @@ main(int ac, char **av) /* Open a connection to the remote host. This needs root privileges if rhosts_authentication is true. */ - ok = ssh_connect(host, options.port, options.connection_attempts, + ok = ssh_connect(host, &hostaddr, options.port, options.connection_attempts, !options.rhosts_authentication && !options.rhosts_rsa_authentication, original_real_uid, options.proxy_command); @@ -581,7 +584,7 @@ main(int ac, char **av) /* Log into the remote system. This never returns if the login fails. */ ssh_login(host_private_key_loaded, host_private_key, - host, &options, original_real_uid); + host, &hostaddr, &options, original_real_uid); /* We no longer need the host private key. Clear it now. */ if (host_private_key_loaded) diff --git a/usr.bin/ssh/ssh.h b/usr.bin/ssh/ssh.h index 05812fc2761..10b04bfb213 100644 --- a/usr.bin/ssh/ssh.h +++ b/usr.bin/ssh/ssh.h @@ -13,7 +13,7 @@ Generic header file for ssh. */ -/* RCSID("$Id: ssh.h,v 1.5 1999/10/01 02:38:10 provos Exp $"); */ +/* RCSID("$Id: ssh.h,v 1.6 1999/10/03 21:50:04 provos Exp $"); */ #ifndef SSH_H #define SSH_H @@ -244,7 +244,8 @@ void record_logout(int pid, const char *ttyname); second. This returns true on success, and zero on failure. If the connection is successful, this calls packet_set_connection for the connection. */ -int ssh_connect(const char *host, int port, int connection_attempts, +int ssh_connect(const char *host, struct sockaddr_in *hostaddr, + int port, int connection_attempts, int anonymous, uid_t original_real_uid, const char *proxy_command); @@ -254,8 +255,9 @@ int ssh_connect(const char *host, int port, int connection_attempts, If login fails, this function prints an error and never returns. This initializes the random state, and leaves it initialized (it will also have references from the packet module). */ -void ssh_login(int host_key_valid, RSA *host_key, - const char *host, Options *options, uid_t original_real_uid); +void ssh_login(int host_key_valid, RSA *host_key, const char *host, + struct sockaddr_in *hostaddr, Options *options, + uid_t original_real_uid); /*------------ Definitions for various authentication methods. -------*/ @@ -315,10 +317,11 @@ int match_hostname(const char *host, const char *pattern, unsigned int len); Returns HOST_OK if the host is known and has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED if the host is known but used to have a different host key. The host must be in all lowercase. */ -typedef enum { HOST_OK, HOST_NEW, HOST_CHANGED } HostStatus; +typedef enum { HOST_OK, HOST_NEW, HOST_CHANGED, HOST_DIFFER } HostStatus; HostStatus check_host_in_hostfile(const char *filename, const char *host, unsigned int bits, - BIGNUM *e, BIGNUM *n); + BIGNUM *e, BIGNUM *n, + BIGNUM *ke, BIGNUM *kn); /* Appends an entry to the host file. Returns false if the entry could not be appended. */ diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c index 5159da41ced..fcb8dd15320 100644 --- a/usr.bin/ssh/sshconnect.c +++ b/usr.bin/ssh/sshconnect.c @@ -15,7 +15,7 @@ login (authentication) dialog. */ #include "includes.h" -RCSID("$Id: sshconnect.c,v 1.11 1999/10/03 19:22:39 deraadt Exp $"); +RCSID("$Id: sshconnect.c,v 1.12 1999/10/03 21:50:04 provos Exp $"); #include <ssl/bn.h> #include "xmalloc.h" @@ -175,7 +175,8 @@ int ssh_create_socket(uid_t original_real_uid, int privileged) and %p substituted for host and port, respectively) to use to contact the daemon. */ -int ssh_connect(const char *host, int port, int connection_attempts, +int ssh_connect(const char *host, struct sockaddr_in *hostaddr, + int port, int connection_attempts, int anonymous, uid_t original_real_uid, const char *proxy_command) { @@ -183,7 +184,6 @@ int ssh_connect(const char *host, int port, int connection_attempts, int on = 1; struct servent *sp; struct hostent *hp; - struct sockaddr_in hostaddr; struct linger linger; debug("ssh_connect: getuid %d geteuid %d anon %d", @@ -217,15 +217,15 @@ int ssh_connect(const char *host, int port, int connection_attempts, debug("Trying again..."); /* Try to parse the host name as a numeric inet address. */ - memset(&hostaddr, 0, sizeof(hostaddr)); - hostaddr.sin_family = AF_INET; - hostaddr.sin_port = htons(port); - hostaddr.sin_addr.s_addr = inet_addr(host); - if ((hostaddr.sin_addr.s_addr & 0xffffffff) != 0xffffffff) + memset(hostaddr, 0, sizeof(hostaddr)); + hostaddr->sin_family = AF_INET; + hostaddr->sin_port = htons(port); + hostaddr->sin_addr.s_addr = inet_addr(host); + if ((hostaddr->sin_addr.s_addr & 0xffffffff) != 0xffffffff) { /* Valid numeric IP address */ debug("Connecting to %.100s port %d.", - inet_ntoa(hostaddr.sin_addr), port); + inet_ntoa(hostaddr->sin_addr), port); /* Create a socket. */ sock = ssh_create_socket(original_real_uid, @@ -236,7 +236,7 @@ int ssh_connect(const char *host, int port, int connection_attempts, it will help with the problems of tcp_wrappers showing the remote uid as root. */ temporarily_use_uid(original_real_uid); - if (connect(sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) + if (connect(sock, (struct sockaddr *)hostaddr, sizeof(*hostaddr)) >= 0) { /* Successful connect. */ @@ -266,12 +266,12 @@ int ssh_connect(const char *host, int port, int connection_attempts, for (i = 0; hp->h_addr_list[i]; i++) { /* Set the address to connect to. */ - hostaddr.sin_family = hp->h_addrtype; - memcpy(&hostaddr.sin_addr, hp->h_addr_list[i], - sizeof(hostaddr.sin_addr)); + hostaddr->sin_family = hp->h_addrtype; + memcpy(&hostaddr->sin_addr, hp->h_addr_list[i], + sizeof(hostaddr->sin_addr)); debug("Connecting to %.200s [%.100s] port %d.", - host, inet_ntoa(hostaddr.sin_addr), port); + host, inet_ntoa(hostaddr->sin_addr), port); /* Create a socket for connecting. */ sock = ssh_create_socket(original_real_uid, @@ -282,8 +282,8 @@ int ssh_connect(const char *host, int port, int connection_attempts, it will help with tcp_wrappers showing the remote uid as root. */ temporarily_use_uid(original_real_uid); - if (connect(sock, (struct sockaddr *)&hostaddr, - sizeof(hostaddr)) >= 0) + if (connect(sock, (struct sockaddr *)hostaddr, + sizeof(*hostaddr)) >= 0) { /* Successful connection. */ restore_uid(); @@ -990,13 +990,14 @@ int read_yes_or_no(const char *prompt, int defval) void ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost, + struct sockaddr_in *hostaddr, Options *options, uid_t original_real_uid) { int i, type; char *password; struct passwd *pw; BIGNUM *key; - RSA *host_key; + RSA *host_key, *file_key; RSA *public_key; unsigned char session_key[SSH_SESSION_KEY_LENGTH]; const char *server_user, *local_user; @@ -1004,6 +1005,7 @@ void ssh_login(int host_key_valid, unsigned char check_bytes[8]; unsigned int supported_ciphers, supported_authentications, protocol_flags; HostStatus host_status; + HostStatus ip_status; int payload_len, clen, sum_len = 0; u_int32_t rand = 0; @@ -1056,6 +1058,15 @@ void ssh_login(int host_key_valid, packet_get_bignum(host_key->n, &clen); sum_len += clen; + if (options->check_host_ip && strcmp(host, inet_ntoa(hostaddr->sin_addr))) { + /* Store the host key from the known host file in here + * so that we can compare it with the key for the IP + * address. */ + file_key = RSA_new(); + file_key->n = BN_new(); + file_key->e = BN_new(); + } + /* Get protocol flags. */ protocol_flags = packet_get_int(); packet_set_protocol_flags(protocol_flags); @@ -1082,12 +1093,13 @@ void ssh_login(int host_key_valid, or in the systemwide list. */ host_status = check_host_in_hostfile(options->user_hostfile, host, BN_num_bits(host_key->n), - host_key->e, host_key->n); + host_key->e, host_key->n, + file_key->e, file_key->n); if (host_status == HOST_NEW) host_status = check_host_in_hostfile(options->system_hostfile, host, BN_num_bits(host_key->n), - host_key->e, host_key->n); - + host_key->e, host_key->n, + file_key->e, file_key->n); /* Force accepting of the host key for localhost and 127.0.0.1. The problem is that if the home directory is NFS-mounted to multiple machines, localhost will refer to a different machine in each of them, @@ -1101,68 +1113,131 @@ void ssh_login(int host_key_valid, host_status = HOST_OK; } - switch (host_status) + /* Also perform check for the ip address */ + if (options->check_host_ip && strcmp(host, inet_ntoa(hostaddr->sin_addr))) { + RSA *ip_key = RSA_new(); + ip_key->n = BN_new(); + ip_key->e = BN_new(); + ip_status = check_host_in_hostfile(options->user_hostfile, + inet_ntoa(hostaddr->sin_addr), + BN_num_bits(host_key->n), + host_key->e, host_key->n, + ip_key->e, ip_key->n); + + if (ip_status == HOST_NEW) + ip_status = check_host_in_hostfile(options->system_hostfile, + inet_ntoa(hostaddr->sin_addr), + BN_num_bits(host_key->n), + host_key->e, host_key->n, + ip_key->e, ip_key->n); + if (ip_status == HOST_CHANGED && host_status == HOST_CHANGED && + (BN_cmp(ip_key->e, file_key->e) || BN_cmp(ip_key->n, file_key->n))) + ip_status = HOST_DIFFER; + + RSA_free(ip_key); + RSA_free(file_key); + } else + ip_status = host_status; + + switch (host_status) { + case HOST_OK: + /* The host is known and the key matches. */ + debug("Host '%.200s' is known and matches the host key.", host); + if (options->check_host_ip) { + if (ip_status == HOST_NEW) { + if (!add_host_to_hostfile(options->user_hostfile, + inet_ntoa(hostaddr->sin_addr), + BN_num_bits(host_key->n), + host_key->e, host_key->n)) + log("Failed to add the host ip to the list of known hosts (%.30s).", + options->user_hostfile); + else + log("Warning: Permanently added host ip '%.30s' to the list of known hosts.", inet_ntoa(hostaddr->sin_addr)); + } else if (ip_status != HOST_OK) + log("Warning: the host key differ from the key of the ip address '%.30s' differs", inet_ntoa(hostaddr->sin_addr)); + } + + break; + case HOST_NEW: { - case HOST_OK: - /* The host is known and the key matches. */ - debug("Host '%.200s' is known and matches the host key.", host); - break; - case HOST_NEW: + char hostline[1000], *hostp = hostline; /* The host is new. */ - if (options->strict_host_key_checking == 1) - { /* User has requested strict host key checking. We will not - add the host key automatically. The only alternative left - is to abort. */ - fatal("No host key is known for %.200s and you have requested strict checking.", host); - } - else if (options->strict_host_key_checking == 2) /* The default */ - { - char prompt[1024]; - sprintf(prompt, - "The authenticity of host '%.200s' can't be established.\n" - "Are you sure you want to continue connecting (yes/no)? ", - host); - if (!read_yes_or_no(prompt, -1)) - fatal("Aborted by user!\n"); - } + if (options->strict_host_key_checking == 1) { + /* User has requested strict host key checking. We will not + add the host key automatically. The only alternative left + is to abort. */ + fatal("No host key is known for %.200s and you have requested strict checking.", host); + } else if (options->strict_host_key_checking == 2) { /* The default */ + char prompt[1024]; + snprintf(prompt, sizeof(prompt), + "The authenticity of host '%.200s' can't be established.\n" + "Are you sure you want to continue connecting (yes/no)? ", + host); + if (!read_yes_or_no(prompt, -1)) + fatal("Aborted by user!\n"); + } + + if (options->check_host_ip && ip_status == HOST_NEW && + strcmp(host, inet_ntoa(hostaddr->sin_addr))) + snprintf(hostline, sizeof(hostline), "%s,%s", + host, inet_ntoa(hostaddr->sin_addr)); + else + hostp = host; + /* If not in strict mode, add the key automatically to the local known_hosts file. */ - if (!add_host_to_hostfile(options->user_hostfile, host, + if (!add_host_to_hostfile(options->user_hostfile, hostp, BN_num_bits(host_key->n), host_key->e, host_key->n)) log("Failed to add the host to the list of known hosts (%.500s).", options->user_hostfile); else - log("Warning: Permanently added host '%.200s' to the list of known hosts.", host); - break; - case HOST_CHANGED: - /* The host key has changed. */ - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("@ WARNING: HOST IDENTIFICATION HAS CHANGED! @"); - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); - error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); - error("It is also possible that the host key has just been changed."); - error("Please contact your system administrator."); - error("Add correct host key in %.100s to get rid of this message.", - options->user_hostfile); - - /* If strict host key checking is in use, the user will have to edit - the key manually and we can only abort. */ - if (options->strict_host_key_checking) - fatal("Host key for %.200s has changed and you have requested strict checking.", host); - - /* If strict host key checking has not been requested, allow the - connection but without password authentication. */ - error("Password authentication is disabled to avoid trojan horses."); - options->password_authentication = 0; - /* XXX Should permit the user to change to use the new id. This could - be done by converting the host key to an identifying sentence, tell - that the host identifies itself by that sentence, and ask the user - if he/she whishes to accept the authentication. */ + log("Warning: Permanently added '%.200s' to the list of known hosts.", + hostp); break; } - + case HOST_CHANGED: + if (options->check_host_ip) { + if (ip_status != HOST_CHANGED) { + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: POSSIBLE DNS SPOOFNG DETECTED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("The host key for %s has changed,", host); + error("but the key for the according IP address %s has", + inet_ntoa(hostaddr->sin_addr)); + error("a different status. This could either mean that DNS"); + error("SPOOFING is happening or the IP address for the host"); + error("and its host key have changed at the same time"); + } + } + + /* The host key has changed. */ + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: HOST IDENTIFICATION HAS CHANGED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); + error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); + error("It is also possible that the host key has just been changed."); + error("Please contact your system administrator."); + error("Add correct host key in %.100s to get rid of this message.", + options->user_hostfile); + + /* If strict host key checking is in use, the user will have to edit + the key manually and we can only abort. */ + if (options->strict_host_key_checking) + fatal("Host key for %.200s has changed and you have requested strict checking.", host); + + /* If strict host key checking has not been requested, allow the + connection but without password authentication. */ + error("Password authentication is disabled to avoid trojan horses."); + options->password_authentication = 0; + /* XXX Should permit the user to change to use the new id. This could + be done by converting the host key to an identifying sentence, tell + that the host identifies itself by that sentence, and ask the user + if he/she whishes to accept the authentication. */ + break; + } + /* Generate a session key. */ arc4random_stir(); |