summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoss Lagerwall <rosslagerwall@gmail.com>2015-03-13 23:25:21 +0000
committerRoss Lagerwall <rosslagerwall@gmail.com>2015-04-09 22:04:29 +0100
commit336fe869f06c8e792aa20170e6278b57c1c38c05 (patch)
tree3b88d8b5ef50362611e36c46963e6480866110a6
parent4ef4dd954a87be11499ea855f846e0f1dbfa9c7b (diff)
downloadgvfs-336fe869f06c8e792aa20170e6278b57c1c38c05.tar.gz
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. https://bugzilla.gnome.org/show_bug.cgi?id=545445
-rw-r--r--daemon/gvfsbackendsftp.c159
1 files changed, 121 insertions, 38 deletions
diff --git a/daemon/gvfsbackendsftp.c b/daemon/gvfsbackendsftp.c
index 576b74e6..e6c1d5b5 100644
--- a/daemon/gvfsbackendsftp.c
+++ b/daemon/gvfsbackendsftp.c
@@ -828,6 +828,94 @@ get_hostname_and_fingerprint_from_line (const gchar *buffer,
return TRUE;
}
+static gboolean
+get_hostname_and_ip_address (const gchar *buffer,
+ gchar **hostname_out,
+ gchar **ip_address_out)
+{
+ char *startpos, *endpos;
+
+ /* Parse a line that looks like:
+ * Warning: the ECDSA/RSA host key for 'hostname' differs from the key for the IP address '...'
+ * First get the hostname.
+ */
+ startpos = strchr (buffer, '\'') + 1;
+ if (!startpos)
+ return FALSE;
+
+ endpos = strchr (startpos, '\'');
+ if (!endpos)
+ return FALSE;
+
+ *hostname_out = g_strndup (startpos, endpos - startpos);
+
+ /* Then get the ip address. */
+ startpos = strchr (endpos + 1, '\'') + 1;
+ if (!startpos)
+ {
+ g_free (hostname_out);
+ return FALSE;
+ }
+
+ endpos = strchr (startpos, '\'');
+ if (!endpos)
+ {
+ g_free (hostname_out);
+ return FALSE;
+ }
+
+ *ip_address_out = g_strndup (startpos, endpos - startpos);
+
+ return TRUE;
+}
+
+static gboolean
+login_answer_yes_no (GMountSource *mount_source,
+ char *message,
+ GOutputStream *reply_stream,
+ GError **error)
+{
+ const char *choices[] = {_("Log In Anyway"), _("Cancel Login"), NULL};
+ const char *choice_string;
+ int choice;
+ gboolean aborted = FALSE;
+ gsize bytes_written;
+
+ if (!g_mount_source_ask_question (mount_source,
+ message,
+ choices,
+ &aborted,
+ &choice) ||
+ aborted)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Login dialog cancelled"));
+ g_free (message);
+ return FALSE;
+ }
+ g_free (message);
+
+ choice_string = (choice == 0) ? "yes" : "no";
+ if (!g_output_stream_write_all (reply_stream,
+ choice_string,
+ strlen (choice_string),
+ &bytes_written,
+ NULL, NULL) ||
+ !g_output_stream_write_all (reply_stream,
+ "\n", 1,
+ &bytes_written,
+ NULL, NULL))
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Can't send host identity confirmation"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static const gchar *
get_authtype_from_password_line (const char *password_line)
{
@@ -874,11 +962,9 @@ handle_login (GVfsBackend *backend,
struct pollfd fds[2];
char buffer[1024];
gsize len;
- gboolean aborted = FALSE;
gboolean ret_val;
char *new_password = NULL;
char *new_user = NULL;
- gsize bytes_written;
gboolean password_in_keyring = FALSE;
const gchar *authtype = NULL;
gchar *object = NULL;
@@ -963,6 +1049,9 @@ handle_login (GVfsBackend *backend,
g_str_has_prefix (buffer, "Enter Kerberos password") ||
g_str_has_prefix (buffer, "Enter passphrase for key"))
{
+ gboolean aborted = FALSE;
+ gsize bytes_written;
+
authtype = get_authtype_from_password_line (buffer);
object = get_object_from_password_line (buffer);
@@ -1103,11 +1192,8 @@ handle_login (GVfsBackend *backend,
else if (g_str_has_prefix (buffer, "The authenticity of host '") ||
strstr (buffer, "Key fingerprint:") != NULL)
{
- const gchar *choices[] = {_("Log In Anyway"), _("Cancel Login"), NULL};
- const gchar *choice_string;
gchar *hostname = NULL;
gchar *fingerprint = NULL;
- gint choice;
gchar *message;
DEBUG ("handle_login #%d - confirming authenticity of host...\n", i);
@@ -1124,40 +1210,37 @@ handle_login (GVfsBackend *backend,
g_free (hostname);
g_free (fingerprint);
- if (!g_mount_source_ask_question (mount_source,
- message,
- choices,
- &aborted,
- &choice) ||
- aborted)
- {
- g_set_error_literal (error,
- G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Login dialog cancelled"));
- g_free (message);
- ret_val = FALSE;
- break;
- }
- g_free (message);
-
- choice_string = (choice == 0) ? "yes" : "no";
- if (!g_output_stream_write_all (reply_stream,
- choice_string,
- strlen (choice_string),
- &bytes_written,
- NULL, NULL) ||
- !g_output_stream_write_all (reply_stream,
- "\n", 1,
- &bytes_written,
- NULL, NULL))
- {
- g_set_error_literal (error,
- G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
- _("Can't send host identity confirmation"));
- ret_val = FALSE;
- break;
- }
+ if (!login_answer_yes_no (mount_source, message, reply_stream, error))
+ {
+ ret_val = FALSE;
+ break;
+ }
}
+ else if (strstr (buffer, "differs from the key for the IP address"))
+ {
+ gchar *hostname = NULL;
+ gchar *ip_address = NULL;
+ gchar *message;
+
+ DEBUG ("handle_login #%d - host key / IP mismatch ...\n", i);
+
+ get_hostname_and_ip_address (buffer, &hostname, &ip_address);
+
+ message = g_strdup_printf (_("The host key for ā€œ%sā€ differs from the key for the IP address ā€œ%sā€\n"
+ "If you want to be absolutely sure it is safe to continue, "
+ "contact the system administrator."),
+ hostname ? hostname : op_backend->host,
+ ip_address ? ip_address : "???");
+
+ g_free (hostname);
+ g_free (ip_address);
+
+ if (!login_answer_yes_no (mount_source, message, reply_stream, error))
+ {
+ ret_val = FALSE;
+ break;
+ }
+ }
}
if (ret_val)