diff options
author | Xavier Claessens <xavier.claessens@collabora.co.uk> | 2012-06-13 14:41:10 +0200 |
---|---|---|
committer | Xavier Claessens <xavier.claessens@collabora.co.uk> | 2012-06-20 14:39:53 +0200 |
commit | 9abf25885dd71047746ea496ea3bdaff7f3499e7 (patch) | |
tree | 48318902a717aa79e52ea08f11989824ed69aced /src | |
parent | 287fb2d9fabd2703c17020c4fd9493e8531c0a03 (diff) |
GabbleServerTLSManager: Support multiple consecutive TLS verifications
WockyConnector could now restart connection with another host,
and so needs to re-verify TLS.
Diffstat (limited to 'src')
-rw-r--r-- | src/server-tls-channel.c | 4 | ||||
-rw-r--r-- | src/server-tls-manager.c | 159 |
2 files changed, 98 insertions, 65 deletions
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, @@ -113,6 +115,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, guint reason, @@ -124,14 +138,47 @@ 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); |