[hotssh] Read and write ~/.ssh/known_hosts
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [hotssh] Read and write ~/.ssh/known_hosts
- Date: Thu, 2 Jan 2014 00:09:50 +0000 (UTC)
commit 9a3b6fa4233958cba98c9eccb53b3f788980f00b
Author: Colin Walters <walters verbum org>
Date: Wed Jan 1 15:26:40 2014 -0500
Read and write ~/.ssh/known_hosts
With this change, the button to approve the hostkey now actually
writes it to ~/.ssh/known_hosts. This necessitated modeling keytypes
and exposing the raw base64 from GSsh.
libgssh/gssh-connection-private.h | 3 +-
libgssh/gssh-connection.c | 39 ++++++--
libgssh/gssh-connection.h | 6 +-
src/hotssh-hostdb.c | 193 ++++++++++++++++++++++++++++++++-----
src/hotssh-hostdb.h | 15 ++-
src/hotssh-tab.c | 167 +++++++++++++++++++++++++++-----
src/tab.ui | 16 +++-
7 files changed, 372 insertions(+), 67 deletions(-)
---
diff --git a/libgssh/gssh-connection-private.h b/libgssh/gssh-connection-private.h
index 6a0d7d3..c231ba3 100644
--- a/libgssh/gssh-connection-private.h
+++ b/libgssh/gssh-connection-private.h
@@ -47,7 +47,8 @@ struct _GSshConnection
GError *cached_error;
char *remote_hostkey_type;
- GBytes *remote_hostkey_sha1;
+ char *remote_hostkey_sha1_text;
+ char *remote_hostkey_base64;
GMainContext *maincontext;
GSocketClient *socket_client;
GSocket *socket;
diff --git a/libgssh/gssh-connection.c b/libgssh/gssh-connection.c
index 8d29761..e50a836 100644
--- a/libgssh/gssh-connection.c
+++ b/libgssh/gssh-connection.c
@@ -88,7 +88,8 @@ reset_state (GSshConnection *self)
/* This hash doesn't hold a ref */
self->channels = g_hash_table_new (NULL, NULL);
- g_clear_pointer (&self->remote_hostkey_sha1, g_bytes_unref);
+ g_clear_pointer (&self->remote_hostkey_sha1_text, g_free);
+ g_clear_pointer (&self->remote_hostkey_base64, g_free);
g_clear_error (&self->cached_error);
g_clear_object (&self->socket);
if (self->socket_source)
@@ -350,6 +351,8 @@ set_hostkey_sha1 (GSshConnection *self,
guint8 sha1buf[20];
gsize sha1len = sizeof (sha1buf);
GChecksum *csum;
+ GString *buf;
+ guint i;
rc = ssh_get_publickey (self->session, &key);
if (rc != SSH_OK)
@@ -373,8 +376,18 @@ set_hostkey_sha1 (GSshConnection *self,
g_checksum_get_digest (csum, sha1buf, &sha1len);
g_assert (sha1len == sizeof (sha1buf));
- self->remote_hostkey_sha1 = g_bytes_new (sha1buf, sha1len);
+ buf = g_string_new ("");
+ for (i = 0; i < sha1len; i++)
+ {
+ g_string_append_printf (buf, "%02X", sha1buf[i]);
+ if (i < sha1len - 1)
+ g_string_append_c (buf, ':');
+ }
+
+ self->remote_hostkey_sha1_text = g_string_free (buf, FALSE);
self->remote_hostkey_type = g_strdup (ssh_key_type_to_char (ssh_key_type (key)));
+ self->remote_hostkey_base64 = g_strdup (key_b64);
+ free (key_b64); /* Possible free != g_free */
ret = TRUE;
out:
@@ -759,18 +772,24 @@ gssh_connection_get_state (GSshConnection *self)
}
/**
- * gssh_connection_preauth_get_host_key_fingerprint_sha1:
+ * gssh_connection_preauth_get_host_key:
* @self: Self
* @out_key_type: (out): String representation of key type
- *
- * Returns: (transfer none): 20 bytes for the remote host's SHA1 fingerprint
+ * @out_key_sha1_text: (out): String representation of key SHA1
+ * @out_key_base64: (out): String representation of base64-encoded key
*/
-GBytes *
-gssh_connection_preauth_get_host_key_fingerprint_sha1 (GSshConnection *self,
- char **out_key_type)
+void
+gssh_connection_preauth_get_host_key (GSshConnection *self,
+ char **out_key_type,
+ char **out_key_sha1_text,
+ char **out_key_base64)
{
- *out_key_type = g_strdup (self->remote_hostkey_type);
- return self->remote_hostkey_sha1;
+ if (out_key_type)
+ *out_key_type = g_strdup (self->remote_hostkey_type);
+ if (out_key_sha1_text)
+ *out_key_sha1_text = g_strdup (self->remote_hostkey_sha1_text);
+ if (out_key_base64)
+ *out_key_base64 = g_strdup (self->remote_hostkey_base64);
}
void
diff --git a/libgssh/gssh-connection.h b/libgssh/gssh-connection.h
index e5fdbda..3e9c43b 100644
--- a/libgssh/gssh-connection.h
+++ b/libgssh/gssh-connection.h
@@ -72,8 +72,10 @@ gboolean gssh_connection_handshake_finish (GSshConnection *sel
void gssh_connection_set_interaction (GSshConnection *self,
GTlsInteraction *interaction);
-GBytes * gssh_connection_preauth_get_host_key_fingerprint_sha1 (GSshConnection *self,
- char
**out_key_type);
+void gssh_connection_preauth_get_host_key (GSshConnection *self,
+ char **out_keytype,
+ char **out_key_sha1_text,
+ char **out_key_base64);
void gssh_connection_negotiate_async (GSshConnection *self,
GCancellable *cancellable,
diff --git a/src/hotssh-hostdb.c b/src/hotssh-hostdb.c
index e909513..a1e36b7 100644
--- a/src/hotssh-hostdb.c
+++ b/src/hotssh-hostdb.c
@@ -28,6 +28,8 @@
#include "libgsystem.h"
+#define WRITE_IDLE_SECONDS (5)
+
struct _HotSshHostDB
{
GObject parent;
@@ -50,22 +52,31 @@ struct _HotSshHostDBPrivate
GFile *hotssh_hostdb_path;
GFileMonitor *knownhosts_monitor;
+ GHashTable *add_knownhost_queue;
+
guint idle_save_hostdb_id;
+ guint idle_save_knownhosts_id;
char *new_hostdb_contents;
};
G_DEFINE_TYPE_WITH_PRIVATE(HotSshHostDB, hotssh_hostdb, G_TYPE_OBJECT)
static char *
-address_to_string (GNetworkAddress *address)
+hostname_and_port_to_string (const char *hostname,
+ guint port)
{
- const char *hostname = g_network_address_get_hostname (address);
- guint port = g_network_address_get_port (address);
if (port == 22)
- return g_strdup (g_network_address_get_hostname (address));
+ return g_strdup (hostname);
return g_strdup_printf ("[%s]:%u", hostname, port);
}
+static char *
+address_to_string (GNetworkAddress *address)
+{
+ return hostname_and_port_to_string (g_network_address_get_hostname (address),
+ g_network_address_get_port (address));
+}
+
static void
mark_all_entries_unknown (HotSshHostDB *self)
{
@@ -89,7 +100,9 @@ static void
mark_all_entries_known_by_address (HotSshHostDB *self,
const char *hostname,
guint port,
- guint lineno)
+ guint lineno,
+ const char *keytype,
+ const char *key_base64)
{
G_GNUC_UNUSED HotSshHostDBPrivate *priv = hotssh_hostdb_get_instance_private (self);
GtkTreeIter iter;
@@ -114,6 +127,8 @@ mark_all_entries_known_by_address (HotSshHostDB *self,
{
gtk_list_store_set (priv->model, &iter,
HOTSSH_HOSTDB_COLUMN_IS_KNOWN, TRUE,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_TYPE, keytype,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_BASE64, key_base64,
HOTSSH_HOSTDB_COLUMN_OPENSSH_KNOWNHOST_LINE, lineno,
-1);
}
@@ -156,6 +171,8 @@ on_knownhosts_changed (GFileMonitor *monitor,
GNetworkAddress *address_obj = NULL;
gs_free char *address_str = NULL;
char *comma;
+ const char *keytype;
+ const char *key_base64;
eol = strchr (iter, '\n');
if (eol)
@@ -181,10 +198,15 @@ on_knownhosts_changed (GFileMonitor *monitor,
goto next;
address_str = address_to_string (address_obj);
+ keytype = parts[1];
+ key_base64 = parts[2];
+
mark_all_entries_known_by_address (self,
g_network_address_get_hostname (address_obj),
g_network_address_get_port (address_obj),
- lineno);
+ lineno,
+ keytype,
+ key_base64);
g_hash_table_insert (priv->openssh_knownhosts, address_str, parts);
address_str = NULL;
@@ -340,7 +362,7 @@ queue_save_hostdb (HotSshHostDB *self)
G_GNUC_UNUSED HotSshHostDBPrivate *priv = hotssh_hostdb_get_instance_private (self);
if (priv->idle_save_hostdb_id > 0)
return;
- priv->idle_save_hostdb_id = g_timeout_add_seconds (5, idle_save_hostdb, self);
+ priv->idle_save_hostdb_id = g_timeout_add_seconds (WRITE_IDLE_SECONDS, idle_save_hostdb, self);
}
static void
@@ -464,33 +486,149 @@ hotssh_hostdb_update_last_used (HotSshHostDB *self,
queue_save_hostdb (self);
}
+static void
+on_knownhosts_splice_complete (GObject *src,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ HotSshHostDB *self = user_data;
+ G_GNUC_UNUSED HotSshHostDBPrivate *priv = hotssh_hostdb_get_instance_private (self);
+ gssize bytes_written;
+ GError *local_error = NULL;
+
+ priv->idle_save_knownhosts_id = 0;
+
+ g_debug ("knownhosts splice complete");
+
+ bytes_written = g_output_stream_splice_finish ((GOutputStream*)src, result, &local_error);
+ if (bytes_written == -1)
+ goto out;
+
+ out:
+ if (local_error)
+ {
+ g_warning ("Failed to write '%s': %s",
+ gs_file_get_path_cached (priv->openssh_knownhosts_path),
+ local_error->message);
+ g_error_free (local_error);
+ }
+}
+
+static void
+on_knownhosts_opened (GObject *src,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ HotSshHostDB *self = user_data;
+ G_GNUC_UNUSED HotSshHostDBPrivate *priv = hotssh_hostdb_get_instance_private (self);
+ GHashTableIter hashiter;
+ gpointer key, value;
+ GError *local_error = NULL;
+ gs_unref_object GFileOutputStream *fileout = NULL;
+ gs_unref_object GMemoryInputStream *membuf = (GMemoryInputStream*)g_memory_input_stream_new ();
+
+ g_debug ("knownhosts opened for append");
+
+ fileout = g_file_append_to_finish ((GFile*)src, result, &local_error);
+ if (!fileout)
+ goto out;
+
+ g_hash_table_iter_init (&hashiter, priv->add_knownhost_queue);
+ while (g_hash_table_iter_next (&hashiter, &key, &value))
+ {
+ GtkTreeIter iter;
+ const char *id = key;
+ gs_free char *hostname = NULL;
+ guint port;
+ gs_free char *keytype = NULL;
+ gs_free char *key_base64 = NULL;
+ gs_free char *ipaddr = NULL;
+ gs_free char *address = NULL;
+ char *out_line;
+
+ if (!hotssh_hostdb_lookup_by_id (self, id, &iter))
+ continue;
+
+ gtk_tree_model_get ((GtkTreeModel*)priv->model, &iter,
+ HOTSSH_HOSTDB_COLUMN_HOSTNAME, &hostname,
+ HOTSSH_HOSTDB_COLUMN_PORT, &port,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_TYPE, &keytype,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_BASE64, &key_base64,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_IP_ADDRESS, &ipaddr,
+ -1);
+
+ address = hostname_and_port_to_string (hostname, port);
+ if (ipaddr)
+ out_line = g_strdup_printf ("%s,%s %s %s\n", address, ipaddr,
+ keytype, key_base64);
+ else
+ out_line = g_strdup_printf ("%s %s %s\n", address,
+ keytype, key_base64);
+
+ g_memory_input_stream_add_bytes (membuf, g_bytes_new_take (out_line, strlen (out_line)));
+
+ g_hash_table_iter_remove (&hashiter);
+ }
+
+ g_output_stream_splice_async ((GOutputStream*)fileout, (GInputStream*)membuf,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ on_knownhosts_splice_complete,
+ self);
+
+ out:
+ if (local_error)
+ {
+ priv->idle_save_knownhosts_id = 0;
+ g_warning ("Failed to write '%s': %s",
+ gs_file_get_path_cached (priv->openssh_knownhosts_path),
+ local_error->message);
+ g_error_free (local_error);
+ }
+}
+
+static gboolean
+idle_write_knownhosts (gpointer user_data)
+{
+ HotSshHostDB *self = user_data;
+ G_GNUC_UNUSED HotSshHostDBPrivate *priv = hotssh_hostdb_get_instance_private (self);
+
+ g_file_append_to_async (priv->openssh_knownhosts_path, 0,
+ G_PRIORITY_DEFAULT, NULL,
+ on_knownhosts_opened, self);
+
+ return FALSE;
+}
+
void
-hotssh_hostdb_set_entry_known (HotSshHostDB *self,
- const char *id,
- gboolean make_known)
+hotssh_hostdb_set_entry_host_key_known (HotSshHostDB *self,
+ const char *id,
+ const char *keytype,
+ const char *key_base64,
+ const char *last_ip_address)
{
G_GNUC_UNUSED HotSshHostDBPrivate *priv = hotssh_hostdb_get_instance_private (self);
- gboolean is_known;
GtkTreeIter iter;
+ g_return_if_fail (id != NULL);
+ g_return_if_fail (keytype != NULL);
+ g_return_if_fail (key_base64 != NULL);
+
if (!hotssh_hostdb_lookup_by_id (self, id, &iter))
return;
- gtk_tree_model_get ((GtkTreeModel*)priv->model, &iter,
- HOTSSH_HOSTDB_COLUMN_IS_KNOWN, &is_known,
+ gtk_list_store_set (priv->model, &iter,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_TYPE, keytype,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_BASE64, key_base64,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_IP_ADDRESS, last_ip_address,
-1);
- if (is_known == make_known)
- return;
+ g_hash_table_add (priv->add_knownhost_queue, g_strdup (id));
- if (make_known)
- {
- g_debug ("not implemented");
- }
- else
- {
- g_debug ("not implemented");
- }
+ if (priv->idle_save_knownhosts_id == 0)
+ priv->idle_save_knownhosts_id = g_timeout_add_seconds (WRITE_IDLE_SECONDS, idle_write_knownhosts, self);
}
static GFileMonitor *
@@ -533,7 +671,10 @@ hotssh_hostdb_init (HotSshHostDB *self)
G_TYPE_STRING, /* username */
G_TYPE_UINT64, /* last-used */
G_TYPE_BOOLEAN, /* is-known */
- G_TYPE_UINT64 /* openssh-knownhost-line */
+ G_TYPE_UINT64, /* openssh-knownhost-line */
+ G_TYPE_STRING, /* last-ip-address */
+ G_TYPE_STRING, /* host-key-type */
+ G_TYPE_STRING /* host-key-base64 */
);
gtk_tree_sortable_set_sort_column_id ((GtkTreeSortable*)priv->model,
HOTSSH_HOSTDB_COLUMN_LAST_USED,
@@ -541,6 +682,9 @@ hotssh_hostdb_init (HotSshHostDB *self)
homedir = g_get_home_dir ();
g_assert (homedir);
+ priv->add_knownhost_queue = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, g_free);
+
priv->openssh_knownhosts = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify)g_strfreev);
@@ -579,6 +723,7 @@ hotssh_hostdb_dispose (GObject *object)
g_clear_pointer (&priv->hostdb, g_key_file_unref);
g_clear_pointer (&priv->openssh_knownhosts_path, g_hash_table_unref);
g_clear_object (&priv->model);
+ g_clear_pointer (&priv->add_knownhost_queue, g_hash_table_unref);
G_OBJECT_CLASS (hotssh_hostdb_parent_class)->dispose (object);
}
diff --git a/src/hotssh-hostdb.h b/src/hotssh-hostdb.h
index 459491d..7cb7b32 100644
--- a/src/hotssh-hostdb.h
+++ b/src/hotssh-hostdb.h
@@ -35,9 +35,12 @@ enum {
HOTSSH_HOSTDB_COLUMN_USERNAME,
HOTSSH_HOSTDB_COLUMN_LAST_USED,
HOTSSH_HOSTDB_COLUMN_IS_KNOWN,
- HOTSSH_HOSTDB_COLUMN_OPENSSH_KNOWNHOST_LINE
+ HOTSSH_HOSTDB_COLUMN_OPENSSH_KNOWNHOST_LINE,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_IP_ADDRESS,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_TYPE,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_BASE64
};
-#define HOTSSH_HOSTDB_N_COLUMNS (HOTSSH_HOSTDB_COLUMN_OPENSSH_KNOWNHOST_LINE+1)
+#define HOTSSH_HOSTDB_N_COLUMNS (HOTSSH_HOSTDB_COLUMN_HOST_KEY_BASE64+1)
GType hotssh_hostdb_get_type (void);
HotSshHostDB *hotssh_hostdb_get_instance (void);
@@ -61,6 +64,8 @@ void hotssh_hostdb_set_entry_basic (HotSshHostDB *self,
void hotssh_hostdb_update_last_used (HotSshHostDB *self,
const char *id);
-void hotssh_hostdb_set_entry_known (HotSshHostDB *self,
- const char *id,
- gboolean known);
+void hotssh_hostdb_set_entry_host_key_known (HotSshHostDB *self,
+ const char *id,
+ const char *keytype,
+ const char *key_base64,
+ const char *last_ip_address);
diff --git a/src/hotssh-tab.c b/src/hotssh-tab.c
index a32df2d..b2674e9 100644
--- a/src/hotssh-tab.c
+++ b/src/hotssh-tab.c
@@ -94,6 +94,8 @@ struct _HotSshTabPrivate
GtkWidget *hostname_renderer;
GtkWidget *lastused_column;
GtkWidget *lastused_renderer;
+ GtkWidget *known_column;
+ GtkWidget *known_renderer;
/* State */
HotSshTabPage active_page;
@@ -121,6 +123,10 @@ struct _HotSshTabPrivate
G_DEFINE_TYPE_WITH_PRIVATE(HotSshTab, hotssh_tab, GTK_TYPE_NOTEBOOK);
+static void
+on_negotiate_complete (GObject *src,
+ GAsyncResult *result,
+ gpointer user_data);
static void
set_status (HotSshTab *self,
@@ -428,6 +434,64 @@ iterate_authentication_modes (HotSshTab *self)
}
static void
+handle_unknown_hostkey (HotSshTab *self,
+ const char *connected_hostkey_type,
+ const char *connected_hostkey_sha1)
+{
+ HotSshTabPrivate *priv = hotssh_tab_get_instance_private (self);
+
+ gtk_label_set_text ((GtkLabel*)priv->hostkey_fingerprint_label,
+ connected_hostkey_sha1);
+ page_transition (self, HOTSSH_TAB_PAGE_HOSTKEY);
+}
+
+static void
+verify_hostkey (HotSshTab *self,
+ const char *connected_hostkey_type,
+ const char *connected_hostkey_base64,
+ const char *saved_hostkey_type,
+ const char *saved_hostkey_base64)
+{
+ HotSshTabPrivate *priv = hotssh_tab_get_instance_private (self);
+ gs_free char *errdetails = NULL;
+
+ if (strcmp (connected_hostkey_type, saved_hostkey_type) != 0)
+ {
+ errdetails = g_strdup_printf (_("The remote host key type has changed; it was previously \"%s\", now
\"%s\""),
+ saved_hostkey_type, connected_hostkey_type);
+ }
+ else if (strcmp (connected_hostkey_base64, saved_hostkey_base64) != 0)
+ {
+ errdetails = g_strdup (_("The remote host key has changed"));
+ }
+
+ if (errdetails)
+ {
+ GError *local_error = NULL;
+
+ g_set_error (&local_error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Error: The host credentials for \"%s\" (%s) do not match the previously "
+ "saved credentials. This may represent an attempt by a malicious party to "
+ "intercept communication; however, it is also possible that the host key was changed "
+ "by a system administrator.\n\nDetails: %s"),
+ priv->hostname,
+ g_network_address_get_hostname ((GNetworkAddress*)priv->address),
+ errdetails);
+ page_transition_take_error (self, local_error);
+ }
+ else
+ {
+ g_debug ("Remote host key matches");
+ page_transition (self, HOTSSH_TAB_PAGE_CONNECTING);
+ set_status (self, _("Negotiating authentication…"));
+
+ gssh_connection_negotiate_async (priv->connection, priv->cancellable,
+ on_negotiate_complete, self);
+ }
+}
+
+static void
on_connection_handshake (GObject *object,
GAsyncResult *result,
gpointer user_data)
@@ -436,36 +500,52 @@ on_connection_handshake (GObject *object,
HotSshTabPrivate *priv = hotssh_tab_get_instance_private (self);
GError *local_error = NULL;
GError **error = &local_error;
- GBytes *hostkey_sha1_binary;
- GString *buf;
- guint i;
- const guint8 *binbuf;
- gsize len;
- gs_free char *hostkey_sha1_text = NULL;
- gs_free char *hostkey_type = NULL;
+ gs_free char *saved_hostkey_type = NULL;
+ gs_free char *saved_hostkey_base64 = NULL;
+ gs_unref_object GtkTreeModel *model = NULL;
+ gs_free char *connected_hostkey_type = NULL;
+ gs_free char *connected_hostkey_sha1_text = NULL;
+ gs_free char *connected_hostkey_base64 = NULL;
+ GtkTreeIter iter;
+
+ model = hotssh_hostdb_get_model (hotssh_hostdb_get_instance ());
if (!gssh_connection_handshake_finish ((GSshConnection*)object, result, error))
goto out;
+ gssh_connection_preauth_get_host_key (priv->connection,
+ &connected_hostkey_type,
+ &connected_hostkey_sha1_text,
+ &connected_hostkey_base64);
+
g_debug ("handshake complete");
+ g_debug ("remote key type:%s SHA1:%s",
+ connected_hostkey_type,
+ connected_hostkey_sha1_text);
+
+ g_assert (hotssh_hostdb_lookup_by_id (hotssh_hostdb_get_instance (), priv->connection_id, &iter));
- hostkey_sha1_binary = gssh_connection_preauth_get_host_key_fingerprint_sha1 (priv->connection,
- &hostkey_type);
- binbuf = g_bytes_get_data (hostkey_sha1_binary, &len);
- buf = g_string_new ("");
- for (i = 0; i < len; i++)
+ gtk_tree_model_get (model, &iter,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_TYPE,
+ &saved_hostkey_type,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_BASE64,
+ &saved_hostkey_base64,
+ -1);
+
+ if (saved_hostkey_type == NULL)
{
- g_string_append_printf (buf, "%02X", binbuf[i]);
- if (i < len - 1)
- g_string_append_c (buf, ':');
+ handle_unknown_hostkey (self,
+ connected_hostkey_type,
+ connected_hostkey_sha1_text);
+ }
+ else
+ {
+ verify_hostkey (self,
+ connected_hostkey_type,
+ connected_hostkey_base64,
+ saved_hostkey_type,
+ saved_hostkey_base64);
}
- hostkey_sha1_text = g_string_free (buf, FALSE);
-
- g_debug ("remote key type:%s SHA1:%s", hostkey_type, hostkey_sha1_text);
-
- gtk_label_set_text ((GtkLabel*)priv->hostkey_fingerprint_label,
- hostkey_sha1_text);
- page_transition (self, HOTSSH_TAB_PAGE_HOSTKEY);
out:
if (local_error)
@@ -727,12 +807,19 @@ on_approve_hostkey_clicked (GtkButton *button,
{
HotSshTab *self = user_data;
HotSshTabPrivate *priv = hotssh_tab_get_instance_private (self);
+ gs_free char *keytype = NULL;
+ gs_free char *key_base64 = NULL;
page_transition (self, HOTSSH_TAB_PAGE_CONNECTING);
set_status (self, _("Negotiating authentication…"));
- hotssh_hostdb_set_entry_known (hotssh_hostdb_get_instance (),
- priv->connection_id, TRUE);
+ gssh_connection_preauth_get_host_key (priv->connection,
+ &keytype, NULL, &key_base64);
+
+ hotssh_hostdb_set_entry_host_key_known (hotssh_hostdb_get_instance (),
+ priv->connection_id,
+ keytype, key_base64,
+ NULL);
gssh_connection_negotiate_async (priv->connection, priv->cancellable,
on_negotiate_complete, self);
@@ -982,6 +1069,32 @@ render_last_used (GtkTreeViewColumn *tree_column,
}
static void
+render_known (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean known;
+ const char *text;
+ gs_free char *keytype;
+
+ gtk_tree_model_get (tree_model, iter,
+ HOTSSH_HOSTDB_COLUMN_IS_KNOWN,
+ &known,
+ HOTSSH_HOSTDB_COLUMN_HOST_KEY_TYPE,
+ &keytype,
+ -1);
+
+ if (!known || !keytype)
+ text = _("Unknown");
+ else
+ text = keytype;
+
+ g_object_set (cell, "text", text, NULL);
+}
+
+static void
hotssh_tab_constructed (GObject *object)
{
HotSshTab *self = HOTSSH_TAB (object);
@@ -1007,6 +1120,10 @@ hotssh_tab_constructed (GObject *object)
"sort-indicator", TRUE,
"sort-order", GTK_SORT_DESCENDING,
NULL);
+ gtk_tree_view_column_set_cell_data_func ((GtkTreeViewColumn*)priv->known_column,
+ (GtkCellRenderer*)priv->known_renderer,
+ render_known,
+ self, NULL);
}
static void
@@ -1024,6 +1141,8 @@ hotssh_tab_class_init (HotSshTabClass *class)
gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab, hostname_renderer);
gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab, lastused_column);
gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab, lastused_renderer);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab, known_column);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab, known_renderer);
gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab, host_entry);
gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab, username_entry);
gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class), HotSshTab,
create_and_connect_button);
diff --git a/src/tab.ui b/src/tab.ui
index 0b5186a..841ac53 100644
--- a/src/tab.ui
+++ b/src/tab.ui
@@ -103,7 +103,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkButton" id="connect_cancel_button1">
+ <object class="GtkButton" id="create_cancel_button">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -195,6 +195,14 @@
</child>
</object>
</child>
+ <child>
+ <object class="GtkTreeViewColumn" id="known_column">
+ <property name="title" translatable="yes">Known</property>
+ <child>
+ <object class="GtkCellRendererText" id="known_renderer"/>
+ </child>
+ </object>
+ </child>
</object>
<packing>
<property name="expand">True</property>
@@ -240,8 +248,11 @@
<object class="GtkLabel" id="connection_text">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
<property name="label" translatable="yes">Connecting…</property>
<property name="justify">center</property>
+ <property name="wrap">True</property>
</object>
<packing>
<property name="expand">True</property>
@@ -295,7 +306,10 @@
<object class="GtkLabel" id="error_text">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
<property name="label" translatable="yes">Error:</property>
+ <property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]