diff options
Diffstat (limited to 'libempathy/empathy-auth-factory.c')
-rw-r--r-- | libempathy/empathy-auth-factory.c | 139 |
1 files changed, 127 insertions, 12 deletions
diff --git a/libempathy/empathy-auth-factory.c b/libempathy/empathy-auth-factory.c index fa2b7dcd1..578b6d6cd 100644 --- a/libempathy/empathy-auth-factory.c +++ b/libempathy/empathy-auth-factory.c @@ -26,6 +26,7 @@ #define DEBUG_FLAG EMPATHY_DEBUG_TLS #include "empathy-debug.h" +#include "empathy-server-sasl-handler.h" #include "empathy-server-tls-handler.h" #include "empathy-utils.h" @@ -36,11 +37,17 @@ G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, G_TYPE_OBJECT); typedef struct { TpBaseClient *handler; + /* Keep a ref here so the auth client doesn't have to mess with + * refs. It will be cleared when the channel (and so the handler) + * gets invalidated. */ + EmpathyServerSASLHandler *sasl_handler; + gboolean dispose_run; } EmpathyAuthFactoryPriv; enum { NEW_SERVER_TLS_HANDLER, + NEW_SERVER_SASL_HANDLER, LAST_SIGNAL, }; @@ -111,6 +118,52 @@ server_tls_handler_ready_cb (GObject *source, } static void +sasl_handler_invalidated_cb (EmpathyServerSASLHandler *handler, + gpointer user_data) +{ + EmpathyAuthFactory *self = user_data; + EmpathyAuthFactoryPriv *priv = GET_PRIV (self); + + DEBUG ("SASL handler is invalidated, unref it"); + + tp_clear_object (&priv->sasl_handler); +} + +static void +server_sasl_handler_ready_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + EmpathyAuthFactoryPriv *priv; + GError *error = NULL; + HandlerContextData *data = user_data; + + priv = GET_PRIV (data->self); + priv->sasl_handler = empathy_server_sasl_handler_new_finish (res, &error); + + if (error != NULL) + { + DEBUG ("Failed to create a server SASL handler; error %s", + error->message); + tp_handle_channels_context_fail (data->context, error); + + g_error_free (error); + } + else + { + tp_handle_channels_context_accept (data->context); + + g_signal_connect (priv->sasl_handler, "invalidated", + G_CALLBACK (sasl_handler_invalidated_cb), data->self); + + g_signal_emit (data->self, signals[NEW_SERVER_SASL_HANDLER], 0, + priv->sasl_handler); + } + + handler_context_data_free (data); +} + +static void handle_channels_cb (TpSimpleHandler *handler, TpAccount *account, TpConnection *connection, @@ -124,18 +177,22 @@ handle_channels_cb (TpSimpleHandler *handler, const GError *dbus_error; GError *error = NULL; EmpathyAuthFactory *self = user_data; + EmpathyAuthFactoryPriv *priv = GET_PRIV (self); HandlerContextData *data; + GHashTable *props; + const gchar * const *available_mechanisms; - DEBUG ("Handle TLS carrier channels."); + DEBUG ("Handle TLS or SASL carrier channels."); - /* there can't be more than one ServerTLSConnection channels - * at the same time, for the same connection/account. + /* there can't be more than one ServerTLSConnection or + * ServerAuthentication channels at the same time, for the same + * connection/account. */ if (g_list_length (channels) != 1) { g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Can't handle more than one ServerTLSConnection channel " - "for the same connection."); + "Can't handle more than one ServerTLSConnection or ServerAuthentication " + "channel for the same connection."); goto error; } @@ -143,11 +200,38 @@ handle_channels_cb (TpSimpleHandler *handler, channel = channels->data; if (tp_channel_get_channel_type_id (channel) != - EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION) + EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION + && tp_channel_get_channel_type_id (channel) != + TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Can only handle ServerTLSConnection channels, this was a %s " - "channel", tp_channel_get_channel_type (channel)); + "Can only handle ServerTLSConnection or ServerAuthentication channels, " + "this was a %s channel", tp_channel_get_channel_type (channel)); + + goto error; + } + + if (tp_channel_get_channel_type_id (channel) == + TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION + && priv->sasl_handler != NULL) + { + g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, + "Can't handle more than one ServerAuthentication channel at one time"); + + goto error; + } + + props = tp_channel_borrow_immutable_properties (channel); + available_mechanisms = tp_asv_get_boxed (props, + TP_PROP_CHANNEL_INTERFACE_SASL_AUTHENTICATION_AVAILABLE_MECHANISMS, + G_TYPE_STRV); + + if (tp_channel_get_channel_type_id (channel) == + TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION + && !tp_strv_contains (available_mechanisms, "X-TELEPATHY-PASSWORD")) + { + g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, + "Only the X-TELEPATHY-PASSWORD SASL mechanism is supported"); goto error; } @@ -160,12 +244,22 @@ handle_channels_cb (TpSimpleHandler *handler, goto error; } - /* create a handler */ data = handler_context_data_new (self, context); tp_handle_channels_context_delay (context); - empathy_server_tls_handler_new_async (channel, server_tls_handler_ready_cb, - data); + /* create a handler */ + if (tp_channel_get_channel_type_id (channel) == + EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION) + { + empathy_server_tls_handler_new_async (channel, server_tls_handler_ready_cb, + data); + } + else if (tp_channel_get_channel_type_id (channel) == + TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION) + { + empathy_server_sasl_handler_new_async (account, channel, + server_sasl_handler_ready_cb, data); + } return; error: @@ -218,12 +312,23 @@ empathy_auth_factory_init (EmpathyAuthFactory *self) FALSE, handle_channels_cb, self, NULL); tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( + /* ChannelType */ TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION, + /* AuthenticationMethod */ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_NONE, NULL)); - g_object_unref (bus); + tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( + /* ChannelType */ + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION, + /* AuthenticationMethod */ + TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD, + G_TYPE_STRING, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, + NULL)); + + g_object_unref (bus); } static void @@ -237,6 +342,7 @@ empathy_auth_factory_dispose (GObject *object) priv->dispose_run = TRUE; tp_clear_object (&priv->handler); + tp_clear_object (&priv->sasl_handler); G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object); } @@ -259,6 +365,15 @@ empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, EMPATHY_TYPE_SERVER_TLS_HANDLER); + + signals[NEW_SERVER_SASL_HANDLER] = + g_signal_new ("new-server-sasl-handler", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_SERVER_SASL_HANDLER); } EmpathyAuthFactory * |