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