]> git.0d.be Git - empathy.git/blob - libempathy/empathy-server-tls-handler.c
local-xmpp-assistant-widget: increase row-spacing
[empathy.git] / libempathy / empathy-server-tls-handler.c
1 /*
2  * empathy-server-tls-handler.c - Source for EmpathyServerTLSHandler
3  * Copyright (C) 2010 Collabora Ltd.
4  * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "empathy-server-tls-handler.h"
22
23 #include <telepathy-glib/interfaces.h>
24 #include <telepathy-glib/util.h>
25
26 #define DEBUG_FLAG EMPATHY_DEBUG_TLS
27 #include "empathy-debug.h"
28 #include "empathy-tls-certificate.h"
29 #include "empathy-utils.h"
30
31 #include "extensions/extensions.h"
32
33 static void async_initable_iface_init (GAsyncInitableIface *iface);
34
35 enum {
36   PROP_CHANNEL = 1,
37   PROP_TLS_CERTIFICATE,
38   PROP_HOSTNAME,
39   PROP_REFERENCE_IDENTITIES,
40   LAST_PROPERTY,
41 };
42
43 typedef struct {
44   TpChannel *channel;
45
46   EmpathyTLSCertificate *certificate;
47   gchar *hostname;
48   gchar **reference_identities;
49
50   GSimpleAsyncResult *async_init_res;
51 } EmpathyServerTLSHandlerPriv;
52
53 G_DEFINE_TYPE_WITH_CODE (EmpathyServerTLSHandler, empathy_server_tls_handler,
54     G_TYPE_OBJECT,
55     G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init));
56
57 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyServerTLSHandler);
58
59 static void
60 tls_certificate_prepared_cb (GObject *source,
61     GAsyncResult *result,
62     gpointer user_data)
63 {
64   EmpathyTLSCertificate *certificate = EMPATHY_TLS_CERTIFICATE (source);
65   EmpathyServerTLSHandler *self = user_data;
66   GError *error = NULL;
67   EmpathyServerTLSHandlerPriv *priv = GET_PRIV (self);
68
69   empathy_tls_certificate_prepare_finish (certificate, result, &error);
70
71   if (error != NULL)
72     {
73       g_simple_async_result_set_from_error (priv->async_init_res, error);
74       g_error_free (error);
75     }
76
77   g_simple_async_result_complete_in_idle (priv->async_init_res);
78   tp_clear_object (&priv->async_init_res);
79 }
80
81 static gboolean
82 tls_handler_init_finish (GAsyncInitable *initable,
83     GAsyncResult *res,
84     GError **error)
85 {
86   gboolean retval = TRUE;
87
88   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res),
89           error))
90     retval = FALSE;
91
92   return retval;
93 }
94
95 static void
96 tls_handler_init_async (GAsyncInitable *initable,
97     gint io_priority,
98     GCancellable *cancellable,
99     GAsyncReadyCallback callback,
100     gpointer user_data)
101 {
102   GHashTable *properties;
103   const gchar *cert_object_path;
104   const gchar *hostname;
105   const gchar * const *identities;
106   const gchar *bus_name;
107   TpDBusDaemon *dbus;
108   GError *error = NULL;
109   /*
110    * Used when channel doesn't implement ReferenceIdentities. A GStrv
111    * with [0] the hostname, and [1] a NULL terminator.
112    */
113   gchar *default_identities[2];
114   EmpathyServerTLSHandler *self = EMPATHY_SERVER_TLS_HANDLER (initable);
115   EmpathyServerTLSHandlerPriv *priv = GET_PRIV (self);
116
117   g_assert (priv->channel != NULL);
118
119   priv->async_init_res = g_simple_async_result_new (G_OBJECT (self),
120       callback, user_data, empathy_server_tls_handler_new_async);
121   properties = tp_channel_borrow_immutable_properties (priv->channel);
122
123   hostname = tp_asv_get_string (properties,
124      TP_PROP_CHANNEL_TYPE_SERVER_TLS_CONNECTION_HOSTNAME);
125   priv->hostname = g_strdup (hostname);
126
127   DEBUG ("Received hostname: %s", hostname);
128
129   identities = tp_asv_get_strv (properties,
130       TP_PROP_CHANNEL_TYPE_SERVER_TLS_CONNECTION_REFERENCE_IDENTITIES);
131
132   /*
133    * If the channel doesn't implement the ReferenceIdentities parameter
134    * then fallback to the hostname.
135    */
136   if (identities == NULL)
137     {
138       default_identities[0] = (gchar *) hostname;
139       default_identities[1] = NULL;
140       identities = (const gchar **) default_identities;
141     }
142   else
143     {
144 #ifdef ENABLE_DEBUG
145       gchar *output = g_strjoinv (", ", (gchar **) identities);
146       DEBUG ("Received reference identities: %s", output);
147       g_free (output);
148 #endif /* ENABLE_DEBUG */
149   }
150
151   priv->reference_identities = g_strdupv ((gchar **) identities);
152
153   cert_object_path = tp_asv_get_object_path (properties,
154       EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION ".ServerCertificate");
155   bus_name = tp_proxy_get_bus_name (TP_PROXY (priv->channel));
156   dbus = tp_proxy_get_dbus_daemon (TP_PROXY (priv->channel));
157
158   DEBUG ("Creating an EmpathyTLSCertificate for path %s, bus name %s",
159       cert_object_path, bus_name);
160
161   priv->certificate = empathy_tls_certificate_new (dbus, bus_name,
162       cert_object_path, &error);
163
164   if (error != NULL)
165     {
166       DEBUG ("Unable to create the EmpathyTLSCertificate: error %s",
167           error->message);
168
169       g_simple_async_result_set_from_error (priv->async_init_res, error);
170       g_simple_async_result_complete_in_idle (priv->async_init_res);
171
172       g_error_free (error);
173       tp_clear_object (&priv->async_init_res);
174
175       return;
176     }
177
178   empathy_tls_certificate_prepare_async (priv->certificate,
179       tls_certificate_prepared_cb, self);
180 }
181
182 static void
183 async_initable_iface_init (GAsyncInitableIface *iface)
184 {
185   iface->init_async = tls_handler_init_async;
186   iface->init_finish = tls_handler_init_finish;
187 }
188
189 static void
190 empathy_server_tls_handler_finalize (GObject *object)
191 {
192   EmpathyServerTLSHandlerPriv *priv = GET_PRIV (object);
193
194   DEBUG ("%p", object);
195
196   tp_clear_object (&priv->channel);
197   tp_clear_object (&priv->certificate);
198   g_strfreev (priv->reference_identities);
199   g_free (priv->hostname);
200
201   G_OBJECT_CLASS (empathy_server_tls_handler_parent_class)->finalize (object);
202 }
203
204 static void
205 empathy_server_tls_handler_get_property (GObject *object,
206     guint property_id,
207     GValue *value,
208     GParamSpec *pspec)
209 {
210   EmpathyServerTLSHandlerPriv *priv = GET_PRIV (object);
211
212   switch (property_id)
213     {
214     case PROP_CHANNEL:
215       g_value_set_object (value, priv->channel);
216       break;
217     case PROP_TLS_CERTIFICATE:
218       g_value_set_object (value, priv->certificate);
219       break;
220     case PROP_HOSTNAME:
221       g_value_set_string (value, priv->hostname);
222       break;
223     case PROP_REFERENCE_IDENTITIES:
224       g_value_set_boxed (value, priv->reference_identities);
225       break;
226     default:
227       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
228       break;
229     }
230 }
231
232 static void
233 empathy_server_tls_handler_set_property (GObject *object,
234     guint property_id,
235     const GValue *value,
236     GParamSpec *pspec)
237 {
238   EmpathyServerTLSHandlerPriv *priv = GET_PRIV (object);
239
240   switch (property_id)
241     {
242     case PROP_CHANNEL:
243       priv->channel = g_value_dup_object (value);
244       break;
245     default:
246       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
247       break;
248     }
249 }
250
251 static void
252 empathy_server_tls_handler_class_init (EmpathyServerTLSHandlerClass *klass)
253 {
254   GObjectClass *oclass = G_OBJECT_CLASS (klass);
255   GParamSpec *pspec;
256
257   oclass->get_property = empathy_server_tls_handler_get_property;
258   oclass->set_property = empathy_server_tls_handler_set_property;
259   oclass->finalize = empathy_server_tls_handler_finalize;
260
261   g_type_class_add_private (klass, sizeof (EmpathyServerTLSHandlerPriv));
262
263   pspec = g_param_spec_object ("channel", "The TpChannel",
264       "The TpChannel this handler is supposed to handle.",
265       TP_TYPE_CHANNEL,
266       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
267   g_object_class_install_property (oclass, PROP_CHANNEL, pspec);
268
269   pspec = g_param_spec_object ("certificate", "The EmpathyTLSCertificate",
270       "The EmpathyTLSCertificate carried by the channel.",
271       EMPATHY_TYPE_TLS_CERTIFICATE,
272       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
273   g_object_class_install_property (oclass, PROP_TLS_CERTIFICATE, pspec);
274
275   pspec = g_param_spec_string ("hostname", "The hostname",
276       "The hostname the user is expecting to connect to.",
277       NULL,
278       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
279   g_object_class_install_property (oclass, PROP_HOSTNAME, pspec);
280
281   pspec = g_param_spec_boxed ("reference-identities", "Reference Identities",
282       "The server certificate should certify one of these identities",
283       G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
284   g_object_class_install_property (oclass, PROP_REFERENCE_IDENTITIES, pspec);
285
286 }
287
288 static void
289 empathy_server_tls_handler_init (EmpathyServerTLSHandler *self)
290 {
291   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
292       EMPATHY_TYPE_SERVER_TLS_HANDLER, EmpathyServerTLSHandlerPriv);
293 }
294
295 void
296 empathy_server_tls_handler_new_async (TpChannel *channel,
297     GAsyncReadyCallback callback,
298     gpointer user_data)
299 {
300   g_assert (TP_IS_CHANNEL (channel));
301   g_assert (channel != NULL);
302
303   g_async_initable_new_async (EMPATHY_TYPE_SERVER_TLS_HANDLER,
304       G_PRIORITY_DEFAULT, NULL, callback, user_data,
305       "channel", channel, NULL);
306 }
307
308 EmpathyServerTLSHandler *
309 empathy_server_tls_handler_new_finish (GAsyncResult *result,
310     GError **error)
311 {
312   GObject *object, *source_object;
313
314   source_object = g_async_result_get_source_object (result);
315
316   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
317       result, error);
318   g_object_unref (source_object);
319
320   if (object != NULL)
321     return EMPATHY_SERVER_TLS_HANDLER (object);
322   else
323     return NULL;
324 }
325
326 EmpathyTLSCertificate *
327 empathy_server_tls_handler_get_certificate (EmpathyServerTLSHandler *self)
328 {
329   EmpathyServerTLSHandlerPriv *priv = GET_PRIV (self);
330
331   g_assert (priv->certificate != NULL);
332
333   return priv->certificate;
334 }