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