]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-auth-factory.c
Merge branch 'sasl'
[empathy.git] / libempathy / empathy-auth-factory.c
index fa2b7dcd15ff16b3cf28333fc34bf83f3482caf0..578b6d6cd4e67253bf2916bb1d71c1d1922842b7 100644 (file)
@@ -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,
 };
 
@@ -110,6 +117,52 @@ server_tls_handler_ready_cb (GObject *source,
   handler_context_data_free (data);
 }
 
+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,
@@ -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 *