From 9abf25885dd71047746ea496ea3bdaff7f3499e7 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 13 Jun 2012 14:41:10 +0200 Subject: GabbleServerTLSManager: Support multiple consecutive TLS verifications WockyConnector could now restart connection with another host, and so needs to re-verify TLS. --- lib/ext/wocky | 2 +- src/server-tls-channel.c | 4 +- src/server-tls-manager.c | 159 ++++++++++++++++++++++++++++------------------- 3 files changed, 99 insertions(+), 66 deletions(-) diff --git a/lib/ext/wocky b/lib/ext/wocky index 520016c06..9d5d16dab 160000 --- a/lib/ext/wocky +++ b/lib/ext/wocky @@ -1 +1 @@ -Subproject commit 520016c06c3c7440c925bde233842deafce76208 +Subproject commit 9d5d16dabbb84a44d230996cd1d1480f5b767ec0 diff --git a/src/server-tls-channel.c b/src/server-tls-channel.c index 859edb4d6..a82842d77 100644 --- a/src/server-tls-channel.c +++ b/src/server-tls-channel.c @@ -227,7 +227,9 @@ gabble_server_tls_channel_fill_immutable_properties ( static gchar * gabble_server_tls_channel_get_object_path_suffix (TpBaseChannel *base) { - return g_strdup ("ServerTLSChannel"); + static guint count = 0; + + return g_strdup_printf ("ServerTLSChannel%u", ++count); } static void diff --git a/src/server-tls-manager.c b/src/server-tls-manager.c index 890a4d637..8dd90fbeb 100644 --- a/src/server-tls-manager.c +++ b/src/server-tls-manager.c @@ -50,24 +50,26 @@ enum { }; struct _GabbleServerTLSManagerPrivate { + /* Properties */ GabbleConnection *connection; - GabbleServerTLSChannel *channel; + gboolean interactive_tls; + /* Current operation data */ gchar *peername; GStrv reference_identities; WockyTLSSession *tls_session; - + GabbleServerTLSChannel *channel; GSimpleAsyncResult *async_result; - GAsyncReadyCallback async_callback; - gpointer async_data; - gboolean verify_async_called; - gboolean tls_state_changed; - gboolean interactive_tls; + /* List of owned TpBaseChannel not yet closed by the client */ + GList *completed_channels; gboolean dispose_has_run; }; +#define chainup ((WockyTLSHandlerClass *) \ + gabble_server_tls_manager_parent_class) + static void gabble_server_tls_manager_get_property (GObject *object, guint property_id, @@ -112,6 +114,18 @@ gabble_server_tls_manager_set_property (GObject *object, } } +static void +close_all (GabbleServerTLSManager *self) +{ + GList *l; + + if (self->priv->channel != NULL) + tp_base_channel_close (TP_BASE_CHANNEL (self->priv->channel)); + + for (l = self->priv->completed_channels; l != NULL; l = l->next) + tp_base_channel_close (l->data); +} + static void connection_status_changed_cb (GabbleConnection *conn, guint status, @@ -124,13 +138,46 @@ connection_status_changed_cb (GabbleConnection *conn, if (status == TP_CONNECTION_STATUS_DISCONNECTED) { - if (self->priv->channel != NULL) - tp_base_channel_close (TP_BASE_CHANNEL (self->priv->channel)); - + close_all (self); tp_clear_object (&self->priv->connection); } } +static void +complete_verify (GabbleServerTLSManager *self) +{ + /* Move channel to a list until a client Close() it */ + if (self->priv->channel != NULL) + { + self->priv->completed_channels = g_list_prepend ( + self->priv->completed_channels, + g_object_ref (self->priv->channel)); + } + + g_simple_async_result_complete (self->priv->async_result); + + /* Reset to initial state */ + tp_clear_pointer (&self->priv->peername, g_free); + tp_clear_pointer (&self->priv->reference_identities, g_strfreev); + g_clear_object (&self->priv->tls_session); + g_clear_object (&self->priv->channel); + g_clear_object (&self->priv->async_result); +} + +static void +verify_fallback_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GabbleServerTLSManager *self = (GabbleServerTLSManager *) source; + GError *error = NULL; + + if (!chainup->verify_finish_func (WOCKY_TLS_HANDLER (self), result, &error)) + g_simple_async_result_take_error (self->priv->async_result, error); + + complete_verify (self); +} + static void server_tls_channel_closed_cb (GabbleServerTLSChannel *channel, gpointer user_data) @@ -139,24 +186,31 @@ server_tls_channel_closed_cb (GabbleServerTLSChannel *channel, DEBUG ("Server TLS channel closed."); - if (!self->priv->tls_state_changed) + if (channel == self->priv->channel) { /* fallback to the old-style non interactive TLS verification */ DEBUG ("Channel closed, but unhandled, falling back..."); - WOCKY_TLS_HANDLER_CLASS - (gabble_server_tls_manager_parent_class)->verify_async_func ( - WOCKY_TLS_HANDLER (self), self->priv->tls_session, - self->priv->peername, self->priv->reference_identities, - self->priv->async_callback, self->priv->async_data); + chainup->verify_async_func (WOCKY_TLS_HANDLER (self), + self->priv->tls_session, self->priv->peername, + self->priv->reference_identities, verify_fallback_cb, NULL); + + self->priv->channel = NULL; } + else + { + GList *l; - tp_clear_object (&self->priv->async_result); + l = g_list_find (self->priv->completed_channels, channel); + g_assert (l != NULL); + + self->priv->completed_channels = g_list_delete_link ( + self->priv->completed_channels, l); + } tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (channel)); - - tp_clear_object (&self->priv->channel); + g_object_unref (channel); } GQuark @@ -178,10 +232,7 @@ tls_certificate_accepted_cb (GabbleTLSCertificate *certificate, DEBUG ("TLS certificate accepted"); - self->priv->tls_state_changed = TRUE; - - g_simple_async_result_complete_in_idle (self->priv->async_result); - tp_clear_object (&self->priv->async_result); + complete_verify (self); } static void @@ -189,20 +240,15 @@ tls_certificate_rejected_cb (GabbleTLSCertificate *certificate, GPtrArray *rejections, gpointer user_data) { - GError *error = NULL; GabbleServerTLSManager *self = user_data; DEBUG ("TLS certificate rejected with rejections %p, length %u.", rejections, rejections->len); - self->priv->tls_state_changed = TRUE; - g_set_error (&error, GABBLE_SERVER_TLS_ERROR, 0, - "TLS certificate rejected"); - g_simple_async_result_set_from_error (self->priv->async_result, error); + g_simple_async_result_set_error (self->priv->async_result, + GABBLE_SERVER_TLS_ERROR, 0, "TLS certificate rejected"); - g_simple_async_result_complete_in_idle (self->priv->async_result); - tp_clear_object (&self->priv->async_result); - g_clear_error (&error); + complete_verify (self); } static void @@ -280,13 +326,10 @@ gabble_server_tls_manager_verify_async (WockyTLSHandler *handler, GabbleTLSCertificate *certificate; GSimpleAsyncResult *result; - /* this should be called only once per-connection. */ - g_return_if_fail (!self->priv->verify_async_called); + g_return_if_fail (self->priv->async_result == NULL); DEBUG ("verify_async() called on the GabbleServerTLSManager."); - self->priv->verify_async_called = TRUE; - result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gabble_server_tls_manager_verify_async); @@ -300,6 +343,8 @@ gabble_server_tls_manager_verify_async (WockyTLSHandler *handler, return; } + self->priv->async_result = result; + fill_reference_identities (self, peername, extra_identities); if (!self->priv->interactive_tls) @@ -307,21 +352,14 @@ gabble_server_tls_manager_verify_async (WockyTLSHandler *handler, DEBUG ("ignore-ssl-errors is set, fallback to non-interactive " "verification."); - g_object_unref (result); - - WOCKY_TLS_HANDLER_CLASS - (gabble_server_tls_manager_parent_class)->verify_async_func ( - WOCKY_TLS_HANDLER (self), tls_session, peername, - self->priv->reference_identities, callback, user_data); + chainup->verify_async_func (WOCKY_TLS_HANDLER (self), tls_session, + peername, self->priv->reference_identities, verify_fallback_cb, NULL); return; } - self->priv->async_result = result; self->priv->tls_session = g_object_ref (tls_session); self->priv->peername = g_strdup (peername); - self->priv->async_callback = callback; - self->priv->async_data = user_data; self->priv->channel = g_object_new (GABBLE_TYPE_SERVER_TLS_CHANNEL, "connection", self->priv->connection, @@ -333,8 +371,7 @@ gabble_server_tls_manager_verify_async (WockyTLSHandler *handler, g_signal_connect (self->priv->channel, "closed", G_CALLBACK (server_tls_channel_closed_cb), self); - certificate = gabble_server_tls_channel_get_certificate - (self->priv->channel); + certificate = gabble_server_tls_channel_get_certificate (self->priv->channel); g_signal_connect (certificate, "accepted", G_CALLBACK (tls_certificate_accepted_cb), self); @@ -351,19 +388,7 @@ gabble_server_tls_manager_verify_finish (WockyTLSHandler *self, GAsyncResult *result, GError **error) { - if (G_IS_SIMPLE_ASYNC_RESULT (result) && - g_simple_async_result_get_source_tag ((GSimpleAsyncResult *) result) == - gabble_server_tls_manager_verify_async) - { - wocky_implement_finish_void (self, - gabble_server_tls_manager_verify_async); - } - else - { - return WOCKY_TLS_HANDLER_CLASS - (gabble_server_tls_manager_parent_class)->verify_finish_func (self, - result, error); - } + wocky_implement_finish_void (self, gabble_server_tls_manager_verify_async); } static void @@ -398,8 +423,7 @@ gabble_server_tls_manager_finalize (GObject *object) DEBUG ("%p", self); - if (self->priv->channel != NULL) - tp_base_channel_close (TP_BASE_CHANNEL (self->priv->channel)); + close_all (self); g_free (self->priv->peername); g_strfreev (self->priv->reference_identities); @@ -460,10 +484,15 @@ gabble_server_tls_manager_foreach_channel (TpChannelManager *manager, gpointer user_data) { GabbleServerTLSManager *self = GABBLE_SERVER_TLS_MANAGER (manager); + GList *l; - /* there's only one channel of this kind */ if (self->priv->channel != NULL) func (TP_EXPORTABLE_CHANNEL (self->priv->channel), user_data); + + for (l = self->priv->completed_channels; l != NULL; l = l->next) + { + func (l->data, user_data); + } } static void @@ -519,9 +548,11 @@ gabble_server_tls_manager_get_rejection_details (GabbleServerTLSManager *self, GValueArray *rejection; TpTLSCertificateRejectReason tls_reason; - certificate = gabble_server_tls_channel_get_certificate - (self->priv->channel); + /* We probably want the rejection details of last completed operation */ + g_return_if_fail (self->priv->completed_channels != NULL); + certificate = gabble_server_tls_channel_get_certificate ( + self->priv->completed_channels->data); g_object_get (certificate, "rejections", &rejections, NULL); -- cgit v1.2.3