diff options
Diffstat (limited to 'usr.bin')
-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(); |