diff options
author | Ross Lagerwall <rosslagerwall@gmail.com> | 2015-03-13 23:25:21 +0000 |
---|---|---|
committer | Ross Lagerwall <rosslagerwall@gmail.com> | 2015-04-09 22:04:29 +0100 |
commit | 336fe869f06c8e792aa20170e6278b57c1c38c05 (patch) | |
tree | 3b88d8b5ef50362611e36c46963e6480866110a6 | |
parent | 4ef4dd954a87be11499ea855f846e0f1dbfa9c7b (diff) | |
download | gvfs-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.c | 159 |
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) |