summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/idle-connection.c10
-rw-r--r--src/idle-server-connection.c85
2 files changed, 93 insertions, 2 deletions
diff --git a/src/idle-connection.c b/src/idle-connection.c
index 6a655b1..0e7e05c 100644
--- a/src/idle-connection.c
+++ b/src/idle-connection.c
@@ -48,6 +48,7 @@
#include "idle-roomlist-manager.h"
#include "idle-parser.h"
#include "idle-server-connection.h"
+#include "server-tls-manager.h"
#include "extensions/extensions.h" /* Renaming */
@@ -199,6 +200,9 @@ struct _IdleConnectionPrivate {
/* so we can pop up a SASL channel asking for the password */
TpSimplePasswordManager *password_manager;
+
+ /* TLS channel */
+ IdleServerTLSManager *tls_manager;
};
static void _iface_create_handle_repos(TpBaseConnection *self, TpHandleRepoIface **repos);
@@ -533,6 +537,10 @@ static GPtrArray *_iface_create_channel_managers(TpBaseConnection *base) {
manager = g_object_new(IDLE_TYPE_ROOMLIST_MANAGER, "connection", self, NULL);
g_ptr_array_add(managers, manager);
+ priv->tls_manager = g_object_new (IDLE_TYPE_SERVER_TLS_MANAGER,
+ "connection", self, NULL);
+ g_ptr_array_add(managers, priv->tls_manager);
+
return managers;
}
@@ -742,7 +750,7 @@ static void _start_connecting_continue(IdleConnection *conn) {
priv->username = g_strdup(g_get_user_name());
}
- sconn = g_object_new(IDLE_TYPE_SERVER_CONNECTION, "host", priv->server, "port", priv->port, NULL);
+ sconn = g_object_new(IDLE_TYPE_SERVER_CONNECTION, "host", priv->server, "port", priv->port, "tls-manager", priv->tls_manager, NULL);
if (priv->use_ssl)
idle_server_connection_set_tls(sconn, TRUE);
diff --git a/src/idle-server-connection.c b/src/idle-server-connection.c
index 1605b61..d6b8250 100644
--- a/src/idle-server-connection.c
+++ b/src/idle-server-connection.c
@@ -31,6 +31,7 @@
#define IDLE_DEBUG_FLAG IDLE_DEBUG_NETWORK
#include "idle-connection.h"
+#include "server-tls-manager.h"
#include "idle-debug.h"
typedef struct _IdleServerConnectionPrivate IdleServerConnectionPrivate;
@@ -47,7 +48,8 @@ enum {
enum {
PROP_HOST = 1,
- PROP_PORT
+ PROP_PORT,
+ PROP_TLS_MANAGER
};
struct _IdleServerConnectionPrivate {
@@ -66,6 +68,8 @@ struct _IdleServerConnectionPrivate {
GCancellable *cancellable;
IdleServerConnectionState state;
+ IdleServerTLSManager *tls_manager;
+ GAsyncQueue *certificate_queue;
};
static GObject *idle_server_connection_constructor(GType type, guint n_props, GObjectConstructParam *props);
@@ -81,6 +85,7 @@ static void idle_server_connection_init(IdleServerConnection *conn) {
priv->socket_client = g_socket_client_new();
priv->state = SERVER_CONNECTION_STATE_NOT_CONNECTED;
+ priv->certificate_queue = g_async_queue_new ();
}
static GObject *idle_server_connection_constructor(GType type, guint n_props, GObjectConstructParam *props) {
@@ -105,6 +110,7 @@ static void idle_server_connection_finalize(GObject *obj) {
IdleServerConnection *conn = IDLE_SERVER_CONNECTION(obj);
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
+ g_async_queue_unref (priv->certificate_queue);
g_free(priv->host);
}
@@ -121,6 +127,10 @@ static void idle_server_connection_get_property(GObject *obj, guint prop_id, GV
g_value_set_uint(value, priv->port);
break;
+ case PROP_TLS_MANAGER:
+ g_value_set_object(value, priv->tls_manager);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break;
@@ -144,6 +154,10 @@ static void idle_server_connection_set_property(GObject *obj,
priv->port = (guint16) g_value_get_uint(value);
break;
+ case PROP_TLS_MANAGER:
+ priv->tls_manager = g_value_dup_object(value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break;
@@ -183,6 +197,16 @@ static void idle_server_connection_class_init(IdleServerConnectionClass *klass)
g_object_class_install_property(object_class, PROP_PORT, pspec);
+ pspec = g_param_spec_object("tls-manager", "TLS Manager",
+ "TLS manager for interactive certificate checking",
+ IDLE_TYPE_SERVER_TLS_MANAGER,
+ G_PARAM_READABLE|
+ G_PARAM_WRITABLE|
+ G_PARAM_STATIC_NICK|
+ G_PARAM_STATIC_BLURB);
+
+ g_object_class_install_property(object_class, PROP_TLS_MANAGER, pspec);
+
signals[STATUS_CHANGED] = g_signal_new("status-changed",
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
@@ -293,14 +317,73 @@ cleanup:
g_object_unref(result);
}
+
+#define CERT_ACCEPTED 1
+#define CERT_REJECTED 2
+struct CertData {
+ IdleServerConnection *self;
+ GTlsCertificate *certificate;
+};
+
+static void _certificate_verified (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ IdleServerConnection *self = user_data;
+ IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(self);
+ gboolean ret;
+
+ ret = idle_server_tls_manager_verify_finish (IDLE_SERVER_TLS_MANAGER (source), res, NULL);
+ g_async_queue_push (priv->certificate_queue, GINT_TO_POINTER (ret ? CERT_ACCEPTED : CERT_REJECTED));
+}
+
+static gboolean
+_check_certificate_interactively (gpointer data) {
+ struct CertData *d = data;
+ IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(d->self);
+
+ idle_server_tls_manager_verify_async (priv->tls_manager, d->certificate, priv->host, _certificate_verified, d->self);
+ return FALSE;
+}
+
+static gboolean _accept_certificate_request (GTlsConnection *tls_connection, GTlsCertificate *peer_cert, GTlsCertificateFlags errors, IdleServerConnection *conn)
+{
+ IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
+ struct CertData d;
+ gpointer result;
+
+ /* Requested to check the extra errors from an ssl certificate,
+ * Need to bounce this back into the main thread so we can ask the UI
+ * on dbus */
+ IDLE_DEBUG ("Requested to validate certificate");
+
+ d.self = conn;
+ d.certificate = peer_cert;
+
+ g_idle_add (_check_certificate_interactively, &d);
+ result = g_async_queue_pop (priv->certificate_queue);
+
+ return GPOINTER_TO_INT (result) == CERT_ACCEPTED;
+}
+
+static void _connect_event_cb (GSocketClient *client, GSocketClientEvent event, GSocketConnectable *connectable, GIOStream *connection, gpointer user_data)
+{
+ if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING)
+ return;
+
+ g_signal_connect (connection, "accept-certificate", G_CALLBACK (_accept_certificate_request), user_data);
+}
+
static void _connect_in_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
{
IdleServerConnection *conn = source_object;
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
GError *error = NULL;
GSocketConnection *socket_connection;
+ gulong event_id;
+ event_id = g_signal_connect (priv->socket_client, "event",
+ G_CALLBACK (_connect_event_cb), conn);
socket_connection = g_socket_client_connect_to_host (priv->socket_client, priv->host, priv->port, cancellable, &error);
+ g_signal_handler_disconnect (priv->socket_client, event_id);
if (socket_connection != NULL)
g_task_return_pointer (task, socket_connection, NULL);
else