2 * empathy-auth-factory.c - Source for EmpathyAuthFactory
3 * Copyright (C) 2010 Collabora Ltd.
4 * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "empathy-auth-factory.h"
23 #include <telepathy-glib/interfaces.h>
24 #include <telepathy-glib/simple-handler.h>
25 #include <telepathy-glib/util.h>
27 #define DEBUG_FLAG EMPATHY_DEBUG_TLS
28 #include "empathy-debug.h"
29 #include "empathy-server-sasl-handler.h"
30 #include "empathy-server-tls-handler.h"
31 #include "empathy-utils.h"
33 #include "extensions/extensions.h"
35 G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, G_TYPE_OBJECT);
38 TpBaseClient *handler;
40 /* Keep a ref here so the auth client doesn't have to mess with
41 * refs. It will be cleared when the channel (and so the handler)
42 * gets invalidated. */
43 EmpathyServerSASLHandler *sasl_handler;
46 } EmpathyAuthFactoryPriv;
49 NEW_SERVER_TLS_HANDLER,
50 NEW_SERVER_SASL_HANDLER,
54 static guint signals[LAST_SIGNAL] = { 0, };
56 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAuthFactory)
58 static EmpathyAuthFactory *auth_factory_singleton = NULL;
61 TpHandleChannelsContext *context;
62 EmpathyAuthFactory *self;
66 handler_context_data_free (HandlerContextData *data)
68 tp_clear_object (&data->self);
69 tp_clear_object (&data->context);
71 g_slice_free (HandlerContextData, data);
74 static HandlerContextData *
75 handler_context_data_new (EmpathyAuthFactory *self,
76 TpHandleChannelsContext *context)
78 HandlerContextData *data;
80 data = g_slice_new0 (HandlerContextData);
81 data->self = g_object_ref (self);
82 data->context = g_object_ref (context);
88 server_tls_handler_ready_cb (GObject *source,
92 EmpathyServerTLSHandler *handler;
94 EmpathyAuthFactoryPriv *priv;
95 HandlerContextData *data = user_data;
97 priv = GET_PRIV (data->self);
98 handler = empathy_server_tls_handler_new_finish (res, &error);
102 DEBUG ("Failed to create a server TLS handler; error %s",
104 tp_handle_channels_context_fail (data->context, error);
106 g_error_free (error);
110 tp_handle_channels_context_accept (data->context);
111 g_signal_emit (data->self, signals[NEW_SERVER_TLS_HANDLER], 0,
114 g_object_unref (handler);
117 handler_context_data_free (data);
121 sasl_handler_invalidated_cb (EmpathyServerSASLHandler *handler,
124 EmpathyAuthFactory *self = user_data;
125 EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
127 DEBUG ("SASL handler is invalidated, unref it");
129 tp_clear_object (&priv->sasl_handler);
133 server_sasl_handler_ready_cb (GObject *source,
137 EmpathyAuthFactoryPriv *priv;
138 GError *error = NULL;
139 HandlerContextData *data = user_data;
141 priv = GET_PRIV (data->self);
142 priv->sasl_handler = empathy_server_sasl_handler_new_finish (res, &error);
146 DEBUG ("Failed to create a server SASL handler; error %s",
148 tp_handle_channels_context_fail (data->context, error);
150 g_error_free (error);
154 tp_handle_channels_context_accept (data->context);
156 g_signal_connect (priv->sasl_handler, "invalidated",
157 G_CALLBACK (sasl_handler_invalidated_cb), data->self);
159 g_signal_emit (data->self, signals[NEW_SERVER_SASL_HANDLER], 0,
163 handler_context_data_free (data);
167 handle_channels_cb (TpSimpleHandler *handler,
169 TpConnection *connection,
171 GList *requests_satisfied,
172 gint64 user_action_time,
173 TpHandleChannelsContext *context,
177 const GError *dbus_error;
178 GError *error = NULL;
179 EmpathyAuthFactory *self = user_data;
180 EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
181 HandlerContextData *data;
183 const gchar * const *available_mechanisms;
185 DEBUG ("Handle TLS or SASL carrier channels.");
187 /* there can't be more than one ServerTLSConnection or
188 * ServerAuthentication channels at the same time, for the same
189 * connection/account.
191 if (g_list_length (channels) != 1)
193 g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
194 "Can't handle more than one ServerTLSConnection or ServerAuthentication "
195 "channel for the same connection.");
200 channel = channels->data;
202 if (tp_channel_get_channel_type_id (channel) !=
203 EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION
204 && tp_channel_get_channel_type_id (channel) !=
205 TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
207 g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
208 "Can only handle ServerTLSConnection or ServerAuthentication channels, "
209 "this was a %s channel", tp_channel_get_channel_type (channel));
214 if (tp_channel_get_channel_type_id (channel) ==
215 TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION
216 && priv->sasl_handler != NULL)
218 g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
219 "Can't handle more than one ServerAuthentication channel at one time");
224 props = tp_channel_borrow_immutable_properties (channel);
225 available_mechanisms = tp_asv_get_boxed (props,
226 TP_PROP_CHANNEL_INTERFACE_SASL_AUTHENTICATION_AVAILABLE_MECHANISMS,
229 if (tp_channel_get_channel_type_id (channel) ==
230 TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION
231 && !tp_strv_contains (available_mechanisms, "X-TELEPATHY-PASSWORD"))
233 g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
234 "Only the X-TELEPATHY-PASSWORD SASL mechanism is supported");
239 dbus_error = tp_proxy_get_invalidated (channel);
241 if (dbus_error != NULL)
243 error = g_error_copy (dbus_error);
247 data = handler_context_data_new (self, context);
248 tp_handle_channels_context_delay (context);
250 /* create a handler */
251 if (tp_channel_get_channel_type_id (channel) ==
252 EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
254 empathy_server_tls_handler_new_async (channel, server_tls_handler_ready_cb,
257 else if (tp_channel_get_channel_type_id (channel) ==
258 TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
260 empathy_server_sasl_handler_new_async (account, channel,
261 server_sasl_handler_ready_cb, data);
266 tp_handle_channels_context_fail (context, error);
267 g_clear_error (&error);
271 empathy_auth_factory_constructor (GType type,
273 GObjectConstructParam *params)
277 if (auth_factory_singleton != NULL)
279 retval = g_object_ref (auth_factory_singleton);
283 retval = G_OBJECT_CLASS (empathy_auth_factory_parent_class)->constructor
284 (type, n_params, params);
286 auth_factory_singleton = EMPATHY_AUTH_FACTORY (retval);
287 g_object_add_weak_pointer (retval, (gpointer *) &auth_factory_singleton);
294 empathy_auth_factory_init (EmpathyAuthFactory *self)
296 EmpathyAuthFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
297 EMPATHY_TYPE_AUTH_FACTORY, EmpathyAuthFactoryPriv);
299 GError *error = NULL;
303 bus = tp_dbus_daemon_dup (&error);
306 g_critical ("Failed to get TpDBusDaemon: %s", error->message);
307 g_error_free (error);
311 priv->handler = tp_simple_handler_new (bus, FALSE, FALSE, "Empathy.Auth",
312 FALSE, handle_channels_cb, self, NULL);
314 tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
316 TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
317 EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION,
318 /* AuthenticationMethod */
319 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
320 TP_HANDLE_TYPE_NONE, NULL));
322 tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
324 TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
325 TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
326 /* AuthenticationMethod */
327 TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD,
328 G_TYPE_STRING, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
331 g_object_unref (bus);
335 empathy_auth_factory_dispose (GObject *object)
337 EmpathyAuthFactoryPriv *priv = GET_PRIV (object);
339 if (priv->dispose_run)
342 priv->dispose_run = TRUE;
344 tp_clear_object (&priv->handler);
345 tp_clear_object (&priv->sasl_handler);
347 G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object);
351 empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass)
353 GObjectClass *oclass = G_OBJECT_CLASS (klass);
355 oclass->constructor = empathy_auth_factory_constructor;
356 oclass->dispose = empathy_auth_factory_dispose;
358 g_type_class_add_private (klass, sizeof (EmpathyAuthFactoryPriv));
360 signals[NEW_SERVER_TLS_HANDLER] =
361 g_signal_new ("new-server-tls-handler",
362 G_TYPE_FROM_CLASS (klass),
363 G_SIGNAL_RUN_LAST, 0,
365 g_cclosure_marshal_VOID__OBJECT,
367 1, EMPATHY_TYPE_SERVER_TLS_HANDLER);
369 signals[NEW_SERVER_SASL_HANDLER] =
370 g_signal_new ("new-server-sasl-handler",
371 G_TYPE_FROM_CLASS (klass),
372 G_SIGNAL_RUN_LAST, 0,
374 g_cclosure_marshal_VOID__OBJECT,
376 1, EMPATHY_TYPE_SERVER_SASL_HANDLER);
380 empathy_auth_factory_dup_singleton (void)
382 return g_object_new (EMPATHY_TYPE_AUTH_FACTORY, NULL);
386 empathy_auth_factory_register (EmpathyAuthFactory *self,
389 EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
391 return tp_base_client_register (priv->handler, error);