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