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