GNOME Bugzilla – Bug 545445
SSH's "Offending key" message results in connection timeout
Last modified: 2018-05-04 10:30:55 UTC
Please describe the problem: On a small home network with a NAT router doing DHCP and multiple Linux machines with sshd running, I occassionally get into a situation where ssh has a problem connecting via ssh because host keys do not match for the IP (but for the host) or vice-versa. When manually connecting to such a server via "ssh" in the terminal, I get: Warning: the RSA host key for 'serverhostname' differs from the key for the IP address 'XX.XX.XX.XX' Offending key for IP in /home/username/.ssh/known_hosts:123 Matching host key in /home/username/.ssh/known_hosts:32 Are you sure you want to continue connecting (yes/no)? I can then choose to accept the changed key or not. This should be handled in the sftp backend, too, by asking a question similiar to the case where no host key is saved locally ("The identify of the remote computer (...) is unknown[...]"). This should probably be handled with a similiar dialog to the handling for the string "The authenticity of host" in handle_login(), but stating that there is a new host key, but an old one matches (or something like that). By looking at the source, I think this should be handled in "handle_login()" in "daemon/gvfsbackendsftp.c". By the way: Maybe the host key verification failure should also be handled graphically, see http://www.linux-club.de/viewtopic.php?f=38&t=48887 for a sample message output of the "remote host identification has changed" warning. Steps to reproduce: 1. Have to computers (or virtual machines, I'll call them computer X and computer Y) on the local network, each with their own sshd, a DIFFERENT hostname and a DIFFERENT host key. 2. Have to free IPs to assign to these machines (I'll call them IP A and IP B here) 3. Assign IP A to computer X and IP B to computer Y 4. Connect via ssh to X and Y and save the host keys for each of them 5. Assign IP B to computer X and IP A to computer Y 6. Try to connect to X (or Y) via gvfs' sftp backend Actual results: A timeout error occurs, looking as if the server went offline when in fact the ssh process is just waiting for an answer to the question "Offending key, Matching host key". Expected results: A GTK dialog box popping up and asking me if I want to continue connecting, and stating that the host key has changed (something like the dialog for the case where the host key is not known). Does this happen every time? Yes Other information: The current behaviour is misleading, because if the user does not know how to use the "ssh" command-line client, this effectively locks her out of a sftp connection and it's not possible to connect to such a server with changed host keys or IPs, even though it's possible to connect once with "ssh" and answer the question correctly. After having "fixed" the issue with "ssh", the sftp backend starts working again, because on subsequent connects, the question is not asked anymore. It seems like you have to use the hostname for the machine to get this "Offending key" and "Matching key" messages. Plain IPs won't work (you'll get the "remote host identification has changed" warning).
Created attachment 115578 [details] [review] Patch Hi Thomas, thank you very much for the detailed explanation. I don't have the network configuration needed to reproduce this problem, so I don't actually know whether the attached patch works or not. Could you confirm it please? We should probably add a better explanation of the problem in the dialog message too, but let's see if the patch is correct before.
I've tested your patch and it works fine for the situation described. We just have to work on the wording. Here's how you can test it too: 1.) Backup and move out of the way your ~/.ssh/known_hosts file 2.) Make sure you have HashKnownHosts set to "no" for this test in ~/.ssh/config 3.) Connect to one of your ssh accounts (use the DNS name), saving the host key 4.) Edit ~/.ssh/known_hosts like this: 1.) Duplicate the single entry, so you have two equal lines 2.) Remove the IP address from the first line 3.) In the second line, replace the host key with another one (see below) 4.) Try to connect via ssh, answer with "no" to the question 5.) Connect via the gvfs backend to the same server, you see the dialog box 5.) Revert the HashKnownHosts setting in ~/.ssh/config to the previous setting 6.) Copy the backup of ~/.ssh/known_hosts back into its regular place You can get another host key (which is invalid for your regular host) by trying to connect to a ssh server (like ssh gnome.org) and accepting the host key, which puts it into your known_hosts file where it can be copied and used.
Do you have a concrete proposal for better wording ? It looks ok to me... On the patch, I note that hostname and ipaddress may be NULL if get_hostname_and_ipaddress_from_line fails. The g_strdup_printf call handles that for hostname, but not for ipaddress.
I am ok with the wording, too, if nobody comes up with a better one (Carlos said in comment #1 that we should work on the wording).
(In reply to comment #3) > Do you have a concrete proposal for better wording ? It looks ok to me... > > On the patch, I note that hostname and ipaddress may be NULL if > get_hostname_and_ipaddress_from_line fails. > The g_strdup_printf call handles that for hostname, but not for ipaddress. > Yes, the same happens with fingerprint when get_hostname_and_fingerprint_from_line() fails. I don't know what to use in both cases instead of the fingerprint and ipaddress. (In reply to comment #4) > I am ok with the wording, too, if nobody comes up with a better one (Carlos > said in comment #1 that we should work on the wording). > It's ok for me too, I just thought someone might come up with a more user friendly message.
(In reply to comment #5) > (In reply to comment #3) > > On the patch, I note that hostname and ipaddress may be NULL if > > get_hostname_and_ipaddress_from_line fails. > > The g_strdup_printf call handles that for hostname, but not for ipaddress. > > > > Yes, the same happens with fingerprint when > get_hostname_and_fingerprint_from_line() fails. I don't know what to use in > both cases instead of the fingerprint and ipaddress. I couldn't find anything in GLib to do DNS lookups, so this might be what we want: #include <netdb.h> #include <arpa/inet.h> [...] char buf[16]; if(ipaddress == NULL) { struct hostent* h; h = gethostbyname(hostname ? hostname : op_backend->host); if(h != NULL) { ipaddress = g_strdup(inet_ntop(AF_INET, (struct in_addr *)h->h_addr, buf, 16)); } if(ipaddress == NULL) { ipaddress = g_strdup(_("unknown")); } } [...] (Source: http://beej.us/guide/bgnet/output/html/multipage/syscalls.html#dns and http://www.pronix.de/pronix-281.html) Is there some helper function to easily get an IP address string from a hostname in GLib/gvfs already that I don't know about? Maybe we should just fail and show an helpful error message ("Couldn't connect to host - please check SSH connection with a text-mode SSH client first.") so the user knows what to do in case ipaddress is NULL.
I was just facing the same issue... pretty annoying.
Created attachment 299366 [details] [review] sftp: Handle host key / IP mismatch Handle the following SSH login question by asking the user whether to continue or not: Warning: the ECDSA/RSA host key for 'hostname' differs from the key for the IP address '...' Offending key for IP in /home/username/.ssh/known_hosts:??? Matching host key in /home/username/.ssh/known_hosts:??? Are you sure you want to continue connecting (yes/no)? yes Based on a patch by Carlos Garcia Campos.
Created attachment 299367 [details] [review] sftp: Be more robust when parsing login messages Handle the case when the fingerprint could not be parsed from SSH's output.
Created attachment 299404 [details] [review] sftp: Ignore leading whitespace during login If logging in without an agent, g_str_has_prefix (buffer, "Enter passphrase for key") fails the second time around (e.g. if the first entry was incorrect) because the buffer contains a leading newline: " Enter passphrase for key '/home/user/.ssh/id_rsa': " This makes the login process timeout. To fix this, trim leading whitespace.
Review of attachment 299367 [details] [review]: Looks good!
Review of attachment 299404 [details] [review]: Looks good! (Do you have an idea how to disable the agent in GNOME?)
(In reply to Ondrej Holy from comment #13) > Review of attachment 299404 [details] [review] [review]: > > Looks good! > > (Do you have an idea how to disable the agent in GNOME?) You can grep for gnome-keyring through the dbus service files and comment it out so that it doesn't autostart then restart the session.
(In reply to Ross Lagerwall from comment #14) > (In reply to Ondrej Holy from comment #13) > > Review of attachment 299404 [details] [review] [review] [review]: > > > > Looks good! > > > > (Do you have an idea how to disable the agent in GNOME?) > > You can grep for gnome-keyring through the dbus service files and comment it > out so that it doesn't autostart then restart the session. Or you can just identify the appropriate gnome-keyring-... autostart file in /etc/xdg/autostart and remove it.
(In reply to Matthias Clasen from comment #15) > (In reply to Ross Lagerwall from comment #14) > > (In reply to Ondrej Holy from comment #13) > > > Review of attachment 299404 [details] [review] [review] [review] [review]: > > > > > > Looks good! > > > > > > (Do you have an idea how to disable the agent in GNOME?) > > > > You can grep for gnome-keyring through the dbus service files and comment it > > out so that it doesn't autostart then restart the session. > > Or you can just identify the appropriate gnome-keyring-... autostart file in > /etc/xdg/autostart and remove it. But it can still get get autostarted via dbus by programs (including gvfs) that try and use org.freedesktop.secrets or org.gnome.keyring.
Review of attachment 299366 [details] [review]: Looks good, thanks, just... ::: daemon/gvfsbackendsftp.c @@ +837,3 @@ + + /* Parse a line that looks like: + * Warning: the ECDSA/RSA host key for 'hostname' differs from the key for the IP address '...' Maybe would be good to check that we really parsing this message... @@ +871,3 @@ + +static gboolean +login_answer_yes_no (GMountSource *mount_source, (Maybe would be useful to put something like this function inside e.g. gvfsdaemonutils.c...) @@ +890,3 @@ + { + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, This isn't G_IO_ERROR_PERMISSION_DENIED, is it? @@ +909,3 @@ + { + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, dtto @@ +1231,3 @@ + "contact the system administrator."), + hostname ? hostname : op_backend->host, + ip_address ? ip_address : _("unknown")); "...for the IP address unknown..." seems to me like nonsense, wouldn't be better to just omit the address: ip_address ? ip_address : ""
Review of attachment 299367 [details] [review]: ::: daemon/gvfsbackendsftp.c @@ +1207,3 @@ "contact the system administrator."), + hostname ? hostname : op_backend->host, + fingerprint ? fingerprint : _("unknown")); I've just realized that this doesn't have to work for all translations correctly... Maybe would be good to add translators comments in which context this is used and what is the %s at least...
(In reply to Ross Lagerwall from comment #16) > (In reply to Matthias Clasen from comment #15) > > (In reply to Ross Lagerwall from comment #14) > > > (In reply to Ondrej Holy from comment #13) > > > > Review of attachment 299404 [details] [review] [review] [review] [review] [review]: > > > > > > > > Looks good! > > > > > > > > (Do you have an idea how to disable the agent in GNOME?) > > > > > > You can grep for gnome-keyring through the dbus service files and comment it > > > out so that it doesn't autostart then restart the session. > > > > Or you can just identify the appropriate gnome-keyring-... autostart file in > > /etc/xdg/autostart and remove it. > > But it can still get get autostarted via dbus by programs (including gvfs) > that try and use org.freedesktop.secrets or org.gnome.keyring. Thanks for the elaboration :-)
Created attachment 299766 [details] [review] sftp: Handle host key / IP mismatch Handle the following SSH login question by asking the user whether to continue or not: Warning: the ECDSA/RSA host key for 'hostname' differs from the key for the IP address '...' Offending key for IP in /home/username/.ssh/known_hosts:??? Matching host key in /home/username/.ssh/known_hosts:??? Are you sure you want to continue connecting (yes/no)? yes Based on a patch by Carlos Garcia Campos.
Created attachment 299767 [details] [review] sftp: Be more robust when parsing login messages Handle the case when the fingerprint could not be parsed from SSH's output.
(In reply to Ondrej Holy from comment #17) > Review of attachment 299366 [details] [review] [review]: > > Looks good, thanks, just... > > ::: daemon/gvfsbackendsftp.c > @@ +837,3 @@ > + > + /* Parse a line that looks like: > + * Warning: the ECDSA/RSA host key for 'hostname' differs from the key > for the IP address '...' > > Maybe would be good to check that we really parsing this message... Well I already check that it mostly matches: else if (strstr (buffer, "differs from the key for the IP address")) Checking further seems like more effort for little gain. > > @@ +871,3 @@ > + > +static gboolean > +login_answer_yes_no (GMountSource *mount_source, > > (Maybe would be useful to put something like this function inside e.g. > gvfsdaemonutils.c...) It's fairly specific to ssh at the moment so I'll leave it here for now. > > @@ +890,3 @@ > + { > + g_set_error_literal (error, > + G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, > > This isn't G_IO_ERROR_PERMISSION_DENIED, is it? This is what the original code had. I've changed it to G_IO_ERROR_FAILED. > > @@ +909,3 @@ > + { > + g_set_error_literal (error, > + G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, > > dtto > > @@ +1231,3 @@ > + "contact the system administrator."), > + hostname ? hostname : op_backend->host, > + ip_address ? ip_address : > _("unknown")); > > "...for the IP address unknown..." seems to me like nonsense, wouldn't be > better to just omit the address: > ip_address ? ip_address : "" I changed it to: The host key for “git.gnome.org” differs from the key for the IP address “???” I think this OK, given that it is an unlikely error condition (and it doesn't require awkward translation...) (In reply to Ondrej Holy from comment #18) > Review of attachment 299367 [details] [review] [review]: > > ::: daemon/gvfsbackendsftp.c > @@ +1207,3 @@ > "contact the system administrator."), > + hostname ? hostname : op_backend->host, > + fingerprint ? fingerprint : > _("unknown")); > > I've just realized that this doesn't have to work for all translations > correctly... Maybe would be good to add translators comments in which > context this is used and what is the %s at least... I changed it to: Can't verify the identity of “git.gnome.org”. This happens when you log in to a computer the first time. The identity sent by the remote computer is “???”. If you want to be absolutely sure it is safe to continue, contact the system administrator. I think this OK, given that it is an unlikely error condition (and it doesn't require awkward translation...)
Review of attachment 299767 [details] [review]: Looks good!
Review of attachment 299766 [details] [review]: Looks good, thanks, just formatting... Please push after branched due to the new translations. ::: daemon/gvfsbackendsftp.c @@ +840,3 @@ + * First get the hostname. + */ + startpos = strchr(buffer, '\'') + 1; Missing space between function name and parenthesis. @@ +844,3 @@ + return FALSE; + + endpos = strchr(startpos, '\''); dtto @@ +851,3 @@ + + /* Then get the ip address. */ + startpos = strchr(endpos + 1, '\'') + 1; dtto @@ +858,3 @@ + } + + endpos = strchr(startpos, '\''); dtto
Pushed to master as ab4e591a40bbcd2d0e3b11e966fad42eaf259c28. Thanks for the reviews!
I realized that get_hostname_and_ip_address from attachment 299766 [details] [review] might cause segfault theoretically, so I pushed a fix for it, see commit 4a15698.
*** Bug 312271 has been marked as a duplicate of this bug. ***