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